From a9cf558af7fc08539e15ceca1e889e087c815c8d Mon Sep 17 00:00:00 2001 From: Sajaki Date: Sat, 28 Apr 2012 10:43:43 +0200 Subject: [PATCH 001/497] [ticket/10854] sql server drop default constraint when dropping column drops default columns with T-SQL before attempting drop column to avoids sql exception. This is a huge annoyance in UMIL scripts running under sql server. --- phpBB/includes/db/db_tools.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index c6dd23e6bd..f63ff18cbe 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -1819,6 +1819,22 @@ class phpbb_db_tools case 'mssql': case 'mssqlnative': + // remove default cosntraints first + // http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx + $statements[] = "DECLARE @drop_default_name VARCHAR(100), @cmd VARCHAR(1000) + SET @drop_default_name = + (SELECT so.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}')) + IF @drop_default_name <> '' + BEGIN + SET @cmd = 'ALTER TABLE [{$table_name}] DROP CONSTRAINT [' + @drop_default_name + ']' + EXEC(@cmd) + END"; $statements[] = 'ALTER TABLE [' . $table_name . '] DROP COLUMN [' . $column_name . ']'; break; From d5a788ae5b615c1b6b642c631884a4d936be2a4c Mon Sep 17 00:00:00 2001 From: Callum Macrae Date: Thu, 21 Jun 2012 19:16:05 +0100 Subject: [PATCH 002/497] [ticket/10949] Converted AJAX coding standards to new guidelines. Basically, moved parentheses to same line and changed variable names to camel case. PHPBB3-10949 --- phpBB/assets/javascript/core.js | 195 ++++++++++-------------- phpBB/styles/prosilver/template/ajax.js | 22 +-- 2 files changed, 86 insertions(+), 131 deletions(-) diff --git a/phpBB/assets/javascript/core.js b/phpBB/assets/javascript/core.js index 958b6c9ff6..53b85e677a 100644 --- a/phpBB/assets/javascript/core.js +++ b/phpBB/assets/javascript/core.js @@ -1,5 +1,5 @@ var phpbb = {}; -phpbb.alert_time = 100; +phpbb.alertTime = 100; (function($) { // Avoid conflicts with other libraries @@ -12,35 +12,31 @@ var keymap = { }; var dark = $('#darkenwrapper'); -var loading_alert = $('#loadingalert'); +var loadingAlert = $('#loadingalert'); /** - * Display a loading screen. + * Display a loading screen * - * @returns object Returns loading_alert. + * @returns object Returns loadingAlert. */ -phpbb.loading_alert = function() { - if (dark.is(':visible')) - { - loading_alert.fadeIn(phpbb.alert_time); - } - else - { - loading_alert.show(); - dark.fadeIn(phpbb.alert_time, function() { +phpbb.loadingAlert = function() { + if (dark.is(':visible')) { + loadingAlert.fadeIn(phpbb.alertTime); + } else { + loadingAlert.show(); + dark.fadeIn(phpbb.alertTime, function() { // Wait five seconds and display an error if nothing has been returned by then. setTimeout(function() { - if (loading_alert.is(':visible')) - { + if (loadingAlert.is(':visible')) { phpbb.alert($('#phpbb_alert').attr('data-l-err'), $('#phpbb_alert').attr('data-l-timeout-processing-req')); } }, 5000); }); } - return loading_alert; -} + return loadingAlert; +}; /** * Display a simple alert similar to JSs native alert(). @@ -67,7 +63,7 @@ phpbb.alert = function(title, msg, fadedark) { div.find('.alert_close').unbind('click'); fade = (typeof fadedark !== 'undefined' && !fadedark) ? div : dark; - fade.fadeOut(phpbb.alert_time, function() { + fade.fadeOut(phpbb.alertTime, function() { div.hide(); }); @@ -90,27 +86,22 @@ phpbb.alert = function(title, msg, fadedark) { e.preventDefault(); }); - if (loading_alert.is(':visible')) - { - loading_alert.fadeOut(phpbb.alert_time, function() { + if (loadingAlert.is(':visible')) { + loadingAlert.fadeOut(phpbb.alertTime, function() { dark.append(div); - div.fadeIn(phpbb.alert_time); + div.fadeIn(phpbb.alertTime); }); - } - else if (dark.is(':visible')) - { + } else if (dark.is(':visible')) { dark.append(div); - div.fadeIn(phpbb.alert_time); - } - else - { + div.fadeIn(phpbb.alertTime); + } else { dark.append(div); div.show(); - dark.fadeIn(phpbb.alert_time); + dark.fadeIn(phpbb.alertTime); } return div; -} +}; /** * Display a simple yes / no box to the user. @@ -136,7 +127,7 @@ phpbb.confirm = function(msg, callback, fadedark) { var click_handler = function(e) { var res = this.className === 'button1'; var fade = (typeof fadedark !== 'undefined' && !fadedark && res) ? div : dark; - fade.fadeOut(phpbb.alert_time, function() { + fade.fadeOut(phpbb.alertTime, function() { div.hide(); }); div.find('input[type="button"]').unbind('click', click_handler); @@ -151,7 +142,7 @@ phpbb.confirm = function(msg, callback, fadedark) { dark.one('click', function(e) { div.find('.alert_close').unbind('click'); - dark.fadeOut(phpbb.alert_time, function() { + dark.fadeOut(phpbb.alertTime, function() { div.hide(); }); callback(false); @@ -174,7 +165,7 @@ phpbb.confirm = function(msg, callback, fadedark) { div.find('.alert_close').one('click', function(e) { var fade = (typeof fadedark !== 'undefined' && fadedark) ? div : dark; - fade.fadeOut(phpbb.alert_time, function() { + fade.fadeOut(phpbb.alertTime, function() { div.hide(); }); callback(false); @@ -182,27 +173,22 @@ phpbb.confirm = function(msg, callback, fadedark) { e.preventDefault(); }); - if (loading_alert.is(':visible')) - { - loading_alert.fadeOut(phpbb.alert_time, function() { + if (loadingAlert.is(':visible')) { + loadingAlert.fadeOut(phpbb.alertTime, function() { dark.append(div); - div.fadeIn(phpbb.alert_time); + div.fadeIn(phpbb.alertTime); }); - } - else if (dark.is(':visible')) - { + } else if (dark.is(':visible')) { dark.append(div); - div.fadeIn(phpbb.alert_time); - } - else - { + div.fadeIn(phpbb.alertTime); + } else { dark.append(div); div.show(); - dark.fadeIn(phpbb.alert_time); + dark.fadeIn(phpbb.alertTime); } return div; -} +}; /** * Turn a querystring into an array. @@ -214,13 +200,12 @@ phpbb.parse_querystring = function(string) { var params = {}, i, split; string = string.split('&'); - for (i = 0; i < string.length; i++) - { + for (i = 0; i < string.length; i++) { split = string[i].split('='); params[split[0]] = decodeURIComponent(split[1]); } return params; -} +}; /** @@ -246,14 +231,13 @@ phpbb.ajaxify = function(options) { refresh = options.refresh, callback = options.callback, overlay = (typeof options.overlay !== 'undefined') ? options.overlay : true, - is_form = elements.is('form'), - event_name = is_form ? 'submit' : 'click'; + isForm = elements.is('form'), + eventName = isForm ? 'submit' : 'click'; - elements.bind(event_name, function(event) { + elements.bind(eventName, function(event) { var action, method, data, submit, that = this, $this = $(this); - if ($this.find('input[type="submit"][data-clicked]').attr('data-ajax') === 'false') - { + if ($this.find('input[type="submit"][data-clicked]').attr('data-ajax') === 'false') { return; } @@ -267,84 +251,69 @@ phpbb.ajaxify = function(options) { * * @param object res The object sent back by the server. */ - function return_handler(res) - { + function returnHandler(res) { var alert; // Is a confirmation required? - if (typeof res.S_CONFIRM_ACTION === 'undefined') - { + if (typeof res.S_CONFIRM_ACTION === 'undefined') { // If a confirmation is not required, display an alert and call the // callbacks. - if (typeof res.MESSAGE_TITLE !== 'undefined') - { + if (typeof res.MESSAGE_TITLE !== 'undefined') { alert = phpbb.alert(res.MESSAGE_TITLE, res.MESSAGE_TEXT); - } - else - { - dark.fadeOut(phpbb.alert_time); + } else { + dark.fadeOut(phpbb.alertTime); } - if (typeof phpbb.ajax_callbacks[callback] === 'function') - { - phpbb.ajax_callbacks[callback].call(that, res); + if (typeof phpbb.ajaxCallbacks[callback] === 'function') { + phpbb.ajaxCallbacks[callback].call(that, res); } // If the server says to refresh the page, check whether the page should // be refreshed and refresh page after specified time if required. - if (res.REFRESH_DATA) - { - if (typeof refresh === 'function') - { + if (res.REFRESH_DATA) { + if (typeof refresh === 'function') { refresh = refresh(res.REFRESH_DATA.url); - } - else if (typeof refresh !== 'boolean') - { + } else if (typeof refresh !== 'boolean') { refresh = false; } setTimeout(function() { - if (refresh) - { + if (refresh) { window.location = res.REFRESH_DATA.url; } // Hide the alert even if we refresh the page, in case the user // presses the back button. - dark.fadeOut(phpbb.alert_time, function() { + dark.fadeOut(phpbb.alertTime, function() { alert.hide(); }); }, res.REFRESH_DATA.time * 1000); // Server specifies time in seconds } - } - else - { + } else { // If confirmation is required, display a diologue to the user. phpbb.confirm(res.MESSAGE_TEXT, function(del) { - if (del) - { - phpbb.loading_alert(); + if (del) { + phpbb.loadingAlert(); data = $('
' + res.S_HIDDEN_FIELDS + '
').serialize(); $.ajax({ url: res.S_CONFIRM_ACTION, type: 'POST', data: data + '&confirm=' + res.YES_VALUE, - success: return_handler, - error: error_handler + success: returnHandler, + error: errorHandler }); } }, false); } } - function error_handler() - { + function errorHandler() { var alert; alert = phpbb.alert(dark.attr('data-ajax-error-title'), dark.attr('data-ajax-error-text')); setTimeout(function () { - dark.fadeOut(phpbb.alert_time, function() { + dark.fadeOut(phpbb.alertTime, function() { alert.hide(); }); }, 5000); @@ -352,25 +321,21 @@ phpbb.ajaxify = function(options) { // If the element is a form, POST must be used and some extra data must // be taken from the form. - var run_filter = (typeof options.filter === 'function'); + var runFilter = (typeof options.filter === 'function'); - if (is_form) - { + if (isForm) { action = $this.attr('action').replace('&', '&'); data = $this.serializeArray(); method = $this.attr('method') || 'GET'; - if ($this.find('input[type="submit"][data-clicked]')) - { + if ($this.find('input[type="submit"][data-clicked]')) { submit = $this.find('input[type="submit"][data-clicked]'); data.push({ name: submit.attr('name'), value: submit.val() }); } - } - else - { + } else { action = this.href; data = null; method = 'GET'; @@ -378,28 +343,26 @@ phpbb.ajaxify = function(options) { // If filter function returns false, cancel the AJAX functionality, // and return true (meaning that the HTTP request will be sent normally). - if (run_filter && !options.filter.call(this, data)) - { + if (runFilter && !options.filter.call(this, data)) { return; } - if (overlay) - { - phpbb.loading_alert(); + if (overlay) { + phpbb.loadingAlert(); } $.ajax({ url: action, type: method, data: data, - success: return_handler, - error: error_handler + success: returnHandler, + error: errorHandler }); event.preventDefault(); }); - if (is_form) { + if (isForm) { elements.find('input:submit').click(function () { var $this = $(this); @@ -409,9 +372,9 @@ phpbb.ajaxify = function(options) { } return this; -} +}; -phpbb.ajax_callbacks = {}; +phpbb.ajaxCallbacks = {}; /** * Adds an AJAX callback to be used by phpbb.ajaxify. @@ -421,14 +384,12 @@ phpbb.ajax_callbacks = {}; * @param string id The name of the callback. * @param function callback The callback to be called. */ -phpbb.add_ajax_callback = function(id, callback) -{ - if (typeof callback === 'function') - { - phpbb.ajax_callbacks[id] = callback; +phpbb.add_ajax_callback = function(id, callback) { + if (typeof callback === 'function') { + phpbb.ajaxCallbacks[id] = callback; } return this; -} +}; /** @@ -438,11 +399,11 @@ phpbb.add_ajax_callback = function(id, callback) */ phpbb.add_ajax_callback('alt_text', function(data) { var el = $(this), - alt_text; + altText; - alt_text = el.attr('data-alt-text'); - el.attr('title', alt_text); - el.text(alt_text); + altText = el.attr('data-alt-text'); + el.attr('title', altText); + el.text(altText); }); diff --git a/phpBB/styles/prosilver/template/ajax.js b/phpBB/styles/prosilver/template/ajax.js index 54f34e4204..83335b23af 100644 --- a/phpBB/styles/prosilver/template/ajax.js +++ b/phpBB/styles/prosilver/template/ajax.js @@ -5,14 +5,12 @@ // This callback finds the post from the delete link, and removes it. phpbb.add_ajax_callback('post_delete', function() { var el = $(this), - post_id; + postId; - if (el.attr('data-refresh') === undefined) - { - post_id = el[0].href.split('&p=')[1]; - var post = el.parents('#p' + post_id).css('pointer-events', 'none'); - if (post.hasClass('bg1') || post.hasClass('bg2')) - { + if (el.attr('data-refresh') === undefined) { + postId = el[0].href.split('&p=')[1]; + var post = el.parents('#p' + postId).css('pointer-events', 'none'); + if (post.hasClass('bg1') || post.hasClass('bg2')) { var posts1 = post.nextAll('.bg1'); post.nextAll('.bg2').removeClass('bg2').addClass('bg1'); posts1.removeClass('bg1').addClass('bg2'); @@ -54,8 +52,7 @@ $('[data-ajax]').each(function() { ajax = $this.attr('data-ajax'), fn; - if (ajax !== 'false') - { + if (ajax !== 'false') { fn = (ajax !== 'true') ? ajax : null; phpbb.ajaxify({ selector: this, @@ -89,12 +86,9 @@ phpbb.ajaxify({ filter: function (data) { var action = $('#quick-mod-select').val(); - if (action === 'make_normal') - { + if (action === 'make_normal') { return $(this).find('select option[value="make_global"]').length > 0; - } - else if (action === 'lock' || action === 'unlock') - { + } else if (action === 'lock' || action === 'unlock') { return true; } From 90a957ad26f52e26c3979464c5ac15b1fd0fcc28 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Sat, 21 Jul 2012 17:43:43 +0200 Subject: [PATCH 003/497] [ticket/11015] Make DBAL classes autoloadable PHPBB3-11015 This allows us to just create the object without having to include the driver first. However, it also means that users must specify the full class name in config.php --- phpBB/common.php | 3 +- phpBB/download/file.php | 3 +- phpBB/includes/config/db.php | 2 +- phpBB/includes/db/dbal.php | 1049 ----------------- phpBB/includes/db/driver/driver.php | 1044 ++++++++++++++++ phpBB/includes/db/{ => driver}/firebird.php | 4 +- phpBB/includes/db/{ => driver}/mssql.php | 6 +- phpBB/includes/db/{ => driver}/mssql_odbc.php | 4 +- .../includes/db/{ => driver}/mssqlnative.php | 4 +- phpBB/includes/db/{ => driver}/mysql.php | 4 +- phpBB/includes/db/{ => driver}/mysqli.php | 4 +- phpBB/includes/db/{ => driver}/oracle.php | 4 +- phpBB/includes/db/{ => driver}/postgres.php | 9 +- phpBB/includes/db/{ => driver}/sqlite.php | 4 +- phpBB/includes/extension/manager.php | 4 +- phpBB/includes/functions_install.php | 59 +- phpBB/install/database_update.php | 7 +- phpBB/install/install_convert.php | 24 +- phpBB/install/install_install.php | 12 +- phpBB/install/install_update.php | 3 +- tests/RUNNING_TESTS.txt | 2 +- tests/session/testable_factory.php | 2 +- .../phpbb_database_test_case.php | 7 +- ...phpbb_database_test_connection_manager.php | 44 +- .../phpbb_functional_test_case.php | 8 +- .../phpbb_test_case_helpers.php | 2 +- 26 files changed, 1129 insertions(+), 1189 deletions(-) delete mode 100644 phpBB/includes/db/dbal.php create mode 100644 phpBB/includes/db/driver/driver.php rename phpBB/includes/db/{ => driver}/firebird.php (99%) rename phpBB/includes/db/{ => driver}/mssql.php (99%) rename phpBB/includes/db/{ => driver}/mssql_odbc.php (98%) rename phpBB/includes/db/{ => driver}/mssqlnative.php (99%) rename phpBB/includes/db/{ => driver}/mysql.php (99%) rename phpBB/includes/db/{ => driver}/mysqli.php (99%) rename phpBB/includes/db/{ => driver}/oracle.php (99%) rename phpBB/includes/db/{ => driver}/postgres.php (98%) rename phpBB/includes/db/{ => driver}/sqlite.php (98%) diff --git a/phpBB/common.php b/phpBB/common.php index 81fe275008..9862fcf4c3 100644 --- a/phpBB/common.php +++ b/phpBB/common.php @@ -79,7 +79,6 @@ require($phpbb_root_path . 'includes/functions.' . $phpEx); require($phpbb_root_path . 'includes/functions_content.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); -require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx); // Set PHP error handler to ours @@ -102,7 +101,7 @@ $phpbb_dispatcher = new phpbb_event_dispatcher(); $request = new phpbb_request(); $user = new phpbb_user(); $auth = new phpbb_auth(); -$db = new $sql_db(); +$db = new $dbms(); // make sure request_var uses this request instance request_var('', 0, false, false, $request); // "dependency injection" for a function diff --git a/phpBB/download/file.php b/phpBB/download/file.php index c01b0789de..72c2d3ba3f 100644 --- a/phpBB/download/file.php +++ b/phpBB/download/file.php @@ -39,7 +39,6 @@ if (isset($_GET['avatar'])) } require($phpbb_root_path . 'includes/class_loader.' . $phpEx); - require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); require($phpbb_root_path . 'includes/functions.' . $phpEx); require($phpbb_root_path . 'includes/functions_download' . '.' . $phpEx); @@ -58,7 +57,7 @@ if (isset($_GET['avatar'])) $phpbb_dispatcher = new phpbb_event_dispatcher(); $request = new phpbb_request(); - $db = new $sql_db(); + $db = new $dbms(); // Connect to DB if (!@$db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, false)) diff --git a/phpBB/includes/config/db.php b/phpBB/includes/config/db.php index 993a764a7f..4293498d97 100644 --- a/phpBB/includes/config/db.php +++ b/phpBB/includes/config/db.php @@ -46,7 +46,7 @@ class phpbb_config_db extends phpbb_config * @param phpbb_cache_driver_interface $cache Cache instance * @param string $table Configuration table name */ - public function __construct(dbal $db, phpbb_cache_driver_interface $cache, $table) + public function __construct(phpbb_db_driver $db, phpbb_cache_driver_interface $cache, $table) { $this->db = $db; $this->cache = $cache; diff --git a/phpBB/includes/db/dbal.php b/phpBB/includes/db/dbal.php deleted file mode 100644 index 159703d3be..0000000000 --- a/phpBB/includes/db/dbal.php +++ /dev/null @@ -1,1049 +0,0 @@ -num_queries = array( - 'cached' => 0, - 'normal' => 0, - 'total' => 0, - ); - - // Fill default sql layer based on the class being called. - // This can be changed by the specified layer itself later if needed. - $this->sql_layer = substr(get_class($this), 5); - - // Do not change this please! This variable is used to easy the use of it - and is hardcoded. - $this->any_char = chr(0) . '%'; - $this->one_char = chr(0) . '_'; - } - - /** - * return on error or display error message - */ - function sql_return_on_error($fail = false) - { - $this->sql_error_triggered = false; - $this->sql_error_sql = ''; - - $this->return_on_error = $fail; - } - - /** - * Return number of sql queries and cached sql queries used - */ - function sql_num_queries($cached = false) - { - return ($cached) ? $this->num_queries['cached'] : $this->num_queries['normal']; - } - - /** - * Add to query count - */ - function sql_add_num_queries($cached = false) - { - $this->num_queries['cached'] += ($cached !== false) ? 1 : 0; - $this->num_queries['normal'] += ($cached !== false) ? 0 : 1; - $this->num_queries['total'] += 1; - } - - /** - * DBAL garbage collection, close sql connection - */ - function sql_close() - { - if (!$this->db_connect_id) - { - return false; - } - - if ($this->transaction) - { - do - { - $this->sql_transaction('commit'); - } - while ($this->transaction); - } - - foreach ($this->open_queries as $query_id) - { - $this->sql_freeresult($query_id); - } - - // Connection closed correctly. Set db_connect_id to false to prevent errors - if ($result = $this->_sql_close()) - { - $this->db_connect_id = false; - } - - return $result; - } - - /** - * Build LIMIT query - * Doing some validation here. - */ - function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - if (empty($query)) - { - return false; - } - - // Never use a negative total or offset - $total = ($total < 0) ? 0 : $total; - $offset = ($offset < 0) ? 0 : $offset; - - return $this->_sql_query_limit($query, $total, $offset, $cache_ttl); - } - - /** - * Fetch all rows - */ - function sql_fetchrowset($query_id = false) - { - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if ($query_id !== false) - { - $result = array(); - while ($row = $this->sql_fetchrow($query_id)) - { - $result[] = $row; - } - - return $result; - } - - return false; - } - - /** - * Seek to given row number - * rownum is zero-based - */ - function sql_rowseek($rownum, &$query_id) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_rowseek($rownum, $query_id); - } - - if ($query_id === false) - { - return false; - } - - $this->sql_freeresult($query_id); - $query_id = $this->sql_query($this->last_query_text); - - if ($query_id === false) - { - return false; - } - - // We do not fetch the row for rownum == 0 because then the next resultset would be the second row - for ($i = 0; $i < $rownum; $i++) - { - if (!$this->sql_fetchrow($query_id)) - { - return false; - } - } - - return true; - } - - /** - * Fetch field - * if rownum is false, the current row is used, else it is pointing to the row (zero-based) - */ - function sql_fetchfield($field, $rownum = false, $query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if ($query_id !== false) - { - if ($rownum !== false) - { - $this->sql_rowseek($rownum, $query_id); - } - - if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchfield($query_id, $field); - } - - $row = $this->sql_fetchrow($query_id); - return (isset($row[$field])) ? $row[$field] : false; - } - - return false; - } - - /** - * Correctly adjust LIKE expression for special characters - * Some DBMS are handling them in a different way - * - * @param string $expression The expression to use. Every wildcard is escaped, except $this->any_char and $this->one_char - * @return string LIKE expression including the keyword! - */ - function sql_like_expression($expression) - { - $expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression); - $expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression); - - return $this->_sql_like_expression('LIKE \'' . $this->sql_escape($expression) . '\''); - } - - /** - * Build a case expression - * - * Note: The two statements action_true and action_false must have the same data type (int, vchar, ...) in the database! - * - * @param string $condition The condition which must be true, to use action_true rather then action_else - * @param string $action_true SQL expression that is used, if the condition is true - * @param string $action_else SQL expression that is used, if the condition is false, optional - * @return string CASE expression including the condition and statements - */ - public function sql_case($condition, $action_true, $action_false = false) - { - $sql_case = 'CASE WHEN ' . $condition; - $sql_case .= ' THEN ' . $action_true; - $sql_case .= ($action_false !== false) ? ' ELSE ' . $action_false : ''; - $sql_case .= ' END'; - return $sql_case; - } - - /** - * Build a concatenated expression - * - * @param string $expr1 Base SQL expression where we append the second one - * @param string $expr2 SQL expression that is appended to the first expression - * @return string Concatenated string - */ - public function sql_concatenate($expr1, $expr2) - { - return $expr1 . ' || ' . $expr2; - } - - /** - * Returns whether results of a query need to be buffered to run a transaction while iterating over them. - * - * @return bool Whether buffering is required. - */ - function sql_buffer_nested_transactions() - { - return false; - } - - /** - * SQL Transaction - * @access private - */ - function sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - // If we are within a transaction we will not open another one, but enclose the current one to not loose data (prevening auto commit) - if ($this->transaction) - { - $this->transactions++; - return true; - } - - $result = $this->_sql_transaction('begin'); - - if (!$result) - { - $this->sql_error(); - } - - $this->transaction = true; - break; - - case 'commit': - // If there was a previously opened transaction we do not commit yet... but count back the number of inner transactions - if ($this->transaction && $this->transactions) - { - $this->transactions--; - return true; - } - - // Check if there is a transaction (no transaction can happen if there was an error, with a combined rollback and error returning enabled) - // This implies we have transaction always set for autocommit db's - if (!$this->transaction) - { - return false; - } - - $result = $this->_sql_transaction('commit'); - - if (!$result) - { - $this->sql_error(); - } - - $this->transaction = false; - $this->transactions = 0; - break; - - case 'rollback': - $result = $this->_sql_transaction('rollback'); - $this->transaction = false; - $this->transactions = 0; - break; - - default: - $result = $this->_sql_transaction($status); - break; - } - - return $result; - } - - /** - * Build sql statement from array for insert/update/select statements - * - * Idea for this from Ikonboard - * Possible query values: INSERT, INSERT_SELECT, UPDATE, SELECT - * - */ - function sql_build_array($query, $assoc_ary = false) - { - if (!is_array($assoc_ary)) - { - return false; - } - - $fields = $values = array(); - - if ($query == 'INSERT' || $query == 'INSERT_SELECT') - { - foreach ($assoc_ary as $key => $var) - { - $fields[] = $key; - - if (is_array($var) && is_string($var[0])) - { - // This is used for INSERT_SELECT(s) - $values[] = $var[0]; - } - else - { - $values[] = $this->_sql_validate_value($var); - } - } - - $query = ($query == 'INSERT') ? ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')' : ' (' . implode(', ', $fields) . ') SELECT ' . implode(', ', $values) . ' '; - } - else if ($query == 'MULTI_INSERT') - { - trigger_error('The MULTI_INSERT query value is no longer supported. Please use sql_multi_insert() instead.', E_USER_ERROR); - } - else if ($query == 'UPDATE' || $query == 'SELECT') - { - $values = array(); - foreach ($assoc_ary as $key => $var) - { - $values[] = "$key = " . $this->_sql_validate_value($var); - } - $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); - } - - return $query; - } - - /** - * Build IN or NOT IN sql comparison string, uses <> or = on single element - * arrays to improve comparison speed - * - * @access public - * @param string $field name of the sql column that shall be compared - * @param array $array array of values that are allowed (IN) or not allowed (NOT IN) - * @param bool $negate true for NOT IN (), false for IN () (default) - * @param bool $allow_empty_set If true, allow $array to be empty, this function will return 1=1 or 1=0 then. Default to false. - */ - function sql_in_set($field, $array, $negate = false, $allow_empty_set = false) - { - if (!sizeof($array)) - { - if (!$allow_empty_set) - { - // Print the backtrace to help identifying the location of the problematic code - $this->sql_error('No values specified for SQL IN comparison'); - } - else - { - // NOT IN () actually means everything so use a tautology - if ($negate) - { - return '1=1'; - } - // IN () actually means nothing so use a contradiction - else - { - return '1=0'; - } - } - } - - if (!is_array($array)) - { - $array = array($array); - } - - if (sizeof($array) == 1) - { - @reset($array); - $var = current($array); - - return $field . ($negate ? ' <> ' : ' = ') . $this->_sql_validate_value($var); - } - else - { - return $field . ($negate ? ' NOT IN ' : ' IN ') . '(' . implode(', ', array_map(array($this, '_sql_validate_value'), $array)) . ')'; - } - } - - /** - * Run binary AND operator on DB column. - * Results in sql statement: "{$column_name} & (1 << {$bit}) {$compare}" - * - * @param string $column_name The column name to use - * @param int $bit The value to use for the AND operator, will be converted to (1 << $bit). Is used by options, using the number schema... 0, 1, 2...29 - * @param string $compare Any custom SQL code after the check (for example "= 0") - */ - function sql_bit_and($column_name, $bit, $compare = '') - { - if (method_exists($this, '_sql_bit_and')) - { - return $this->_sql_bit_and($column_name, $bit, $compare); - } - - return $column_name . ' & ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); - } - - /** - * Run binary OR operator on DB column. - * Results in sql statement: "{$column_name} | (1 << {$bit}) {$compare}" - * - * @param string $column_name The column name to use - * @param int $bit The value to use for the OR operator, will be converted to (1 << $bit). Is used by options, using the number schema... 0, 1, 2...29 - * @param string $compare Any custom SQL code after the check (for example "= 0") - */ - function sql_bit_or($column_name, $bit, $compare = '') - { - if (method_exists($this, '_sql_bit_or')) - { - return $this->_sql_bit_or($column_name, $bit, $compare); - } - - return $column_name . ' | ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); - } - - /** - * Returns SQL string to cast a string expression to an int. - * - * @param string $expression An expression evaluating to string - * @return string Expression returning an int - */ - function cast_expr_to_bigint($expression) - { - return $expression; - } - - /** - * Returns SQL string to cast an integer expression to a string. - * - * @param string $expression An expression evaluating to int - * @return string Expression returning a string - */ - function cast_expr_to_string($expression) - { - return $expression; - } - - /** - * Run LOWER() on DB column of type text (i.e. neither varchar nor char). - * - * @param string $column_name The column name to use - * - * @return string A SQL statement like "LOWER($column_name)" - */ - function sql_lower_text($column_name) - { - return "LOWER($column_name)"; - } - - /** - * Run more than one insert statement. - * - * @param string $table table name to run the statements on - * @param array &$sql_ary multi-dimensional array holding the statement data. - * - * @return bool false if no statements were executed. - * @access public - */ - function sql_multi_insert($table, &$sql_ary) - { - if (!sizeof($sql_ary)) - { - return false; - } - - if ($this->multi_insert) - { - $ary = array(); - foreach ($sql_ary as $id => $_sql_ary) - { - // If by accident the sql array is only one-dimensional we build a normal insert statement - if (!is_array($_sql_ary)) - { - return $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $sql_ary)); - } - - $values = array(); - foreach ($_sql_ary as $key => $var) - { - $values[] = $this->_sql_validate_value($var); - } - $ary[] = '(' . implode(', ', $values) . ')'; - } - - return $this->sql_query('INSERT INTO ' . $table . ' ' . ' (' . implode(', ', array_keys($sql_ary[0])) . ') VALUES ' . implode(', ', $ary)); - } - else - { - foreach ($sql_ary as $ary) - { - if (!is_array($ary)) - { - return false; - } - - $result = $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary)); - - if (!$result) - { - return false; - } - } - } - - return true; - } - - /** - * Function for validating values - * @access private - */ - function _sql_validate_value($var) - { - if (is_null($var)) - { - return 'NULL'; - } - else if (is_string($var)) - { - return "'" . $this->sql_escape($var) . "'"; - } - else - { - return (is_bool($var)) ? intval($var) : $var; - } - } - - /** - * Build sql statement from array for select and select distinct statements - * - * Possible query values: SELECT, SELECT_DISTINCT - */ - function sql_build_query($query, $array) - { - $sql = ''; - switch ($query) - { - case 'SELECT': - case 'SELECT_DISTINCT'; - - $sql = str_replace('_', ' ', $query) . ' ' . $array['SELECT'] . ' FROM '; - - // Build table array. We also build an alias array for later checks. - $table_array = $aliases = array(); - $used_multi_alias = false; - - foreach ($array['FROM'] as $table_name => $alias) - { - if (is_array($alias)) - { - $used_multi_alias = true; - - foreach ($alias as $multi_alias) - { - $table_array[] = $table_name . ' ' . $multi_alias; - $aliases[] = $multi_alias; - } - } - else - { - $table_array[] = $table_name . ' ' . $alias; - $aliases[] = $alias; - } - } - - // We run the following code to determine if we need to re-order the table array. ;) - // The reason for this is that for multi-aliased tables (two equal tables) in the FROM statement the last table need to match the first comparison. - // DBMS who rely on this: Oracle, PostgreSQL and MSSQL. For all other DBMS it makes absolutely no difference in which order the table is. - if (!empty($array['LEFT_JOIN']) && sizeof($array['FROM']) > 1 && $used_multi_alias !== false) - { - // Take first LEFT JOIN - $join = current($array['LEFT_JOIN']); - - // Determine the table used there (even if there are more than one used, we only want to have one - preg_match('/(' . implode('|', $aliases) . ')\.[^\s]+/U', str_replace(array('(', ')', 'AND', 'OR', ' '), '', $join['ON']), $matches); - - // If there is a first join match, we need to make sure the table order is correct - if (!empty($matches[1])) - { - $first_join_match = trim($matches[1]); - $table_array = $last = array(); - - foreach ($array['FROM'] as $table_name => $alias) - { - if (is_array($alias)) - { - foreach ($alias as $multi_alias) - { - ($multi_alias === $first_join_match) ? $last[] = $table_name . ' ' . $multi_alias : $table_array[] = $table_name . ' ' . $multi_alias; - } - } - else - { - ($alias === $first_join_match) ? $last[] = $table_name . ' ' . $alias : $table_array[] = $table_name . ' ' . $alias; - } - } - - $table_array = array_merge($table_array, $last); - } - } - - $sql .= $this->_sql_custom_build('FROM', implode(' CROSS JOIN ', $table_array)); - - if (!empty($array['LEFT_JOIN'])) - { - foreach ($array['LEFT_JOIN'] as $join) - { - $sql .= ' LEFT JOIN ' . key($join['FROM']) . ' ' . current($join['FROM']) . ' ON (' . $join['ON'] . ')'; - } - } - - if (!empty($array['WHERE'])) - { - $sql .= ' WHERE ' . $this->_sql_custom_build('WHERE', $array['WHERE']); - } - - if (!empty($array['GROUP_BY'])) - { - $sql .= ' GROUP BY ' . $array['GROUP_BY']; - } - - if (!empty($array['ORDER_BY'])) - { - $sql .= ' ORDER BY ' . $array['ORDER_BY']; - } - - break; - } - - return $sql; - } - - /** - * display sql error page - */ - function sql_error($sql = '') - { - global $auth, $user, $config; - - // Set var to retrieve errored status - $this->sql_error_triggered = true; - $this->sql_error_sql = $sql; - - $this->sql_error_returned = $this->_sql_error(); - - if (!$this->return_on_error) - { - $message = 'SQL ERROR [ ' . $this->sql_layer . ' ]

' . $this->sql_error_returned['message'] . ' [' . $this->sql_error_returned['code'] . ']'; - - // Show complete SQL error and path to administrators only - // Additionally show complete error on installation or if extended debug mode is enabled - // The DEBUG_EXTRA constant is for development only! - if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || defined('DEBUG_EXTRA')) - { - $message .= ($sql) ? '

SQL

' . htmlspecialchars($sql) : ''; - } - else - { - // If error occurs in initiating the session we need to use a pre-defined language string - // This could happen if the connection could not be established for example (then we are not able to grab the default language) - if (!isset($user->lang['SQL_ERROR_OCCURRED'])) - { - $message .= '

An sql error occurred while fetching this page. Please contact an administrator if this problem persists.'; - } - else - { - if (!empty($config['board_contact'])) - { - $message .= '

' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', ''); - } - else - { - $message .= '

' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', ''); - } - } - } - - if ($this->transaction) - { - $this->sql_transaction('rollback'); - } - - if (strlen($message) > 1024) - { - // We need to define $msg_long_text here to circumvent text stripping. - global $msg_long_text; - $msg_long_text = $message; - - trigger_error(false, E_USER_ERROR); - } - - trigger_error($message, E_USER_ERROR); - } - - if ($this->transaction) - { - $this->sql_transaction('rollback'); - } - - return $this->sql_error_returned; - } - - /** - * Explain queries - */ - function sql_report($mode, $query = '') - { - global $cache, $starttime, $phpbb_root_path, $user; - global $request; - - if (is_object($request) && !$request->variable('explain', false)) - { - return false; - } - - if (!$query && $this->query_hold != '') - { - $query = $this->query_hold; - } - - switch ($mode) - { - case 'display': - if (!empty($cache)) - { - $cache->unload(); - } - $this->sql_close(); - - $mtime = explode(' ', microtime()); - $totaltime = $mtime[0] + $mtime[1] - $starttime; - - echo ' - - - - SQL Report - - - -
- -
-
-
- -
-

SQL Report

-
-

Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries['normal']} queries" . (($this->num_queries['cached']) ? " + {$this->num_queries['cached']} " . (($this->num_queries['cached'] == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '

- -

Time spent on ' . $this->sql_layer . ' queries: ' . round($this->sql_time, 5) . 's | Time spent on PHP: ' . round($totaltime - $this->sql_time, 5) . 's

- -

- ' . $this->sql_report . ' -
- -
-
-
- -
- - '; - - exit_handler(); - - break; - - case 'stop': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $this->sql_report .= ' - - - - - - - - - - - - -
Query #' . $this->num_queries['total'] . '
- - ' . $this->html_hold . ' - -

- '; - - if ($this->query_result) - { - if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)) - { - $this->sql_report .= 'Affected rows: ' . $this->sql_affectedrows($this->query_result) . ' | '; - } - $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: ' . sprintf('%.5f', $endtime - $this->curtime) . 's'; - } - else - { - $error = $this->sql_error(); - $this->sql_report .= 'FAILED - ' . $this->sql_layer . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); - } - - $this->sql_report .= '



'; - - $this->sql_time += $endtime - $this->curtime; - break; - - case 'start': - $this->query_hold = $query; - $this->html_hold = ''; - - $this->_sql_report($mode, $query); - - $this->curtime = explode(' ', microtime()); - $this->curtime = $this->curtime[0] + $this->curtime[1]; - - break; - - case 'add_select_row': - - $html_table = func_get_arg(2); - $row = func_get_arg(3); - - if (!$html_table && sizeof($row)) - { - $html_table = true; - $this->html_hold .= ''; - - foreach (array_keys($row) as $val) - { - $this->html_hold .= ''; - } - $this->html_hold .= ''; - } - $this->html_hold .= ''; - - $class = 'row1'; - foreach (array_values($row) as $val) - { - $class = ($class == 'row1') ? 'row2' : 'row1'; - $this->html_hold .= ''; - } - $this->html_hold .= ''; - - return $html_table; - - break; - - case 'fromcache': - - $this->_sql_report($mode, $query); - - break; - - case 'record_fromcache': - - $endtime = func_get_arg(2); - $splittime = func_get_arg(3); - - $time_cache = $endtime - $this->curtime; - $time_db = $splittime - $endtime; - $color = ($time_db > $time_cache) ? 'green' : 'red'; - - $this->sql_report .= '
' . (($val) ? ucwords(str_replace('_', ' ', $val)) : ' ') . '
' . (($val) ? $val : ' ') . '
'; - $this->sql_report .= '
Query results obtained from the cache
'; - $this->sql_report .= '

'; - $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: ' . sprintf('%.5f', ($time_cache)) . 's | Elapsed [db]: ' . sprintf('%.5f', $time_db) . 's



'; - - // Pad the start time to not interfere with page timing - $starttime += $time_db; - - break; - - default: - - $this->_sql_report($mode, $query); - - break; - } - - return true; - } - - /** - * Gets the estimated number of rows in a specified table. - * - * @param string $table_name Table name - * - * @return string Number of rows in $table_name. - * Prefixed with ~ if estimated (otherwise exact). - * - * @access public - */ - function get_estimated_row_count($table_name) - { - return $this->get_row_count($table_name); - } - - /** - * Gets the exact number of rows in a specified table. - * - * @param string $table_name Table name - * - * @return string Exact number of rows in $table_name. - * - * @access public - */ - function get_row_count($table_name) - { - $sql = 'SELECT COUNT(*) AS rows_total - FROM ' . $this->sql_escape($table_name); - $result = $this->sql_query($sql); - $rows_total = $this->sql_fetchfield('rows_total'); - $this->sql_freeresult($result); - - return $rows_total; - } -} - -/** -* This variable holds the class name to use later -*/ -$sql_db = (!empty($dbms)) ? 'dbal_' . basename($dbms) : 'dbal'; diff --git a/phpBB/includes/db/driver/driver.php b/phpBB/includes/db/driver/driver.php new file mode 100644 index 0000000000..39211a5af4 --- /dev/null +++ b/phpBB/includes/db/driver/driver.php @@ -0,0 +1,1044 @@ +num_queries = array( + 'cached' => 0, + 'normal' => 0, + 'total' => 0, + ); + + // Fill default sql layer based on the class being called. + // This can be changed by the specified layer itself later if needed. + $this->sql_layer = substr(get_class($this), 5); + + // Do not change this please! This variable is used to easy the use of it - and is hardcoded. + $this->any_char = chr(0) . '%'; + $this->one_char = chr(0) . '_'; + } + + /** + * return on error or display error message + */ + function sql_return_on_error($fail = false) + { + $this->sql_error_triggered = false; + $this->sql_error_sql = ''; + + $this->return_on_error = $fail; + } + + /** + * Return number of sql queries and cached sql queries used + */ + function sql_num_queries($cached = false) + { + return ($cached) ? $this->num_queries['cached'] : $this->num_queries['normal']; + } + + /** + * Add to query count + */ + function sql_add_num_queries($cached = false) + { + $this->num_queries['cached'] += ($cached !== false) ? 1 : 0; + $this->num_queries['normal'] += ($cached !== false) ? 0 : 1; + $this->num_queries['total'] += 1; + } + + /** + * DBAL garbage collection, close sql connection + */ + function sql_close() + { + if (!$this->db_connect_id) + { + return false; + } + + if ($this->transaction) + { + do + { + $this->sql_transaction('commit'); + } + while ($this->transaction); + } + + foreach ($this->open_queries as $query_id) + { + $this->sql_freeresult($query_id); + } + + // Connection closed correctly. Set db_connect_id to false to prevent errors + if ($result = $this->_sql_close()) + { + $this->db_connect_id = false; + } + + return $result; + } + + /** + * Build LIMIT query + * Doing some validation here. + */ + function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) + { + if (empty($query)) + { + return false; + } + + // Never use a negative total or offset + $total = ($total < 0) ? 0 : $total; + $offset = ($offset < 0) ? 0 : $offset; + + return $this->_sql_query_limit($query, $total, $offset, $cache_ttl); + } + + /** + * Fetch all rows + */ + function sql_fetchrowset($query_id = false) + { + if ($query_id === false) + { + $query_id = $this->query_result; + } + + if ($query_id !== false) + { + $result = array(); + while ($row = $this->sql_fetchrow($query_id)) + { + $result[] = $row; + } + + return $result; + } + + return false; + } + + /** + * Seek to given row number + * rownum is zero-based + */ + function sql_rowseek($rownum, &$query_id) + { + global $cache; + + if ($query_id === false) + { + $query_id = $this->query_result; + } + + if (isset($cache->sql_rowset[$query_id])) + { + return $cache->sql_rowseek($rownum, $query_id); + } + + if ($query_id === false) + { + return false; + } + + $this->sql_freeresult($query_id); + $query_id = $this->sql_query($this->last_query_text); + + if ($query_id === false) + { + return false; + } + + // We do not fetch the row for rownum == 0 because then the next resultset would be the second row + for ($i = 0; $i < $rownum; $i++) + { + if (!$this->sql_fetchrow($query_id)) + { + return false; + } + } + + return true; + } + + /** + * Fetch field + * if rownum is false, the current row is used, else it is pointing to the row (zero-based) + */ + function sql_fetchfield($field, $rownum = false, $query_id = false) + { + global $cache; + + if ($query_id === false) + { + $query_id = $this->query_result; + } + + if ($query_id !== false) + { + if ($rownum !== false) + { + $this->sql_rowseek($rownum, $query_id); + } + + if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) + { + return $cache->sql_fetchfield($query_id, $field); + } + + $row = $this->sql_fetchrow($query_id); + return (isset($row[$field])) ? $row[$field] : false; + } + + return false; + } + + /** + * Correctly adjust LIKE expression for special characters + * Some DBMS are handling them in a different way + * + * @param string $expression The expression to use. Every wildcard is escaped, except $this->any_char and $this->one_char + * @return string LIKE expression including the keyword! + */ + function sql_like_expression($expression) + { + $expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression); + $expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression); + + return $this->_sql_like_expression('LIKE \'' . $this->sql_escape($expression) . '\''); + } + + /** + * Build a case expression + * + * Note: The two statements action_true and action_false must have the same data type (int, vchar, ...) in the database! + * + * @param string $condition The condition which must be true, to use action_true rather then action_else + * @param string $action_true SQL expression that is used, if the condition is true + * @param string $action_else SQL expression that is used, if the condition is false, optional + * @return string CASE expression including the condition and statements + */ + public function sql_case($condition, $action_true, $action_false = false) + { + $sql_case = 'CASE WHEN ' . $condition; + $sql_case .= ' THEN ' . $action_true; + $sql_case .= ($action_false !== false) ? ' ELSE ' . $action_false : ''; + $sql_case .= ' END'; + return $sql_case; + } + + /** + * Build a concatenated expression + * + * @param string $expr1 Base SQL expression where we append the second one + * @param string $expr2 SQL expression that is appended to the first expression + * @return string Concatenated string + */ + public function sql_concatenate($expr1, $expr2) + { + return $expr1 . ' || ' . $expr2; + } + + /** + * Returns whether results of a query need to be buffered to run a transaction while iterating over them. + * + * @return bool Whether buffering is required. + */ + function sql_buffer_nested_transactions() + { + return false; + } + + /** + * SQL Transaction + * @access private + */ + function sql_transaction($status = 'begin') + { + switch ($status) + { + case 'begin': + // If we are within a transaction we will not open another one, but enclose the current one to not loose data (prevening auto commit) + if ($this->transaction) + { + $this->transactions++; + return true; + } + + $result = $this->_sql_transaction('begin'); + + if (!$result) + { + $this->sql_error(); + } + + $this->transaction = true; + break; + + case 'commit': + // If there was a previously opened transaction we do not commit yet... but count back the number of inner transactions + if ($this->transaction && $this->transactions) + { + $this->transactions--; + return true; + } + + // Check if there is a transaction (no transaction can happen if there was an error, with a combined rollback and error returning enabled) + // This implies we have transaction always set for autocommit db's + if (!$this->transaction) + { + return false; + } + + $result = $this->_sql_transaction('commit'); + + if (!$result) + { + $this->sql_error(); + } + + $this->transaction = false; + $this->transactions = 0; + break; + + case 'rollback': + $result = $this->_sql_transaction('rollback'); + $this->transaction = false; + $this->transactions = 0; + break; + + default: + $result = $this->_sql_transaction($status); + break; + } + + return $result; + } + + /** + * Build sql statement from array for insert/update/select statements + * + * Idea for this from Ikonboard + * Possible query values: INSERT, INSERT_SELECT, UPDATE, SELECT + * + */ + function sql_build_array($query, $assoc_ary = false) + { + if (!is_array($assoc_ary)) + { + return false; + } + + $fields = $values = array(); + + if ($query == 'INSERT' || $query == 'INSERT_SELECT') + { + foreach ($assoc_ary as $key => $var) + { + $fields[] = $key; + + if (is_array($var) && is_string($var[0])) + { + // This is used for INSERT_SELECT(s) + $values[] = $var[0]; + } + else + { + $values[] = $this->_sql_validate_value($var); + } + } + + $query = ($query == 'INSERT') ? ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')' : ' (' . implode(', ', $fields) . ') SELECT ' . implode(', ', $values) . ' '; + } + else if ($query == 'MULTI_INSERT') + { + trigger_error('The MULTI_INSERT query value is no longer supported. Please use sql_multi_insert() instead.', E_USER_ERROR); + } + else if ($query == 'UPDATE' || $query == 'SELECT') + { + $values = array(); + foreach ($assoc_ary as $key => $var) + { + $values[] = "$key = " . $this->_sql_validate_value($var); + } + $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); + } + + return $query; + } + + /** + * Build IN or NOT IN sql comparison string, uses <> or = on single element + * arrays to improve comparison speed + * + * @access public + * @param string $field name of the sql column that shall be compared + * @param array $array array of values that are allowed (IN) or not allowed (NOT IN) + * @param bool $negate true for NOT IN (), false for IN () (default) + * @param bool $allow_empty_set If true, allow $array to be empty, this function will return 1=1 or 1=0 then. Default to false. + */ + function sql_in_set($field, $array, $negate = false, $allow_empty_set = false) + { + if (!sizeof($array)) + { + if (!$allow_empty_set) + { + // Print the backtrace to help identifying the location of the problematic code + $this->sql_error('No values specified for SQL IN comparison'); + } + else + { + // NOT IN () actually means everything so use a tautology + if ($negate) + { + return '1=1'; + } + // IN () actually means nothing so use a contradiction + else + { + return '1=0'; + } + } + } + + if (!is_array($array)) + { + $array = array($array); + } + + if (sizeof($array) == 1) + { + @reset($array); + $var = current($array); + + return $field . ($negate ? ' <> ' : ' = ') . $this->_sql_validate_value($var); + } + else + { + return $field . ($negate ? ' NOT IN ' : ' IN ') . '(' . implode(', ', array_map(array($this, '_sql_validate_value'), $array)) . ')'; + } + } + + /** + * Run binary AND operator on DB column. + * Results in sql statement: "{$column_name} & (1 << {$bit}) {$compare}" + * + * @param string $column_name The column name to use + * @param int $bit The value to use for the AND operator, will be converted to (1 << $bit). Is used by options, using the number schema... 0, 1, 2...29 + * @param string $compare Any custom SQL code after the check (for example "= 0") + */ + function sql_bit_and($column_name, $bit, $compare = '') + { + if (method_exists($this, '_sql_bit_and')) + { + return $this->_sql_bit_and($column_name, $bit, $compare); + } + + return $column_name . ' & ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); + } + + /** + * Run binary OR operator on DB column. + * Results in sql statement: "{$column_name} | (1 << {$bit}) {$compare}" + * + * @param string $column_name The column name to use + * @param int $bit The value to use for the OR operator, will be converted to (1 << $bit). Is used by options, using the number schema... 0, 1, 2...29 + * @param string $compare Any custom SQL code after the check (for example "= 0") + */ + function sql_bit_or($column_name, $bit, $compare = '') + { + if (method_exists($this, '_sql_bit_or')) + { + return $this->_sql_bit_or($column_name, $bit, $compare); + } + + return $column_name . ' | ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); + } + + /** + * Returns SQL string to cast a string expression to an int. + * + * @param string $expression An expression evaluating to string + * @return string Expression returning an int + */ + function cast_expr_to_bigint($expression) + { + return $expression; + } + + /** + * Returns SQL string to cast an integer expression to a string. + * + * @param string $expression An expression evaluating to int + * @return string Expression returning a string + */ + function cast_expr_to_string($expression) + { + return $expression; + } + + /** + * Run LOWER() on DB column of type text (i.e. neither varchar nor char). + * + * @param string $column_name The column name to use + * + * @return string A SQL statement like "LOWER($column_name)" + */ + function sql_lower_text($column_name) + { + return "LOWER($column_name)"; + } + + /** + * Run more than one insert statement. + * + * @param string $table table name to run the statements on + * @param array &$sql_ary multi-dimensional array holding the statement data. + * + * @return bool false if no statements were executed. + * @access public + */ + function sql_multi_insert($table, &$sql_ary) + { + if (!sizeof($sql_ary)) + { + return false; + } + + if ($this->multi_insert) + { + $ary = array(); + foreach ($sql_ary as $id => $_sql_ary) + { + // If by accident the sql array is only one-dimensional we build a normal insert statement + if (!is_array($_sql_ary)) + { + return $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $sql_ary)); + } + + $values = array(); + foreach ($_sql_ary as $key => $var) + { + $values[] = $this->_sql_validate_value($var); + } + $ary[] = '(' . implode(', ', $values) . ')'; + } + + return $this->sql_query('INSERT INTO ' . $table . ' ' . ' (' . implode(', ', array_keys($sql_ary[0])) . ') VALUES ' . implode(', ', $ary)); + } + else + { + foreach ($sql_ary as $ary) + { + if (!is_array($ary)) + { + return false; + } + + $result = $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary)); + + if (!$result) + { + return false; + } + } + } + + return true; + } + + /** + * Function for validating values + * @access private + */ + function _sql_validate_value($var) + { + if (is_null($var)) + { + return 'NULL'; + } + else if (is_string($var)) + { + return "'" . $this->sql_escape($var) . "'"; + } + else + { + return (is_bool($var)) ? intval($var) : $var; + } + } + + /** + * Build sql statement from array for select and select distinct statements + * + * Possible query values: SELECT, SELECT_DISTINCT + */ + function sql_build_query($query, $array) + { + $sql = ''; + switch ($query) + { + case 'SELECT': + case 'SELECT_DISTINCT'; + + $sql = str_replace('_', ' ', $query) . ' ' . $array['SELECT'] . ' FROM '; + + // Build table array. We also build an alias array for later checks. + $table_array = $aliases = array(); + $used_multi_alias = false; + + foreach ($array['FROM'] as $table_name => $alias) + { + if (is_array($alias)) + { + $used_multi_alias = true; + + foreach ($alias as $multi_alias) + { + $table_array[] = $table_name . ' ' . $multi_alias; + $aliases[] = $multi_alias; + } + } + else + { + $table_array[] = $table_name . ' ' . $alias; + $aliases[] = $alias; + } + } + + // We run the following code to determine if we need to re-order the table array. ;) + // The reason for this is that for multi-aliased tables (two equal tables) in the FROM statement the last table need to match the first comparison. + // DBMS who rely on this: Oracle, PostgreSQL and MSSQL. For all other DBMS it makes absolutely no difference in which order the table is. + if (!empty($array['LEFT_JOIN']) && sizeof($array['FROM']) > 1 && $used_multi_alias !== false) + { + // Take first LEFT JOIN + $join = current($array['LEFT_JOIN']); + + // Determine the table used there (even if there are more than one used, we only want to have one + preg_match('/(' . implode('|', $aliases) . ')\.[^\s]+/U', str_replace(array('(', ')', 'AND', 'OR', ' '), '', $join['ON']), $matches); + + // If there is a first join match, we need to make sure the table order is correct + if (!empty($matches[1])) + { + $first_join_match = trim($matches[1]); + $table_array = $last = array(); + + foreach ($array['FROM'] as $table_name => $alias) + { + if (is_array($alias)) + { + foreach ($alias as $multi_alias) + { + ($multi_alias === $first_join_match) ? $last[] = $table_name . ' ' . $multi_alias : $table_array[] = $table_name . ' ' . $multi_alias; + } + } + else + { + ($alias === $first_join_match) ? $last[] = $table_name . ' ' . $alias : $table_array[] = $table_name . ' ' . $alias; + } + } + + $table_array = array_merge($table_array, $last); + } + } + + $sql .= $this->_sql_custom_build('FROM', implode(' CROSS JOIN ', $table_array)); + + if (!empty($array['LEFT_JOIN'])) + { + foreach ($array['LEFT_JOIN'] as $join) + { + $sql .= ' LEFT JOIN ' . key($join['FROM']) . ' ' . current($join['FROM']) . ' ON (' . $join['ON'] . ')'; + } + } + + if (!empty($array['WHERE'])) + { + $sql .= ' WHERE ' . $this->_sql_custom_build('WHERE', $array['WHERE']); + } + + if (!empty($array['GROUP_BY'])) + { + $sql .= ' GROUP BY ' . $array['GROUP_BY']; + } + + if (!empty($array['ORDER_BY'])) + { + $sql .= ' ORDER BY ' . $array['ORDER_BY']; + } + + break; + } + + return $sql; + } + + /** + * display sql error page + */ + function sql_error($sql = '') + { + global $auth, $user, $config; + + // Set var to retrieve errored status + $this->sql_error_triggered = true; + $this->sql_error_sql = $sql; + + $this->sql_error_returned = $this->_sql_error(); + + if (!$this->return_on_error) + { + $message = 'SQL ERROR [ ' . $this->sql_layer . ' ]

' . $this->sql_error_returned['message'] . ' [' . $this->sql_error_returned['code'] . ']'; + + // Show complete SQL error and path to administrators only + // Additionally show complete error on installation or if extended debug mode is enabled + // The DEBUG_EXTRA constant is for development only! + if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || defined('DEBUG_EXTRA')) + { + $message .= ($sql) ? '

SQL

' . htmlspecialchars($sql) : ''; + } + else + { + // If error occurs in initiating the session we need to use a pre-defined language string + // This could happen if the connection could not be established for example (then we are not able to grab the default language) + if (!isset($user->lang['SQL_ERROR_OCCURRED'])) + { + $message .= '

An sql error occurred while fetching this page. Please contact an administrator if this problem persists.'; + } + else + { + if (!empty($config['board_contact'])) + { + $message .= '

' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', ''); + } + else + { + $message .= '

' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', ''); + } + } + } + + if ($this->transaction) + { + $this->sql_transaction('rollback'); + } + + if (strlen($message) > 1024) + { + // We need to define $msg_long_text here to circumvent text stripping. + global $msg_long_text; + $msg_long_text = $message; + + trigger_error(false, E_USER_ERROR); + } + + trigger_error($message, E_USER_ERROR); + } + + if ($this->transaction) + { + $this->sql_transaction('rollback'); + } + + return $this->sql_error_returned; + } + + /** + * Explain queries + */ + function sql_report($mode, $query = '') + { + global $cache, $starttime, $phpbb_root_path, $user; + global $request; + + if (is_object($request) && !$request->variable('explain', false)) + { + return false; + } + + if (!$query && $this->query_hold != '') + { + $query = $this->query_hold; + } + + switch ($mode) + { + case 'display': + if (!empty($cache)) + { + $cache->unload(); + } + $this->sql_close(); + + $mtime = explode(' ', microtime()); + $totaltime = $mtime[0] + $mtime[1] - $starttime; + + echo ' + + + + SQL Report + + + +
+ +
+
+
+ +
+

SQL Report

+
+

Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries['normal']} queries" . (($this->num_queries['cached']) ? " + {$this->num_queries['cached']} " . (($this->num_queries['cached'] == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '

+ +

Time spent on ' . $this->sql_layer . ' queries: ' . round($this->sql_time, 5) . 's | Time spent on PHP: ' . round($totaltime - $this->sql_time, 5) . 's

+ +

+ ' . $this->sql_report . ' +
+ +
+
+
+ +
+ + '; + + exit_handler(); + + break; + + case 'stop': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $this->sql_report .= ' + + + + + + + + + + + + +
Query #' . $this->num_queries['total'] . '
+ + ' . $this->html_hold . ' + +

+ '; + + if ($this->query_result) + { + if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)) + { + $this->sql_report .= 'Affected rows: ' . $this->sql_affectedrows($this->query_result) . ' | '; + } + $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: ' . sprintf('%.5f', $endtime - $this->curtime) . 's'; + } + else + { + $error = $this->sql_error(); + $this->sql_report .= 'FAILED - ' . $this->sql_layer . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); + } + + $this->sql_report .= '



'; + + $this->sql_time += $endtime - $this->curtime; + break; + + case 'start': + $this->query_hold = $query; + $this->html_hold = ''; + + $this->_sql_report($mode, $query); + + $this->curtime = explode(' ', microtime()); + $this->curtime = $this->curtime[0] + $this->curtime[1]; + + break; + + case 'add_select_row': + + $html_table = func_get_arg(2); + $row = func_get_arg(3); + + if (!$html_table && sizeof($row)) + { + $html_table = true; + $this->html_hold .= ''; + + foreach (array_keys($row) as $val) + { + $this->html_hold .= ''; + } + $this->html_hold .= ''; + } + $this->html_hold .= ''; + + $class = 'row1'; + foreach (array_values($row) as $val) + { + $class = ($class == 'row1') ? 'row2' : 'row1'; + $this->html_hold .= ''; + } + $this->html_hold .= ''; + + return $html_table; + + break; + + case 'fromcache': + + $this->_sql_report($mode, $query); + + break; + + case 'record_fromcache': + + $endtime = func_get_arg(2); + $splittime = func_get_arg(3); + + $time_cache = $endtime - $this->curtime; + $time_db = $splittime - $endtime; + $color = ($time_db > $time_cache) ? 'green' : 'red'; + + $this->sql_report .= '
' . (($val) ? ucwords(str_replace('_', ' ', $val)) : ' ') . '
' . (($val) ? $val : ' ') . '
'; + $this->sql_report .= '
Query results obtained from the cache
'; + $this->sql_report .= '

'; + $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: ' . sprintf('%.5f', ($time_cache)) . 's | Elapsed [db]: ' . sprintf('%.5f', $time_db) . 's



'; + + // Pad the start time to not interfere with page timing + $starttime += $time_db; + + break; + + default: + + $this->_sql_report($mode, $query); + + break; + } + + return true; + } + + /** + * Gets the estimated number of rows in a specified table. + * + * @param string $table_name Table name + * + * @return string Number of rows in $table_name. + * Prefixed with ~ if estimated (otherwise exact). + * + * @access public + */ + function get_estimated_row_count($table_name) + { + return $this->get_row_count($table_name); + } + + /** + * Gets the exact number of rows in a specified table. + * + * @param string $table_name Table name + * + * @return string Exact number of rows in $table_name. + * + * @access public + */ + function get_row_count($table_name) + { + $sql = 'SELECT COUNT(*) AS rows_total + FROM ' . $this->sql_escape($table_name); + $result = $this->sql_query($sql); + $rows_total = $this->sql_fetchfield('rows_total'); + $this->sql_freeresult($result); + + return $rows_total; + } +} diff --git a/phpBB/includes/db/firebird.php b/phpBB/includes/db/driver/firebird.php similarity index 99% rename from phpBB/includes/db/firebird.php rename to phpBB/includes/db/driver/firebird.php index 7709e8fdf5..c793e0a51f 100644 --- a/phpBB/includes/db/firebird.php +++ b/phpBB/includes/db/driver/firebird.php @@ -15,14 +15,12 @@ if (!defined('IN_PHPBB')) exit; } -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - /** * Firebird/Interbase Database Abstraction Layer * Minimum Requirement is Firebird 2.1 * @package dbal */ -class dbal_firebird extends dbal +class phpbb_db_driver_firebird extends phpbb_db_driver { var $last_query_text = ''; var $service_handle = false; diff --git a/phpBB/includes/db/mssql.php b/phpBB/includes/db/driver/mssql.php similarity index 99% rename from phpBB/includes/db/mssql.php rename to phpBB/includes/db/driver/mssql.php index fb044b492f..e68738f918 100644 --- a/phpBB/includes/db/mssql.php +++ b/phpBB/includes/db/driver/mssql.php @@ -15,14 +15,12 @@ if (!defined('IN_PHPBB')) exit; } -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - /** * MSSQL Database Abstraction Layer * Minimum Requirement is MSSQL 2000+ * @package dbal */ -class dbal_mssql extends dbal +class phpbb_db_driver_mssql extends phpbb_db_driver { /** * Connect to server @@ -374,7 +372,7 @@ class dbal_mssql extends dbal FROM master.dbo.sysmessages WHERE error = ' . $error['code']; $result_id = @mssql_query($sql); - + if ($result_id) { $row = @mssql_fetch_assoc($result_id); diff --git a/phpBB/includes/db/mssql_odbc.php b/phpBB/includes/db/driver/mssql_odbc.php similarity index 98% rename from phpBB/includes/db/mssql_odbc.php rename to phpBB/includes/db/driver/mssql_odbc.php index 64fa9634d1..7b35ce3d11 100644 --- a/phpBB/includes/db/mssql_odbc.php +++ b/phpBB/includes/db/driver/mssql_odbc.php @@ -15,8 +15,6 @@ if (!defined('IN_PHPBB')) exit; } -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - /** * Unified ODBC functions * Unified ODBC functions support any database having ODBC driver, for example Adabas D, IBM DB2, iODBC, Solid, Sybase SQL Anywhere... @@ -28,7 +26,7 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); * * @package dbal */ -class dbal_mssql_odbc extends dbal +class phpbb_db_driver_mssql_odbc extends phpbb_db_driver { var $last_query_text = ''; diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/driver/mssqlnative.php similarity index 99% rename from phpBB/includes/db/mssqlnative.php rename to phpBB/includes/db/driver/mssqlnative.php index 1f37d54ecb..99b9d7975a 100644 --- a/phpBB/includes/db/mssqlnative.php +++ b/phpBB/includes/db/driver/mssqlnative.php @@ -19,8 +19,6 @@ if (!defined('IN_PHPBB')) exit; } -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - /** * Prior to version 1.1 the SQL Server Native PHP driver didn't support sqlsrv_num_rows, or cursor based seeking so we recall all rows into an array * and maintain our own cursor index into that array. @@ -193,7 +191,7 @@ class result_mssqlnative /** * @package dbal */ -class dbal_mssqlnative extends dbal +class phpbb_db_driver_mssqlnative extends phpbb_db_driver { var $m_insert_id = NULL; var $last_query_text = ''; diff --git a/phpBB/includes/db/mysql.php b/phpBB/includes/db/driver/mysql.php similarity index 99% rename from phpBB/includes/db/mysql.php rename to phpBB/includes/db/driver/mysql.php index 8d1f805870..987691341a 100644 --- a/phpBB/includes/db/mysql.php +++ b/phpBB/includes/db/driver/mysql.php @@ -15,8 +15,6 @@ if (!defined('IN_PHPBB')) exit; } -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - /** * MySQL4 Database Abstraction Layer * Compatible with: @@ -26,7 +24,7 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); * MySQL 5.0+ * @package dbal */ -class dbal_mysql extends dbal +class phpbb_db_driver_mysql extends phpbb_db_driver { var $multi_insert = true; diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/driver/mysqli.php similarity index 99% rename from phpBB/includes/db/mysqli.php rename to phpBB/includes/db/driver/mysqli.php index e07cd35e24..c473c7fe99 100644 --- a/phpBB/includes/db/mysqli.php +++ b/phpBB/includes/db/driver/mysqli.php @@ -15,15 +15,13 @@ if (!defined('IN_PHPBB')) exit; } -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - /** * MySQLi Database Abstraction Layer * mysqli-extension has to be compiled with: * MySQL 4.1+ or MySQL 5.0+ * @package dbal */ -class dbal_mysqli extends dbal +class phpbb_db_driver_mysqli extends phpbb_db_driver { var $multi_insert = true; diff --git a/phpBB/includes/db/oracle.php b/phpBB/includes/db/driver/oracle.php similarity index 99% rename from phpBB/includes/db/oracle.php rename to phpBB/includes/db/driver/oracle.php index 2e801532f0..25803e57bd 100644 --- a/phpBB/includes/db/oracle.php +++ b/phpBB/includes/db/driver/oracle.php @@ -15,13 +15,11 @@ if (!defined('IN_PHPBB')) exit; } -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - /** * Oracle Database Abstraction Layer * @package dbal */ -class dbal_oracle extends dbal +class phpbb_db_driver_oracle extends phpbb_db_driver { var $last_query_text = ''; diff --git a/phpBB/includes/db/postgres.php b/phpBB/includes/db/driver/postgres.php similarity index 98% rename from phpBB/includes/db/postgres.php rename to phpBB/includes/db/driver/postgres.php index bf22cffafa..3f54936d23 100644 --- a/phpBB/includes/db/postgres.php +++ b/phpBB/includes/db/driver/postgres.php @@ -15,19 +15,12 @@ if (!defined('IN_PHPBB')) exit; } -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - -if (!class_exists('phpbb_error_collector')) -{ - include($phpbb_root_path . 'includes/error_collector.' . $phpEx); -} - /** * PostgreSQL Database Abstraction Layer * Minimum Requirement is Version 7.3+ * @package dbal */ -class dbal_postgres extends dbal +class phpbb_db_driver_postgres extends phpbb_db_driver { var $last_query_text = ''; var $connect_error = ''; diff --git a/phpBB/includes/db/sqlite.php b/phpBB/includes/db/driver/sqlite.php similarity index 98% rename from phpBB/includes/db/sqlite.php rename to phpBB/includes/db/driver/sqlite.php index 86bfa75a13..363f26da2b 100644 --- a/phpBB/includes/db/sqlite.php +++ b/phpBB/includes/db/driver/sqlite.php @@ -15,14 +15,12 @@ if (!defined('IN_PHPBB')) exit; } -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - /** * Sqlite Database Abstraction Layer * Minimum Requirement: 2.8.2+ * @package dbal */ -class dbal_sqlite extends dbal +class phpbb_db_driver_sqlite extends phpbb_db_driver { /** * Connect to server diff --git a/phpBB/includes/extension/manager.php b/phpBB/includes/extension/manager.php index 537c19aff8..c3d1f58893 100644 --- a/phpBB/includes/extension/manager.php +++ b/phpBB/includes/extension/manager.php @@ -39,7 +39,7 @@ class phpbb_extension_manager * @param phpbb_cache_driver_interface $cache A cache instance or null * @param string $cache_name The name of the cache variable, defaults to _ext */ - public function __construct(dbal $db, $extension_table, $phpbb_root_path, $phpEx = '.php', phpbb_cache_driver_interface $cache = null, $cache_name = '_ext') + public function __construct(phpbb_db_driver $db, $extension_table, $phpbb_root_path, $phpEx = '.php', phpbb_cache_driver_interface $cache = null, $cache_name = '_ext') { $this->phpbb_root_path = $phpbb_root_path; $this->db = $db; @@ -432,7 +432,7 @@ class phpbb_extension_manager } return $disabled; } - + /** * Check to see if a given extension is available on the filesystem * diff --git a/phpBB/includes/functions_install.php b/phpBB/includes/functions_install.php index 46541acd44..413d8481b0 100644 --- a/phpBB/includes/functions_install.php +++ b/phpBB/includes/functions_install.php @@ -49,7 +49,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'firebird', 'MODULE' => 'interbase', 'DELIM' => ';;', - 'DRIVER' => 'firebird', + 'DRIVER' => 'phpbb_db_driver_firebird', 'AVAILABLE' => true, '2.0.x' => false, ), @@ -58,7 +58,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'mysql_41', 'MODULE' => 'mysqli', 'DELIM' => ';', - 'DRIVER' => 'mysqli', + 'DRIVER' => 'phpbb_db_driver_mysqli', 'AVAILABLE' => true, '2.0.x' => true, ), @@ -67,7 +67,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'mysql', 'MODULE' => 'mysql', 'DELIM' => ';', - 'DRIVER' => 'mysql', + 'DRIVER' => 'phpbb_db_driver_mysql', 'AVAILABLE' => true, '2.0.x' => true, ), @@ -76,7 +76,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'mssql', 'MODULE' => 'mssql', 'DELIM' => 'GO', - 'DRIVER' => 'mssql', + 'DRIVER' => 'phpbb_db_driver_mssql', 'AVAILABLE' => true, '2.0.x' => true, ), @@ -85,7 +85,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'mssql', 'MODULE' => 'odbc', 'DELIM' => 'GO', - 'DRIVER' => 'mssql_odbc', + 'DRIVER' => 'phpbb_db_driver_mssql_odbc', 'AVAILABLE' => true, '2.0.x' => true, ), @@ -94,7 +94,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'mssql', 'MODULE' => 'sqlsrv', 'DELIM' => 'GO', - 'DRIVER' => 'mssqlnative', + 'DRIVER' => 'phpbb_db_driver_mssqlnative', 'AVAILABLE' => true, '2.0.x' => false, ), @@ -103,7 +103,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'oracle', 'MODULE' => 'oci8', 'DELIM' => '/', - 'DRIVER' => 'oracle', + 'DRIVER' => 'phpbb_db_driver_oracle', 'AVAILABLE' => true, '2.0.x' => false, ), @@ -112,7 +112,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'postgres', 'MODULE' => 'pgsql', 'DELIM' => ';', - 'DRIVER' => 'postgres', + 'DRIVER' => 'phpbb_db_driver_postgres', 'AVAILABLE' => true, '2.0.x' => true, ), @@ -121,7 +121,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'sqlite', 'MODULE' => 'sqlite', 'DELIM' => ';', - 'DRIVER' => 'sqlite', + 'DRIVER' => 'phpbb_db_driver_sqlite', 'AVAILABLE' => true, '2.0.x' => false, ), @@ -229,26 +229,19 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, $dbms = $dbms_details['DRIVER']; - if ($load_dbal) - { - // Include the DB layer - include($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); - } - // Instantiate it and set return on error true - $sql_db = 'dbal_' . $dbms; - $db = new $sql_db(); + $db = new $dbms(); $db->sql_return_on_error(true); // Check that we actually have a database name before going any further..... - if ($dbms_details['DRIVER'] != 'sqlite' && $dbms_details['DRIVER'] != 'oracle' && $dbname === '') + if ($dbms_details['DRIVER'] != 'phpbb_db_driver_sqlite' && $dbms_details['DRIVER'] != 'phpbb_db_driver_oracle' && $dbname === '') { $error[] = $lang['INST_ERR_DB_NO_NAME']; return false; } // Make sure we don't have a daft user who thinks having the SQLite database in the forum directory is a good idea - if ($dbms_details['DRIVER'] == 'sqlite' && stripos(phpbb_realpath($dbhost), phpbb_realpath('../')) === 0) + if ($dbms_details['DRIVER'] == 'phpbb_db_driver_sqlite' && stripos(phpbb_realpath($dbhost), phpbb_realpath('../')) === 0) { $error[] = $lang['INST_ERR_DB_FORUM_PATH']; return false; @@ -257,8 +250,8 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, // Check the prefix length to ensure that index names are not too long and does not contain invalid characters switch ($dbms_details['DRIVER']) { - case 'mysql': - case 'mysqli': + case 'phpbb_db_driver_mysql': + case 'phpbb_db_driver_mysqli': if (strspn($table_prefix, '-./\\') !== 0) { $error[] = $lang['INST_ERR_PREFIX_INVALID']; @@ -267,22 +260,22 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, // no break; - case 'postgres': + case 'phpbb_db_driver_postgres': $prefix_length = 36; break; - case 'mssql': - case 'mssql_odbc': - case 'mssqlnative': + case 'phpbb_db_driver_mssql': + case 'phpbb_db_driver_mssql_odbc': + case 'phpbb_db_driver_mssqlnative': $prefix_length = 90; break; - case 'sqlite': + case 'phpbb_db_driver_sqlite': $prefix_length = 200; break; - case 'firebird': - case 'oracle': + case 'phpbb_db_driver_firebird': + case 'phpbb_db_driver_oracle': $prefix_length = 6; break; } @@ -320,21 +313,21 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, // Make sure that the user has selected a sensible DBAL for the DBMS actually installed switch ($dbms_details['DRIVER']) { - case 'mysqli': + case 'phpbb_db_driver_mysqli': if (version_compare(mysqli_get_server_info($db->db_connect_id), '4.1.3', '<')) { $error[] = $lang['INST_ERR_DB_NO_MYSQLI']; } break; - case 'sqlite': + case 'phpbb_db_driver_sqlite': if (version_compare(sqlite_libversion(), '2.8.2', '<')) { $error[] = $lang['INST_ERR_DB_NO_SQLITE']; } break; - case 'firebird': + case 'phpbb_db_driver_firebird': // check the version of FB, use some hackery if we can't get access to the server info if ($db->service_handle !== false && function_exists('ibase_server_info')) { @@ -415,7 +408,7 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, } break; - case 'oracle': + case 'phpbb_db_driver_oracle': if ($unicode_check) { $sql = "SELECT * @@ -437,7 +430,7 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, } break; - case 'postgres': + case 'phpbb_db_driver_postgres': if ($unicode_check) { $sql = "SHOW server_encoding;"; diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 6e99fd56a0..63a949762b 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -91,7 +91,6 @@ phpbb_require_updated('includes/functions_content.' . $phpEx, true); require($phpbb_root_path . 'includes/functions_admin.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); -require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx); phpbb_require_updated('includes/db/db_tools.' . $phpEx); @@ -121,7 +120,7 @@ $phpbb_class_loader->set_cache($cache->get_driver()); $phpbb_dispatcher = new phpbb_event_dispatcher(); $request = new phpbb_request(); $user = new phpbb_user(); -$db = new $sql_db(); +$db = new $dbms(); // make sure request_var uses this request instance request_var('', 0, false, false, $request); // "dependency injection" for a function @@ -2601,10 +2600,10 @@ function change_database_data(&$no_updates, $version) // Create config value for displaying last subject on forum list if (!isset($config['display_last_subject'])) - { + { $config->set('display_last_subject', '1'); } - + $no_updates = false; if (!isset($config['assets_version'])) diff --git a/phpBB/install/install_convert.php b/phpBB/install/install_convert.php index db974f9903..8f648066ba 100644 --- a/phpBB/install/install_convert.php +++ b/phpBB/install/install_convert.php @@ -121,10 +121,9 @@ class install_convert extends module require($phpbb_root_path . 'config.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); - require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); require($phpbb_root_path . 'includes/functions_convert.' . $phpEx); - $db = new $sql_db(); + $db = new $dbms(); $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true); unset($dbpasswd); @@ -209,10 +208,8 @@ class install_convert extends module require($phpbb_root_path . 'config.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); - require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); - require($phpbb_root_path . 'includes/functions_convert.' . $phpEx); - $db = new $sql_db(); + $db = new $dbms(); $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true); unset($dbpasswd); @@ -332,10 +329,9 @@ class install_convert extends module require($phpbb_root_path . 'config.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); - require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); require($phpbb_root_path . 'includes/functions_convert.' . $phpEx); - $db = new $sql_db(); + $db = new $dbms(); $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true); unset($dbpasswd); @@ -425,8 +421,7 @@ class install_convert extends module if ($src_dbms != $dbms || $src_dbhost != $dbhost || $src_dbport != $dbport || $src_dbname != $dbname || $src_dbuser != $dbuser) { - $sql_db = 'dbal_' . $src_dbms; - $src_db = new $sql_db(); + $src_db = new $src_dbms(); $src_db->sql_connect($src_dbhost, $src_dbuser, htmlspecialchars_decode($src_dbpasswd), $src_dbname, $src_dbport, false, true); $same_db = false; } @@ -575,10 +570,9 @@ class install_convert extends module require($phpbb_root_path . 'config.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); - require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); require($phpbb_root_path . 'includes/functions_convert.' . $phpEx); - $db = new $sql_db(); + $db = new $dbms(); $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true); unset($dbpasswd); @@ -639,12 +633,8 @@ class install_convert extends module $src_db = $same_db = null; if ($convert->src_dbms != $dbms || $convert->src_dbhost != $dbhost || $convert->src_dbport != $dbport || $convert->src_dbname != $dbname || $convert->src_dbuser != $dbuser) { - if ($convert->src_dbms != $dbms) - { - require($phpbb_root_path . 'includes/db/' . $convert->src_dbms . '.' . $phpEx); - } - $sql_db = 'dbal_' . $convert->src_dbms; - $src_db = new $sql_db(); + $dbms = $convert->src_dbms; + $src_db = new $dbms(); $src_db->sql_connect($convert->src_dbhost, $convert->src_dbuser, htmlspecialchars_decode($convert->src_dbpasswd), $convert->src_dbname, $convert->src_dbport, false, true); $same_db = false; } diff --git a/phpBB/install/install_install.php b/phpBB/install/install_install.php index 40dee7b3d7..520163ef9d 100644 --- a/phpBB/install/install_install.php +++ b/phpBB/install/install_install.php @@ -250,7 +250,7 @@ class install_install extends module 'S_EXPLAIN' => true, 'S_LEGEND' => false, )); - + // Check for php json support if (@extension_loaded('json')) { @@ -1144,11 +1144,8 @@ class install_install extends module $dbms = $available_dbms[$data['dbms']]['DRIVER']; - // Load the appropriate database class if not already loaded - include($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); - // Instantiate the database - $db = new $sql_db(); + $db = new $dbms(); $db->sql_connect($data['dbhost'], $data['dbuser'], htmlspecialchars_decode($data['dbpasswd']), $data['dbname'], $data['dbport'], false, false); // NOTE: trigger_error does not work here. @@ -1444,11 +1441,8 @@ class install_install extends module $dbms = $available_dbms[$data['dbms']]['DRIVER']; - // Load the appropriate database class if not already loaded - include($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); - // Instantiate the database - $db = new $sql_db(); + $db = new $dbms(); $db->sql_connect($data['dbhost'], $data['dbuser'], htmlspecialchars_decode($data['dbpasswd']), $data['dbname'], $data['dbport'], false, false); // NOTE: trigger_error does not work here. diff --git a/phpBB/install/install_update.php b/phpBB/install/install_update.php index c2feaa086a..fb76420033 100644 --- a/phpBB/install/install_update.php +++ b/phpBB/install/install_update.php @@ -83,7 +83,6 @@ class install_update extends module // Init DB require($phpbb_root_path . 'config.' . $phpEx); - require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); // Special options for conflicts/modified files @@ -92,7 +91,7 @@ class install_update extends module define('MERGE_NEW_FILE', 3); define('MERGE_MOD_FILE', 4); - $db = new $sql_db(); + $db = new $dbms(); // Connect to DB $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, false); diff --git a/tests/RUNNING_TESTS.txt b/tests/RUNNING_TESTS.txt index 7c2a7c3fce..0342179a6e 100644 --- a/tests/RUNNING_TESTS.txt +++ b/tests/RUNNING_TESTS.txt @@ -30,7 +30,7 @@ example for mysqli can be found below. More information on configuration options can be found on the wiki (see below). get_database_config(); // Firebird requires table and column names to be uppercase - if ($db_config['dbms'] == 'firebird') + if ($db_config['dbms'] == 'phpbb_db_driver_firebird') { $xml_data = file_get_contents($path); $xml_data = preg_replace_callback('/(?:())/', 'phpbb_database_test_case::to_upper', $xml_data); @@ -100,9 +100,8 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test $config = $this->get_database_config(); - require_once dirname(__FILE__) . '/../../phpBB/includes/db/' . $config['dbms'] . '.php'; - $dbal = 'dbal_' . $config['dbms']; - $db = new $dbal(); + $dbms = $config['dbms']; + $db = new $dbms(); $db->sql_connect($config['dbhost'], $config['dbuser'], $config['dbpasswd'], $config['dbname'], $config['dbport']); return $db; diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index 25e0972f42..db772496a0 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -108,7 +108,7 @@ class phpbb_database_test_connection_manager // These require different connection strings on the phpBB side than they do in PDO // so you must provide a DSN string for ODBC separately - if (!empty($this->config['custom_dsn']) && ($this->config['dbms'] == 'mssql' || $this->config['dbms'] == 'firebird')) + if (!empty($this->config['custom_dsn']) && ($this->config['dbms'] == 'phpbb_db_driver_mssql' || $this->config['dbms'] == 'phpbb_db_driver_firebird')) { $dsn = 'odbc:' . $this->config['custom_dsn']; } @@ -117,12 +117,12 @@ class phpbb_database_test_connection_manager { switch ($this->config['dbms']) { - case 'mssql': - case 'mssql_odbc': + case 'phpbb_db_driver_mssql': + case 'phpbb_db_driver_mssql_odbc': $this->pdo = new phpbb_database_connection_odbc_pdo_wrapper('mssql', 0, $dsn, $this->config['dbuser'], $this->config['dbpasswd']); break; - case 'firebird': + case 'phpbb_db_driver_firebird': if (!empty($this->config['custom_dsn'])) { $this->pdo = new phpbb_database_connection_odbc_pdo_wrapper('firebird', 0, $dsn, $this->config['dbuser'], $this->config['dbpasswd']); @@ -165,14 +165,14 @@ class phpbb_database_test_connection_manager { switch ($this->config['dbms']) { - case 'sqlite': + case 'phpbb_db_driver_sqlite': if (file_exists($this->config['dbhost'])) { unlink($this->config['dbhost']); } break; - case 'firebird': + case 'phpbb_db_driver_firebird': $this->connect(); // Drop all of the tables foreach ($this->get_tables() as $table) @@ -182,7 +182,7 @@ class phpbb_database_test_connection_manager $this->purge_extras(); break; - case 'oracle': + case 'phpbb_db_driver_oracle': $this->connect(); // Drop all of the tables foreach ($this->get_tables() as $table) @@ -232,39 +232,39 @@ class phpbb_database_test_connection_manager switch ($this->config['dbms']) { - case 'mysql': - case 'mysql4': - case 'mysqli': + case 'phpbb_db_driver_mysql': + case 'phpbb_db_driver_mysql4': + case 'phpbb_db_driver_mysqli': $sql = 'SHOW TABLES'; break; - case 'sqlite': + case 'phpbb_db_driver_sqlite': $sql = 'SELECT name FROM sqlite_master WHERE type = "table"'; break; - case 'mssql': - case 'mssql_odbc': - case 'mssqlnative': + case 'phpbb_db_driver_mssql': + case 'phpbb_db_driver_mssql_odbc': + case 'phpbb_db_driver_mssqlnative': $sql = "SELECT name FROM sysobjects WHERE type='U'"; break; - case 'postgres': + case 'phpbb_db_driver_postgres': $sql = 'SELECT relname FROM pg_stat_user_tables'; break; - case 'firebird': + case 'phpbb_db_driver_firebird': $sql = 'SELECT rdb$relation_name FROM rdb$relations WHERE rdb$view_source is null AND rdb$system_flag = 0'; break; - case 'oracle': + case 'phpbb_db_driver_oracle': $sql = 'SELECT table_name FROM USER_TABLES'; break; @@ -299,8 +299,8 @@ class phpbb_database_test_connection_manager protected function load_schema_from_file($directory) { $schema = $this->dbms['SCHEMA']; - - if ($this->config['dbms'] == 'mysql') + + if ($this->config['dbms'] == 'phpbb_db_driver_mysql') { $sth = $this->pdo->query('SELECT VERSION() AS version'); $row = $sth->fetch(PDO::FETCH_ASSOC); @@ -319,7 +319,7 @@ class phpbb_database_test_connection_manager $queries = file_get_contents($filename); $sql = phpbb_remove_comments($queries); - + $sql = split_sql_file($sql, $this->dbms['DELIM']); foreach ($sql as $query) @@ -403,7 +403,7 @@ class phpbb_database_test_connection_manager switch ($this->config['dbms']) { - case 'firebird': + case 'phpbb_db_driver_firebird': $sql = 'SELECT RDB$GENERATOR_NAME FROM RDB$GENERATORS WHERE RDB$SYSTEM_FLAG = 0'; @@ -415,7 +415,7 @@ class phpbb_database_test_connection_manager } break; - case 'oracle': + case 'phpbb_db_driver_oracle': $sql = 'SELECT sequence_name FROM USER_SEQUENCES'; $result = $this->pdo->query($sql); diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index c042d75811..ce0042d538 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -87,12 +87,8 @@ class phpbb_functional_test_case extends phpbb_test_case // so we don't reopen an open connection if (!($this->db instanceof dbal)) { - if (!class_exists('dbal_' . self::$config['dbms'])) - { - include($phpbb_root_path . 'includes/db/' . self::$config['dbms'] . ".$phpEx"); - } - $sql_db = 'dbal_' . self::$config['dbms']; - $this->db = new $sql_db(); + $dbms = self::$config['dbms']; + $this->db = new $dbms(); $this->db->sql_connect(self::$config['dbhost'], self::$config['dbuser'], self::$config['dbpasswd'], self::$config['dbname'], self::$config['dbport']); } return $this->db; diff --git a/tests/test_framework/phpbb_test_case_helpers.php b/tests/test_framework/phpbb_test_case_helpers.php index 46feef550a..5667aa6ca2 100644 --- a/tests/test_framework/phpbb_test_case_helpers.php +++ b/tests/test_framework/phpbb_test_case_helpers.php @@ -54,7 +54,7 @@ class phpbb_test_case_helpers if (extension_loaded('sqlite') && version_compare(PHPUnit_Runner_Version::id(), '3.4.15', '>=')) { $config = array_merge($config, array( - 'dbms' => 'sqlite', + 'dbms' => 'phpbb_db_driver_sqlite', 'dbhost' => dirname(__FILE__) . '/../phpbb_unit_tests.sqlite2', // filename 'dbport' => '', 'dbname' => '', From 65bafb22810038fd51e22fd8168775afd86c2e74 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Sat, 21 Jul 2012 18:08:40 +0200 Subject: [PATCH 004/497] [ticket/11015] Add BC files for the drivers PHPBB3-11015 --- phpBB/includes/db/firebird.php | 19 +++++++++++++++++++ phpBB/includes/db/mssql.php | 19 +++++++++++++++++++ phpBB/includes/db/mssql_odbc.php | 19 +++++++++++++++++++ phpBB/includes/db/mssqlnative.php | 19 +++++++++++++++++++ phpBB/includes/db/mysql.php | 19 +++++++++++++++++++ phpBB/includes/db/mysqli.php | 19 +++++++++++++++++++ phpBB/includes/db/oracle.php | 19 +++++++++++++++++++ phpBB/includes/db/postgres.php | 19 +++++++++++++++++++ phpBB/includes/db/sqlite.php | 19 +++++++++++++++++++ 9 files changed, 171 insertions(+) create mode 100644 phpBB/includes/db/firebird.php create mode 100644 phpBB/includes/db/mssql.php create mode 100644 phpBB/includes/db/mssql_odbc.php create mode 100644 phpBB/includes/db/mssqlnative.php create mode 100644 phpBB/includes/db/mysql.php create mode 100644 phpBB/includes/db/mysqli.php create mode 100644 phpBB/includes/db/oracle.php create mode 100644 phpBB/includes/db/postgres.php create mode 100644 phpBB/includes/db/sqlite.php diff --git a/phpBB/includes/db/firebird.php b/phpBB/includes/db/firebird.php new file mode 100644 index 0000000000..33f4e2ea48 --- /dev/null +++ b/phpBB/includes/db/firebird.php @@ -0,0 +1,19 @@ + Date: Sat, 21 Jul 2012 18:24:24 +0200 Subject: [PATCH 005/497] [ticket/11015] Correctly set sql_layer in driver base class PHPBB3-11015 --- phpBB/includes/db/driver/driver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/db/driver/driver.php b/phpBB/includes/db/driver/driver.php index 39211a5af4..9692ee71b9 100644 --- a/phpBB/includes/db/driver/driver.php +++ b/phpBB/includes/db/driver/driver.php @@ -82,7 +82,7 @@ class phpbb_db_driver // Fill default sql layer based on the class being called. // This can be changed by the specified layer itself later if needed. - $this->sql_layer = substr(get_class($this), 5); + $this->sql_layer = substr(get_class($this), strlen('phpbb_db_driver_')); // Do not change this please! This variable is used to easy the use of it - and is hardcoded. $this->any_char = chr(0) . '%'; From d6cca4e2c0719da35c75d3fff68f4a46255fe352 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Sat, 21 Jul 2012 19:35:39 +0200 Subject: [PATCH 006/497] [ticket/11015] Fix connection manager db driver selection PHPBB3-11015 --- .../phpbb_database_test_connection_manager.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index db772496a0..82da5fe4c3 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -334,47 +334,47 @@ class phpbb_database_test_connection_manager protected function get_dbms_data($dbms) { $available_dbms = array( - 'firebird' => array( + 'phpbb_db_driver_firebird' => array( 'SCHEMA' => 'firebird', 'DELIM' => ';;', 'PDO' => 'firebird', ), - 'mysqli' => array( + 'phpbb_db_driver_mysqli' => array( 'SCHEMA' => 'mysql_41', 'DELIM' => ';', 'PDO' => 'mysql', ), - 'mysql' => array( + 'phpbb_db_driver_mysql' => array( 'SCHEMA' => 'mysql', 'DELIM' => ';', 'PDO' => 'mysql', ), - 'mssql' => array( + 'phpbb_db_driver_mssql' => array( 'SCHEMA' => 'mssql', 'DELIM' => 'GO', 'PDO' => 'odbc', ), - 'mssql_odbc'=> array( + 'phpbb_db_driver_mssql_odbc'=> array( 'SCHEMA' => 'mssql', 'DELIM' => 'GO', 'PDO' => 'odbc', ), - 'mssqlnative' => array( + 'phpbb_db_driver_mssqlnative' => array( 'SCHEMA' => 'mssql', 'DELIM' => 'GO', 'PDO' => 'sqlsrv', ), - 'oracle' => array( + 'phpbb_db_driver_oracle' => array( 'SCHEMA' => 'oracle', 'DELIM' => '/', 'PDO' => 'oci', ), - 'postgres' => array( + 'phpbb_db_driver_postgres' => array( 'SCHEMA' => 'postgres', 'DELIM' => ';', 'PDO' => 'pgsql', ), - 'sqlite' => array( + 'phpbb_db_driver_sqlite' => array( 'SCHEMA' => 'sqlite', 'DELIM' => ';', 'PDO' => 'sqlite2', From c34ca32795f29c944c840f8282c025e4b322c891 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Sat, 21 Jul 2012 19:35:45 +0200 Subject: [PATCH 007/497] [ticket/11015] Fix db connection type hint in lock_db PHPBB3-11015 --- phpBB/includes/lock/db.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/lock/db.php b/phpBB/includes/lock/db.php index fa559d6887..40690144b1 100644 --- a/phpBB/includes/lock/db.php +++ b/phpBB/includes/lock/db.php @@ -61,7 +61,7 @@ class phpbb_lock_db * @param array $config The phpBB configuration * @param dbal $db A database connection */ - public function __construct($config_name, phpbb_config $config, dbal $db) + public function __construct($config_name, phpbb_config $config, phpbb_db_driver $db) { $this->config_name = $config_name; $this->config = $config; From 0971d3f975ebaa8c2874115bd82b308b244783f2 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Sat, 21 Jul 2012 19:57:00 +0200 Subject: [PATCH 008/497] [ticket/11015] Fix configuration for travis PHPBB3-11015 --- travis/phpunit-mysql-travis.xml | 2 +- travis/phpunit-postgres-travis.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/travis/phpunit-mysql-travis.xml b/travis/phpunit-mysql-travis.xml index e54b2bb77b..6eeffeff15 100644 --- a/travis/phpunit-mysql-travis.xml +++ b/travis/phpunit-mysql-travis.xml @@ -27,7 +27,7 @@ - + diff --git a/travis/phpunit-postgres-travis.xml b/travis/phpunit-postgres-travis.xml index 55ba996548..3a09c4a826 100644 --- a/travis/phpunit-postgres-travis.xml +++ b/travis/phpunit-postgres-travis.xml @@ -29,7 +29,7 @@ - + From fd6ee50e06cb48c9e3a476bf23285875484ff5f7 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 2 Nov 2012 16:05:53 -0400 Subject: [PATCH 009/497] [ticket/11162] Extract existing behavior into a function and add a test. PHPBB3-11162 --- phpBB/includes/functions.php | 24 ++++++- tests/functions/fixtures/duplicates.xml | 56 +++++++++++++++ .../update_rows_avoiding_duplicates_test.php | 71 +++++++++++++++++++ 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 tests/functions/fixtures/duplicates.xml create mode 100644 tests/functions/update_rows_avoiding_duplicates_test.php diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 65d8be32ad..8608c6ca4f 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -1297,6 +1297,28 @@ function tz_select($default = '', $truncate = false) return $tz_select; } +/** +* Updates rows in given table from a set of values to a new value. +* If this results in rows violating uniqueness constraints, the duplicate +* rows are eliminated. +* +* @param dbal $db Database object +* @param string $table Table on which to perform the update +* @param string $column Column whose values to change +* @param array $from_values An array of values that should be changed +* @param int $to_value The new value +* @return null +*/ +function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_values, $to_value) +{ + $db->sql_return_on_error(true); + $condition = $db->sql_in_set($column, $from_values); + $db->sql_query('UPDATE ' . $table . ' SET ' . $column . ' = ' . (int) $to_value. ' WHERE ' . $condition); + $db->sql_return_on_error(false); + + $db->sql_query('DELETE FROM ' . $table . ' WHERE ' . $condition); +} + // Functions handling topic/post tracking/marking /** @@ -3355,7 +3377,7 @@ function parse_cfg_file($filename, $lines = false) $parsed_items[$key] = $value; } - + if (isset($parsed_items['inherit_from']) && isset($parsed_items['name']) && $parsed_items['inherit_from'] == $parsed_items['name']) { unset($parsed_items['inherit_from']); diff --git a/tests/functions/fixtures/duplicates.xml b/tests/functions/fixtures/duplicates.xml new file mode 100644 index 0000000000..bc08016a8f --- /dev/null +++ b/tests/functions/fixtures/duplicates.xml @@ -0,0 +1,56 @@ + + +
+ user_id + topic_id + notify_status + + + + 1 + 1 + 1 + + + + + 2 + 2 + 1 + + + 3 + 3 + 1 + + + + + 1 + 4 + 1 + + + 1 + 5 + 1 + + + + + 1 + 6 + 1 + + + 1 + 7 + 1 + + + 2 + 6 + 1 + +
+ diff --git a/tests/functions/update_rows_avoiding_duplicates_test.php b/tests/functions/update_rows_avoiding_duplicates_test.php new file mode 100644 index 0000000000..0e949717d2 --- /dev/null +++ b/tests/functions/update_rows_avoiding_duplicates_test.php @@ -0,0 +1,71 @@ +createXMLDataSet(dirname(__FILE__).'/fixtures/duplicates.xml'); + } + + public static function fixture_data() + { + return array( + // description + // from array + // to value + // expected count with to value post update + array( + 'trivial', + array(1), + 10, + 1, + ), + array( + 'no conflict', + array(2), + 3, + 2, + ), + array( + 'conflict', + array(4), + 5, + 1, + ), + array( + 'conflict and no conflict', + array(6), + 7, + 2, + ), + ); + } + + /** + * @dataProvider fixture_data + */ + public function test_trivial_update($description, $from, $to, $expected_result_count) + { + $db = $this->new_dbal(); + + phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $from, $to); + + $sql = 'SELECT count(*) AS count + FROM ' . TOPICS_WATCH_TABLE . ' + WHERE topic_id = ' . $db->sql_escape($to); + $result = $db->sql_query($sql); + $result_count = $db->sql_fetchfield('count'); + $db->sql_freeresult($result); + + $this->assertEquals($expected_result_count, $result_count); + } +} From b0812c43fa05bec8c59e5ff3c7889f0f98089775 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 11 Nov 2012 17:40:58 +0100 Subject: [PATCH 010/497] [ticket/11162] Use integer casting instead of SQL escape. PHPBB3-11162 --- tests/functions/update_rows_avoiding_duplicates_test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functions/update_rows_avoiding_duplicates_test.php b/tests/functions/update_rows_avoiding_duplicates_test.php index 0e949717d2..e4e156209d 100644 --- a/tests/functions/update_rows_avoiding_duplicates_test.php +++ b/tests/functions/update_rows_avoiding_duplicates_test.php @@ -61,7 +61,7 @@ class phpbb_update_rows_avoiding_duplicates_test extends phpbb_database_test_cas $sql = 'SELECT count(*) AS count FROM ' . TOPICS_WATCH_TABLE . ' - WHERE topic_id = ' . $db->sql_escape($to); + WHERE topic_id = ' . (int) $to; $result = $db->sql_query($sql); $result_count = $db->sql_fetchfield('count'); $db->sql_freeresult($result); From 7d0cc15b926dda1a53b8151e063e2ffda7441240 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 11 Nov 2012 17:48:59 +0100 Subject: [PATCH 011/497] [ticket/11162] Rename count variable name to remaining_rows. PHPBB3-11162 --- tests/functions/update_rows_avoiding_duplicates_test.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/functions/update_rows_avoiding_duplicates_test.php b/tests/functions/update_rows_avoiding_duplicates_test.php index e4e156209d..0c9ae068a4 100644 --- a/tests/functions/update_rows_avoiding_duplicates_test.php +++ b/tests/functions/update_rows_avoiding_duplicates_test.php @@ -59,11 +59,11 @@ class phpbb_update_rows_avoiding_duplicates_test extends phpbb_database_test_cas phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $from, $to); - $sql = 'SELECT count(*) AS count + $sql = 'SELECT count(*) AS remaining_rows FROM ' . TOPICS_WATCH_TABLE . ' WHERE topic_id = ' . (int) $to; $result = $db->sql_query($sql); - $result_count = $db->sql_fetchfield('count'); + $result_count = $db->sql_fetchfield('remaining_rows'); $db->sql_freeresult($result); $this->assertEquals($expected_result_count, $result_count); From ac9c4d7d59ea458834cb64b9c9020c3de8fe90a2 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 11 Nov 2012 17:49:21 +0100 Subject: [PATCH 012/497] [ticket/11162] Make count function upper case. PHPBB3-11162 --- tests/functions/update_rows_avoiding_duplicates_test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functions/update_rows_avoiding_duplicates_test.php b/tests/functions/update_rows_avoiding_duplicates_test.php index 0c9ae068a4..0d68e22d4a 100644 --- a/tests/functions/update_rows_avoiding_duplicates_test.php +++ b/tests/functions/update_rows_avoiding_duplicates_test.php @@ -59,7 +59,7 @@ class phpbb_update_rows_avoiding_duplicates_test extends phpbb_database_test_cas phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $from, $to); - $sql = 'SELECT count(*) AS remaining_rows + $sql = 'SELECT COUNT(*) AS remaining_rows FROM ' . TOPICS_WATCH_TABLE . ' WHERE topic_id = ' . (int) $to; $result = $db->sql_query($sql); From 3e03f95cb73ad090e22514be856c9b0613e0448a Mon Sep 17 00:00:00 2001 From: Vjacheslav Trushkin Date: Sun, 11 Nov 2012 19:07:00 +0100 Subject: [PATCH 013/497] [ticket/10431] CSS3 buttons CSS3 replacements for big buttons PHPBB3-10431 --- phpBB/styles/prosilver/theme/buttons.css | 81 ++++++++++++------ phpBB/styles/prosilver/theme/colours.css | 8 -- .../styles/prosilver/theme/en/stylesheet.css | 16 ---- .../styles/prosilver/theme/images/buttons.png | Bin 0 -> 2563 bytes 4 files changed, 56 insertions(+), 49 deletions(-) create mode 100644 phpBB/styles/prosilver/theme/images/buttons.png diff --git a/phpBB/styles/prosilver/theme/buttons.css b/phpBB/styles/prosilver/theme/buttons.css index e817380f8e..9a69956368 100644 --- a/phpBB/styles/prosilver/theme/buttons.css +++ b/phpBB/styles/prosilver/theme/buttons.css @@ -14,40 +14,71 @@ .buttons div { float: left; margin: 0 5px 0 0; - background-position: 0 100%; } /* Rolloff state */ .buttons div a { - display: block; - width: 100%; - height: 100%; - background-position: 0 0; - position: relative; - overflow: hidden; + display: inline-block; + line-height: 16px; + font-size: 13px; + white-space: nowrap; + border: 1px solid #c7c3bf; + border-radius: 4px; + background: #fff none 0 0 repeat-x; + background-image: -moz-linear-gradient(top, #fff, #e9e9e9); + background-image: -webkit-linear-gradient(top, #fff, #e9e9e9); + background-image: -o-linear-gradient(top, #fff, #e9e9e9); + background-image: linear-gradient(to bottom, #fff, #e9e9e9); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffffff', EndColorStr='#e9e9e9')"; + box-shadow: 0 0 0 1px #fff inset; + -webkit-box-shadow: 0 0 0 1px #fff inset; + text-shadow: 1px 1px 0 #fff, -1px -1px 0 rgba(188, 42, 77, 0.25); + padding: 3px 22px 3px 8px; + color: #bc2a4d !important; + position: relative; + text-decoration: none !important; + outline-style: none !important; } -/* Hide text and hide off-state image when rolling over (prevents flicker in IE) */ -/*.buttons div span { display: none; }*/ -/*.buttons div a:hover { background-image: none; }*/ -.buttons div span { position: absolute; width: 100%; height: 100%; cursor: pointer;} -.buttons div a:hover span { background-position: 0 100%; } +.buttons div span { display: none; } +.buttons div a:hover { + border-color: #0a8ed0; + background-image: -moz-linear-gradient(top, #e9e9e9, #fff); + background-image: -webkit-linear-gradient(top, #e9e9e9, #fff); + background-image: -o-linear-gradient(top, #e9e9e9, #fff); + background-image: linear-gradient(to bottom, #e9e9e9, #fff); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#e9e9e9', EndColorStr='#ffffff')"; + text-shadow: 1px 1px 0 #fff, -1px -1px 0 #fff, -1px -1px 0 rgba(188, 42, 77, 0.2); +} + +.buttons div a:after { + content: ''; + display: block; + position: absolute; + top: 50%; + right: 6px; + width: 12px; + height: 12px; + margin-top: -6px; + background: url("images/buttons.png") 0px 0 no-repeat; +} + +.buttons div a:hover:after { + background-position: 0 -20px; +} /* Big button images */ -.reply-icon span { background: transparent none 0 0 no-repeat; } -.post-icon span { background: transparent none 0 0 no-repeat; } -.locked-icon span { background: transparent none 0 0 no-repeat; } -.pmreply-icon span { background: none 0 0 no-repeat; } -.newpm-icon span { background: none 0 0 no-repeat; } -.forwardpm-icon span { background: none 0 0 no-repeat; } +.buttons div.reply-icon a:after, .buttons div.pmreply-icon a:after { background-position: -20px 0; } +.buttons div.reply-icon a:hover:after, .buttons div.pmreply-icon a:hover:after { background-position: -20px -20px; } -/* Set big button dimensions */ -.buttons div.reply-icon { width: 96px; height: 25px; } -.buttons div.post-icon { width: 96px; height: 25px; } -.buttons div.locked-icon { width: 88px; height: 25px; } -.buttons div.pmreply-icon { width: 96px; height: 25px; } -.buttons div.newpm-icon { width: 84px; height: 25px; } -.buttons div.forwardpm-icon { width: 96px; height: 25px; } +.buttons div.post-icon a:after, .buttons div.newpm-icon a:after { background-position: 0 0; } +.buttons div.post-icon a:hover:after, .buttons div.newpm-icon a:hover:after { background-position: 0 -20px; } + +.buttons div.locked-icon a:after { background-position: -60px 0; } +.buttons div.locked-icon a:hover:after { background-position: -60px -20px; } + +.buttons div.forwardpm-icon a:after { background-position: -40px 0; } +.buttons div.forwardpm-icon a:hover:after { background-position: -40px -20px; } /* Sub-header (navigation bar) --------------------------------------------- */ diff --git a/phpBB/styles/prosilver/theme/colours.css b/phpBB/styles/prosilver/theme/colours.css index d7ce9a7622..0a8e011171 100644 --- a/phpBB/styles/prosilver/theme/colours.css +++ b/phpBB/styles/prosilver/theme/colours.css @@ -649,14 +649,6 @@ fieldset.polls dd div { Colours and backgrounds for buttons.css -------------------------------------------------------------- */ -/* Big button images */ -.reply-icon span { background-image: url("./en/button_topic_reply.gif"); } -.post-icon span { background-image: url("./en/button_topic_new.gif"); } -.locked-icon span { background-image: url("./en/button_topic_locked.gif"); } -.pmreply-icon span { background-image: url("./en/button_pm_reply.gif") ;} -.newpm-icon span { background-image: url("./en/button_pm_new.gif") ;} -.forwardpm-icon span { background-image: url("./en/button_pm_forward.gif") ;} - a.print { background-image: url("./images/icon_print.gif"); } diff --git a/phpBB/styles/prosilver/theme/en/stylesheet.css b/phpBB/styles/prosilver/theme/en/stylesheet.css index d17f9a5be4..1a3d0acb4b 100644 --- a/phpBB/styles/prosilver/theme/en/stylesheet.css +++ b/phpBB/styles/prosilver/theme/en/stylesheet.css @@ -1,11 +1,3 @@ -/* Set big button dimensions */ -.buttons div.reply-icon { width: 96px; height: 25px; } -.buttons div.post-icon { width: 96px; height: 25px; } -.buttons div.locked-icon { width: 88px; height: 25px; } -.buttons div.pmreply-icon { width: 96px; height: 25px; } -.buttons div.newpm-icon { width: 84px; height: 25px; } -.buttons div.forwardpm-icon { width: 96px; height: 25px; } - /* Set profile icon dimensions */ ul.profile-icons li.pm-icon { width: 28px; height: 20px; } ul.profile-icons li.quote-icon { width: 54px; height: 20px; } @@ -14,14 +6,6 @@ ul.profile-icons li.edit-icon { width: 42px; height: 20px; } /* Online image */ .online { background-image: url("./icon_user_online.gif"); } -/* Big button images */ -.reply-icon span { background-image: url("./button_topic_reply.gif"); } -.post-icon span { background-image: url("./button_topic_new.gif"); } -.locked-icon span { background-image: url("./button_topic_locked.gif"); } -.pmreply-icon span { background-image: url("./button_pm_reply.gif") ;} -.newpm-icon span { background-image: url("./button_pm_new.gif") ;} -.forwardpm-icon span { background-image: url("./button_pm_forward.gif") ;} - /* Icon images */ .pm-icon, .pm-icon a { background-image: url("./icon_contact_pm.gif"); } .quote-icon, .quote-icon a { background-image: url("./icon_post_quote.gif"); } diff --git a/phpBB/styles/prosilver/theme/images/buttons.png b/phpBB/styles/prosilver/theme/images/buttons.png new file mode 100644 index 0000000000000000000000000000000000000000..a19abdc2b8aeb3b344a1718d78314104082fa2ba GIT binary patch literal 2563 zcmbVOcT`hZ9?m9+fFlqA8?X~XuOXqN(Mdv)U<3rjfX3t@5mHD(LXkzHC|v?pnhdxK zQiQRhNOeIO2N+OMK*}Is1wkny>ONH5{lhbR&c6HJyXF19?^o`3&v_{{Z@0Bdo0T9C z$XX9~k`LI^z{f~I9(=QR$NvrNHi^iAB41vpNWu^R5N8%|4}kFCF!lmI0D~11c^9yQ zKwzP4zd%tS)r-L7aV!|iHWtwwK8S`u>>Q){3}!eWLhJ$dvbpxishbT*1e;}#46vbE zQu(ex7~4Ho0Qkmw`!Qp~nRph`(E(u>O#lfvfQW&J=0tFXglK!@7hVE5US38a5noJ1 z;r7U{K?PE22v?o}K-gGVnKLcXXoRh;1=`xi))sAsz*wR&C`<6RHAh<$Y-|Y_EaKaR z1icAZp#&ci<(n^XW{(ULiTDH*N+OY1NUSV)g1sm-9*ihktYAI3LJ@<@1XldALBHRy>v22xcslYzhYVcPt8zZ zFsNm5{Fhi(mOuqA55G$voP0k#02e$l0`O=QgdPckK;*4FNX~xIeXn*zx@!h({Old{ zqAT@}GNIyjHMc9pez2FKDsRn#^pC#%$1<)kG1k{#tL#kDNNP4SHgykpwC{XXj*cj= zxFEudeWjWZrIE8fHK^C5{E}13`E?l3lpPw0vZwXt3=qkzF?r^JjueY${m#NpgWCQg{|WIZk>DVWs+nrUC(MyD@L z58jH?qzOZs2(=liT}-%VE%U?>jxIs{6M(@tqIG-;0Yn+Pl$U zn_j6NT$=LyhPo6koV4~M3 z7bO-i!u9{DqMqmhgTa!NkCdp&aHq4f_$iwCd3jcWl@EP;dV26iXP+EV)?VCH<~Fu@ z18$t`1OQ_Wb9e6k>lk96bG2e>Bm7W_IV$1k5ZpkYh9wg7wAIvLn=@L6MTE67S-Ih6 zxTI@z`hb6VQgU+go3st6aSaWP$BLO4nBt7PU^r^Xdiatv>DlCD=*AoT5ov((?Rf6~ z&!0XX8$f2;T3InkZPuD(#^K+_+Tq?#GHi-qghrvX?iL7Uvb@^1ROjR$EGa2z$}-HA z$Hme0e!WT@+t_~Z-r4Z*@b}4TP_eFcheDlVasB zr^(8l*Su?=Os3b=ptsQJ1FYEC8*avl^p55Zld{~ccYcXgfcn7QrK;RS!>xr&s$)c0 zD#?juGd?yJKfN%`oNsUUj7~^M*j}Bc;ZHkZ_a_p0TwYyWztC)#&MJvaxh3FuVPWBg zg@uLM?(S|~_X&rDPy3B8++OcxL})#8scoSwB=&P!T1;@TcE&~1Y{j~>a+%shicB?G zmb}5r(ea`yxkU5I&%;H|F_Bp08>PFmfUfha?aC7^4RRl=cMFCndbA`dve-qR_O&H> z4)?Sgz_mXqHb^;V$TOc}g?%G@%g&05_> zkIue1lR(33@MfxNkE}088j-hV%^KCW<3Q_la4jJuVfN&v@%O|1P!kiAR3m7{tDe@Q zdU=q-k&I`L@vrqde0cfL#Wr1y3T8b4fslQ!P?sB0!|f}5&`b9kJU>o7I_}PyGC8H3ly-{olME^-f|@ec#JeH|)&=bm)EYq>Z+H^}G;D{icdTP?ofe|6TTtxln+ zlO=TXw&+kQ_P?&!KDcX#^ziCQ7x(ANAxA$1HC-Q2ur7H9P41F%jNxVlD%;|0P+G5Z z4~zTl8imh?(>tW%53sd`TkCd5f|^DYZizf=H8*Kw_-3}V_4LyDTQTw`4Sye9HJ>yp zNK1b3Jfwo%FnMS&#VuLyNUz-JRZGjgl!JKF&F?x7w@2lN=08QM63g@LrtR+ZjUr`N z%uPk>)+vPrKUTcnH}!ewQB}ZY%N{yRGD$!2@r-+=f!*bLJM3UYtWI4`uXs)V{h(Eg zrL?rW#KhbQr>2Yb4zji}hi=aSgiL5a8-8mFfk@vou3&qY`oP+X>{ z8v^T3LrcWM3$Hg37v3Mz3WBGc(lL& zmuYkRuu`|-rMEoXn+F^PaZR&Q>K$Jnl3vdNX|bG6DXs2U`D~7=6#DDp*fV4X$uWkP zX#4P8*Eq_Mc9PptTT_`JeW5q$-!)(tiUMbvMEQ literal 0 HcmV?d00001 From 8b1920adb59d2cc6e8bed558c56fb33ab5c4b0f7 Mon Sep 17 00:00:00 2001 From: Vjacheslav Trushkin Date: Mon, 12 Nov 2012 10:25:12 +0100 Subject: [PATCH 014/497] [ticket/10431] Different font for iOS Different font for buttons on iOS devices because Verdana looks incorrectly aligned in Safari/iOS. Also slightly changed text shadow. PHPBB3-10431 --- phpBB/styles/prosilver/theme/buttons.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/phpBB/styles/prosilver/theme/buttons.css b/phpBB/styles/prosilver/theme/buttons.css index 9a69956368..2ba17a7717 100644 --- a/phpBB/styles/prosilver/theme/buttons.css +++ b/phpBB/styles/prosilver/theme/buttons.css @@ -32,8 +32,9 @@ -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffffff', EndColorStr='#e9e9e9')"; box-shadow: 0 0 0 1px #fff inset; -webkit-box-shadow: 0 0 0 1px #fff inset; - text-shadow: 1px 1px 0 #fff, -1px -1px 0 rgba(188, 42, 77, 0.25); + text-shadow: 1px 1px 0 #fff, -1px -1px 1px rgba(188, 42, 77, 0.25); padding: 3px 22px 3px 8px; + font-family: "Futura-Medium", Verdana; color: #bc2a4d !important; position: relative; text-decoration: none !important; From 9bc9ac281af9f194d73160ae3545105f24db5395 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Mon, 12 Nov 2012 10:38:28 +0100 Subject: [PATCH 015/497] [ticket/11015] Remove old dbal classes PHPBB3-11015 --- phpBB/includes/db/firebird.php | 19 ------------------- phpBB/includes/db/mssql.php | 19 ------------------- phpBB/includes/db/mssql_odbc.php | 19 ------------------- phpBB/includes/db/mssqlnative.php | 19 ------------------- phpBB/includes/db/mysql.php | 19 ------------------- phpBB/includes/db/mysqli.php | 19 ------------------- phpBB/includes/db/oracle.php | 19 ------------------- phpBB/includes/db/postgres.php | 19 ------------------- phpBB/includes/db/sqlite.php | 19 ------------------- 9 files changed, 171 deletions(-) delete mode 100644 phpBB/includes/db/firebird.php delete mode 100644 phpBB/includes/db/mssql.php delete mode 100644 phpBB/includes/db/mssql_odbc.php delete mode 100644 phpBB/includes/db/mssqlnative.php delete mode 100644 phpBB/includes/db/mysql.php delete mode 100644 phpBB/includes/db/mysqli.php delete mode 100644 phpBB/includes/db/oracle.php delete mode 100644 phpBB/includes/db/postgres.php delete mode 100644 phpBB/includes/db/sqlite.php diff --git a/phpBB/includes/db/firebird.php b/phpBB/includes/db/firebird.php deleted file mode 100644 index 33f4e2ea48..0000000000 --- a/phpBB/includes/db/firebird.php +++ /dev/null @@ -1,19 +0,0 @@ - Date: Mon, 12 Nov 2012 10:42:11 +0100 Subject: [PATCH 016/497] [ticket/10431] Adjustments for IE7 Adjustments to buttons for IE7 PHPBB3-10431 --- phpBB/styles/prosilver/theme/buttons.css | 1 + 1 file changed, 1 insertion(+) diff --git a/phpBB/styles/prosilver/theme/buttons.css b/phpBB/styles/prosilver/theme/buttons.css index 2ba17a7717..544f4d3def 100644 --- a/phpBB/styles/prosilver/theme/buttons.css +++ b/phpBB/styles/prosilver/theme/buttons.css @@ -39,6 +39,7 @@ position: relative; text-decoration: none !important; outline-style: none !important; + *padding-right: 8px; } .buttons div span { display: none; } From 8e700f7e2bfecc514f8ed4ae8db43dd37703ca1e Mon Sep 17 00:00:00 2001 From: Vjacheslav Trushkin Date: Mon, 12 Nov 2012 11:03:30 +0100 Subject: [PATCH 017/497] [ticket/10431] Changed fonts for Linux Added backup fonts for Linux systems that do not have Verdana font PHPBB3-10431 --- phpBB/styles/prosilver/theme/buttons.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/styles/prosilver/theme/buttons.css b/phpBB/styles/prosilver/theme/buttons.css index 544f4d3def..02f973d0ff 100644 --- a/phpBB/styles/prosilver/theme/buttons.css +++ b/phpBB/styles/prosilver/theme/buttons.css @@ -34,7 +34,7 @@ -webkit-box-shadow: 0 0 0 1px #fff inset; text-shadow: 1px 1px 0 #fff, -1px -1px 1px rgba(188, 42, 77, 0.25); padding: 3px 22px 3px 8px; - font-family: "Futura-Medium", Verdana; + font-family: "Futura-Medium", Verdana, Arial, Helvetica; color: #bc2a4d !important; position: relative; text-decoration: none !important; From 0fd3bb170b95bc8c99329e47990e38c038629075 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Mon, 12 Nov 2012 11:10:25 +0100 Subject: [PATCH 018/497] [ticket/11015] Fixup some things from the big merge PHPBB3-11015 --- phpBB/includes/cache/driver/file.php | 2 +- phpBB/includes/cache/driver/interface.php | 2 +- phpBB/includes/cache/driver/memory.php | 2 +- phpBB/includes/cache/driver/null.php | 2 +- phpBB/includes/cache/service.php | 40 - phpBB/includes/db/dbal.php | 1049 --------------------- phpBB/includes/db/driver/driver.php | 8 +- phpBB/includes/db/driver/firebird.php | 16 +- phpBB/includes/db/driver/mssql.php | 16 +- phpBB/includes/db/driver/mssql_odbc.php | 16 +- phpBB/includes/db/driver/mssqlnative.php | 17 +- phpBB/includes/db/driver/mysql.php | 18 +- phpBB/includes/db/driver/mysqli.php | 18 +- phpBB/includes/db/driver/oracle.php | 18 +- phpBB/includes/db/driver/postgres.php | 18 +- phpBB/includes/db/driver/sqlite.php | 18 +- tests/di/create_container_test.php | 3 +- tests/mock/cache.php | 2 +- 18 files changed, 87 insertions(+), 1178 deletions(-) delete mode 100644 phpBB/includes/db/dbal.php diff --git a/phpBB/includes/cache/driver/file.php b/phpBB/includes/cache/driver/file.php index 23063a1a28..b20c0064ea 100644 --- a/phpBB/includes/cache/driver/file.php +++ b/phpBB/includes/cache/driver/file.php @@ -368,7 +368,7 @@ class phpbb_cache_driver_file extends phpbb_cache_driver_base /** * Save sql query */ - function sql_save($query, &$query_result, $ttl) + function sql_save($query, $query_result, $ttl) { global $db; diff --git a/phpBB/includes/cache/driver/interface.php b/phpBB/includes/cache/driver/interface.php index 313a2d4b31..847ba97262 100644 --- a/phpBB/includes/cache/driver/interface.php +++ b/phpBB/includes/cache/driver/interface.php @@ -75,7 +75,7 @@ interface phpbb_cache_driver_interface /** * Save sql query */ - public function sql_save($query, &$query_result, $ttl); + public function sql_save($query, $query_result, $ttl); /** * Ceck if a given sql query exist in cache diff --git a/phpBB/includes/cache/driver/memory.php b/phpBB/includes/cache/driver/memory.php index 623ae44144..98ac02b161 100644 --- a/phpBB/includes/cache/driver/memory.php +++ b/phpBB/includes/cache/driver/memory.php @@ -284,7 +284,7 @@ abstract class phpbb_cache_driver_memory extends phpbb_cache_driver_base /** * Save sql query */ - function sql_save($query, &$query_result, $ttl) + function sql_save($query, $query_result, $ttl) { global $db; diff --git a/phpBB/includes/cache/driver/null.php b/phpBB/includes/cache/driver/null.php index c143803d0e..df2c6c026f 100644 --- a/phpBB/includes/cache/driver/null.php +++ b/phpBB/includes/cache/driver/null.php @@ -107,7 +107,7 @@ class phpbb_cache_driver_null extends phpbb_cache_driver_base /** * Save sql query */ - function sql_save($query, &$query_result, $ttl) + function sql_save($query, $query_result, $ttl) { } diff --git a/phpBB/includes/cache/service.php b/phpBB/includes/cache/service.php index 7858e27a5c..e63ec6e33a 100644 --- a/phpBB/includes/cache/service.php +++ b/phpBB/includes/cache/service.php @@ -58,11 +58,6 @@ class phpbb_cache_service return call_user_func_array(array($this->driver, $method), $arguments); } - public function __get($var) - { - return $this->driver->$var; - } - /** * Obtain list of naughty words and build preg style replacement arrays for use by the * calling script @@ -413,39 +408,4 @@ class phpbb_cache_service return $hook_files; } - - public function sql_load() - { - return call_user_func_array(array($this->driver, __FUNCTION__), func_get_args()); - } - - public function sql_save($query, &$query_result, $ttl) - { - return call_user_func_array(array($this->driver, __FUNCTION__), array($query, &$query_result, $ttl)); - } - - public function sql_exists() - { - return call_user_func_array(array($this->driver, __FUNCTION__), func_get_args()); - } - - public function sql_fetchrow() - { - return call_user_func_array(array($this->driver, __FUNCTION__), func_get_args()); - } - - public function sql_fetchfield() - { - return call_user_func_array(array($this->driver, __FUNCTION__), func_get_args()); - } - - public function sql_rowseek() - { - return call_user_func_array(array($this->driver, __FUNCTION__), func_get_args()); - } - - public function sql_freeresult() - { - return call_user_func_array(array($this->driver, __FUNCTION__), func_get_args()); - } } diff --git a/phpBB/includes/db/dbal.php b/phpBB/includes/db/dbal.php deleted file mode 100644 index ef1dd7d14d..0000000000 --- a/phpBB/includes/db/dbal.php +++ /dev/null @@ -1,1049 +0,0 @@ -num_queries = array( - 'cached' => 0, - 'normal' => 0, - 'total' => 0, - ); - - // Fill default sql layer based on the class being called. - // This can be changed by the specified layer itself later if needed. - $this->sql_layer = substr(get_class($this), 5); - - // Do not change this please! This variable is used to easy the use of it - and is hardcoded. - $this->any_char = chr(0) . '%'; - $this->one_char = chr(0) . '_'; - } - - /** - * return on error or display error message - */ - function sql_return_on_error($fail = false) - { - $this->sql_error_triggered = false; - $this->sql_error_sql = ''; - - $this->return_on_error = $fail; - } - - /** - * Return number of sql queries and cached sql queries used - */ - function sql_num_queries($cached = false) - { - return ($cached) ? $this->num_queries['cached'] : $this->num_queries['normal']; - } - - /** - * Add to query count - */ - function sql_add_num_queries($cached = false) - { - $this->num_queries['cached'] += ($cached !== false) ? 1 : 0; - $this->num_queries['normal'] += ($cached !== false) ? 0 : 1; - $this->num_queries['total'] += 1; - } - - /** - * DBAL garbage collection, close sql connection - */ - function sql_close() - { - if (!$this->db_connect_id) - { - return false; - } - - if ($this->transaction) - { - do - { - $this->sql_transaction('commit'); - } - while ($this->transaction); - } - - foreach ($this->open_queries as $query_id) - { - $this->sql_freeresult($query_id); - } - - // Connection closed correctly. Set db_connect_id to false to prevent errors - if ($result = $this->_sql_close()) - { - $this->db_connect_id = false; - } - - return $result; - } - - /** - * Build LIMIT query - * Doing some validation here. - */ - function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - if (empty($query)) - { - return false; - } - - // Never use a negative total or offset - $total = ($total < 0) ? 0 : $total; - $offset = ($offset < 0) ? 0 : $offset; - - return $this->_sql_query_limit($query, $total, $offset, $cache_ttl); - } - - /** - * Fetch all rows - */ - function sql_fetchrowset($query_id = false) - { - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if ($query_id !== false) - { - $result = array(); - while ($row = $this->sql_fetchrow($query_id)) - { - $result[] = $row; - } - - return $result; - } - - return false; - } - - /** - * Seek to given row number - * rownum is zero-based - */ - function sql_rowseek($rownum, &$query_id) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if ($cache->sql_exists($query_id)) - { - return $cache->sql_rowseek($rownum, $query_id); - } - - if ($query_id === false) - { - return false; - } - - $this->sql_freeresult($query_id); - $query_id = $this->sql_query($this->last_query_text); - - if ($query_id === false) - { - return false; - } - - // We do not fetch the row for rownum == 0 because then the next resultset would be the second row - for ($i = 0; $i < $rownum; $i++) - { - if (!$this->sql_fetchrow($query_id)) - { - return false; - } - } - - return true; - } - - /** - * Fetch field - * if rownum is false, the current row is used, else it is pointing to the row (zero-based) - */ - function sql_fetchfield($field, $rownum = false, $query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if ($query_id !== false) - { - if ($rownum !== false) - { - $this->sql_rowseek($rownum, $query_id); - } - - if (!is_object($query_id) && $cache->sql_exists($query_id)) - { - return $cache->sql_fetchfield($query_id, $field); - } - - $row = $this->sql_fetchrow($query_id); - return (isset($row[$field])) ? $row[$field] : false; - } - - return false; - } - - /** - * Correctly adjust LIKE expression for special characters - * Some DBMS are handling them in a different way - * - * @param string $expression The expression to use. Every wildcard is escaped, except $this->any_char and $this->one_char - * @return string LIKE expression including the keyword! - */ - function sql_like_expression($expression) - { - $expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression); - $expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression); - - return $this->_sql_like_expression('LIKE \'' . $this->sql_escape($expression) . '\''); - } - - /** - * Build a case expression - * - * Note: The two statements action_true and action_false must have the same data type (int, vchar, ...) in the database! - * - * @param string $condition The condition which must be true, to use action_true rather then action_else - * @param string $action_true SQL expression that is used, if the condition is true - * @param string $action_else SQL expression that is used, if the condition is false, optional - * @return string CASE expression including the condition and statements - */ - public function sql_case($condition, $action_true, $action_false = false) - { - $sql_case = 'CASE WHEN ' . $condition; - $sql_case .= ' THEN ' . $action_true; - $sql_case .= ($action_false !== false) ? ' ELSE ' . $action_false : ''; - $sql_case .= ' END'; - return $sql_case; - } - - /** - * Build a concatenated expression - * - * @param string $expr1 Base SQL expression where we append the second one - * @param string $expr2 SQL expression that is appended to the first expression - * @return string Concatenated string - */ - public function sql_concatenate($expr1, $expr2) - { - return $expr1 . ' || ' . $expr2; - } - - /** - * Returns whether results of a query need to be buffered to run a transaction while iterating over them. - * - * @return bool Whether buffering is required. - */ - function sql_buffer_nested_transactions() - { - return false; - } - - /** - * SQL Transaction - * @access private - */ - function sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - // If we are within a transaction we will not open another one, but enclose the current one to not loose data (prevening auto commit) - if ($this->transaction) - { - $this->transactions++; - return true; - } - - $result = $this->_sql_transaction('begin'); - - if (!$result) - { - $this->sql_error(); - } - - $this->transaction = true; - break; - - case 'commit': - // If there was a previously opened transaction we do not commit yet... but count back the number of inner transactions - if ($this->transaction && $this->transactions) - { - $this->transactions--; - return true; - } - - // Check if there is a transaction (no transaction can happen if there was an error, with a combined rollback and error returning enabled) - // This implies we have transaction always set for autocommit db's - if (!$this->transaction) - { - return false; - } - - $result = $this->_sql_transaction('commit'); - - if (!$result) - { - $this->sql_error(); - } - - $this->transaction = false; - $this->transactions = 0; - break; - - case 'rollback': - $result = $this->_sql_transaction('rollback'); - $this->transaction = false; - $this->transactions = 0; - break; - - default: - $result = $this->_sql_transaction($status); - break; - } - - return $result; - } - - /** - * Build sql statement from array for insert/update/select statements - * - * Idea for this from Ikonboard - * Possible query values: INSERT, INSERT_SELECT, UPDATE, SELECT - * - */ - function sql_build_array($query, $assoc_ary = false) - { - if (!is_array($assoc_ary)) - { - return false; - } - - $fields = $values = array(); - - if ($query == 'INSERT' || $query == 'INSERT_SELECT') - { - foreach ($assoc_ary as $key => $var) - { - $fields[] = $key; - - if (is_array($var) && is_string($var[0])) - { - // This is used for INSERT_SELECT(s) - $values[] = $var[0]; - } - else - { - $values[] = $this->_sql_validate_value($var); - } - } - - $query = ($query == 'INSERT') ? ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')' : ' (' . implode(', ', $fields) . ') SELECT ' . implode(', ', $values) . ' '; - } - else if ($query == 'MULTI_INSERT') - { - trigger_error('The MULTI_INSERT query value is no longer supported. Please use sql_multi_insert() instead.', E_USER_ERROR); - } - else if ($query == 'UPDATE' || $query == 'SELECT') - { - $values = array(); - foreach ($assoc_ary as $key => $var) - { - $values[] = "$key = " . $this->_sql_validate_value($var); - } - $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); - } - - return $query; - } - - /** - * Build IN or NOT IN sql comparison string, uses <> or = on single element - * arrays to improve comparison speed - * - * @access public - * @param string $field name of the sql column that shall be compared - * @param array $array array of values that are allowed (IN) or not allowed (NOT IN) - * @param bool $negate true for NOT IN (), false for IN () (default) - * @param bool $allow_empty_set If true, allow $array to be empty, this function will return 1=1 or 1=0 then. Default to false. - */ - function sql_in_set($field, $array, $negate = false, $allow_empty_set = false) - { - if (!sizeof($array)) - { - if (!$allow_empty_set) - { - // Print the backtrace to help identifying the location of the problematic code - $this->sql_error('No values specified for SQL IN comparison'); - } - else - { - // NOT IN () actually means everything so use a tautology - if ($negate) - { - return '1=1'; - } - // IN () actually means nothing so use a contradiction - else - { - return '1=0'; - } - } - } - - if (!is_array($array)) - { - $array = array($array); - } - - if (sizeof($array) == 1) - { - @reset($array); - $var = current($array); - - return $field . ($negate ? ' <> ' : ' = ') . $this->_sql_validate_value($var); - } - else - { - return $field . ($negate ? ' NOT IN ' : ' IN ') . '(' . implode(', ', array_map(array($this, '_sql_validate_value'), $array)) . ')'; - } - } - - /** - * Run binary AND operator on DB column. - * Results in sql statement: "{$column_name} & (1 << {$bit}) {$compare}" - * - * @param string $column_name The column name to use - * @param int $bit The value to use for the AND operator, will be converted to (1 << $bit). Is used by options, using the number schema... 0, 1, 2...29 - * @param string $compare Any custom SQL code after the check (for example "= 0") - */ - function sql_bit_and($column_name, $bit, $compare = '') - { - if (method_exists($this, '_sql_bit_and')) - { - return $this->_sql_bit_and($column_name, $bit, $compare); - } - - return $column_name . ' & ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); - } - - /** - * Run binary OR operator on DB column. - * Results in sql statement: "{$column_name} | (1 << {$bit}) {$compare}" - * - * @param string $column_name The column name to use - * @param int $bit The value to use for the OR operator, will be converted to (1 << $bit). Is used by options, using the number schema... 0, 1, 2...29 - * @param string $compare Any custom SQL code after the check (for example "= 0") - */ - function sql_bit_or($column_name, $bit, $compare = '') - { - if (method_exists($this, '_sql_bit_or')) - { - return $this->_sql_bit_or($column_name, $bit, $compare); - } - - return $column_name . ' | ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); - } - - /** - * Returns SQL string to cast a string expression to an int. - * - * @param string $expression An expression evaluating to string - * @return string Expression returning an int - */ - function cast_expr_to_bigint($expression) - { - return $expression; - } - - /** - * Returns SQL string to cast an integer expression to a string. - * - * @param string $expression An expression evaluating to int - * @return string Expression returning a string - */ - function cast_expr_to_string($expression) - { - return $expression; - } - - /** - * Run LOWER() on DB column of type text (i.e. neither varchar nor char). - * - * @param string $column_name The column name to use - * - * @return string A SQL statement like "LOWER($column_name)" - */ - function sql_lower_text($column_name) - { - return "LOWER($column_name)"; - } - - /** - * Run more than one insert statement. - * - * @param string $table table name to run the statements on - * @param array &$sql_ary multi-dimensional array holding the statement data. - * - * @return bool false if no statements were executed. - * @access public - */ - function sql_multi_insert($table, &$sql_ary) - { - if (!sizeof($sql_ary)) - { - return false; - } - - if ($this->multi_insert) - { - $ary = array(); - foreach ($sql_ary as $id => $_sql_ary) - { - // If by accident the sql array is only one-dimensional we build a normal insert statement - if (!is_array($_sql_ary)) - { - return $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $sql_ary)); - } - - $values = array(); - foreach ($_sql_ary as $key => $var) - { - $values[] = $this->_sql_validate_value($var); - } - $ary[] = '(' . implode(', ', $values) . ')'; - } - - return $this->sql_query('INSERT INTO ' . $table . ' ' . ' (' . implode(', ', array_keys($sql_ary[0])) . ') VALUES ' . implode(', ', $ary)); - } - else - { - foreach ($sql_ary as $ary) - { - if (!is_array($ary)) - { - return false; - } - - $result = $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary)); - - if (!$result) - { - return false; - } - } - } - - return true; - } - - /** - * Function for validating values - * @access private - */ - function _sql_validate_value($var) - { - if (is_null($var)) - { - return 'NULL'; - } - else if (is_string($var)) - { - return "'" . $this->sql_escape($var) . "'"; - } - else - { - return (is_bool($var)) ? intval($var) : $var; - } - } - - /** - * Build sql statement from array for select and select distinct statements - * - * Possible query values: SELECT, SELECT_DISTINCT - */ - function sql_build_query($query, $array) - { - $sql = ''; - switch ($query) - { - case 'SELECT': - case 'SELECT_DISTINCT'; - - $sql = str_replace('_', ' ', $query) . ' ' . $array['SELECT'] . ' FROM '; - - // Build table array. We also build an alias array for later checks. - $table_array = $aliases = array(); - $used_multi_alias = false; - - foreach ($array['FROM'] as $table_name => $alias) - { - if (is_array($alias)) - { - $used_multi_alias = true; - - foreach ($alias as $multi_alias) - { - $table_array[] = $table_name . ' ' . $multi_alias; - $aliases[] = $multi_alias; - } - } - else - { - $table_array[] = $table_name . ' ' . $alias; - $aliases[] = $alias; - } - } - - // We run the following code to determine if we need to re-order the table array. ;) - // The reason for this is that for multi-aliased tables (two equal tables) in the FROM statement the last table need to match the first comparison. - // DBMS who rely on this: Oracle, PostgreSQL and MSSQL. For all other DBMS it makes absolutely no difference in which order the table is. - if (!empty($array['LEFT_JOIN']) && sizeof($array['FROM']) > 1 && $used_multi_alias !== false) - { - // Take first LEFT JOIN - $join = current($array['LEFT_JOIN']); - - // Determine the table used there (even if there are more than one used, we only want to have one - preg_match('/(' . implode('|', $aliases) . ')\.[^\s]+/U', str_replace(array('(', ')', 'AND', 'OR', ' '), '', $join['ON']), $matches); - - // If there is a first join match, we need to make sure the table order is correct - if (!empty($matches[1])) - { - $first_join_match = trim($matches[1]); - $table_array = $last = array(); - - foreach ($array['FROM'] as $table_name => $alias) - { - if (is_array($alias)) - { - foreach ($alias as $multi_alias) - { - ($multi_alias === $first_join_match) ? $last[] = $table_name . ' ' . $multi_alias : $table_array[] = $table_name . ' ' . $multi_alias; - } - } - else - { - ($alias === $first_join_match) ? $last[] = $table_name . ' ' . $alias : $table_array[] = $table_name . ' ' . $alias; - } - } - - $table_array = array_merge($table_array, $last); - } - } - - $sql .= $this->_sql_custom_build('FROM', implode(' CROSS JOIN ', $table_array)); - - if (!empty($array['LEFT_JOIN'])) - { - foreach ($array['LEFT_JOIN'] as $join) - { - $sql .= ' LEFT JOIN ' . key($join['FROM']) . ' ' . current($join['FROM']) . ' ON (' . $join['ON'] . ')'; - } - } - - if (!empty($array['WHERE'])) - { - $sql .= ' WHERE ' . $this->_sql_custom_build('WHERE', $array['WHERE']); - } - - if (!empty($array['GROUP_BY'])) - { - $sql .= ' GROUP BY ' . $array['GROUP_BY']; - } - - if (!empty($array['ORDER_BY'])) - { - $sql .= ' ORDER BY ' . $array['ORDER_BY']; - } - - break; - } - - return $sql; - } - - /** - * display sql error page - */ - function sql_error($sql = '') - { - global $auth, $user, $config; - - // Set var to retrieve errored status - $this->sql_error_triggered = true; - $this->sql_error_sql = $sql; - - $this->sql_error_returned = $this->_sql_error(); - - if (!$this->return_on_error) - { - $message = 'SQL ERROR [ ' . $this->sql_layer . ' ]

' . $this->sql_error_returned['message'] . ' [' . $this->sql_error_returned['code'] . ']'; - - // Show complete SQL error and path to administrators only - // Additionally show complete error on installation or if extended debug mode is enabled - // The DEBUG constant is for development only! - if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || defined('DEBUG')) - { - $message .= ($sql) ? '

SQL

' . htmlspecialchars($sql) : ''; - } - else - { - // If error occurs in initiating the session we need to use a pre-defined language string - // This could happen if the connection could not be established for example (then we are not able to grab the default language) - if (!isset($user->lang['SQL_ERROR_OCCURRED'])) - { - $message .= '

An sql error occurred while fetching this page. Please contact an administrator if this problem persists.'; - } - else - { - if (!empty($config['board_contact'])) - { - $message .= '

' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '
', ''); - } - else - { - $message .= '

' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', ''); - } - } - } - - if ($this->transaction) - { - $this->sql_transaction('rollback'); - } - - if (strlen($message) > 1024) - { - // We need to define $msg_long_text here to circumvent text stripping. - global $msg_long_text; - $msg_long_text = $message; - - trigger_error(false, E_USER_ERROR); - } - - trigger_error($message, E_USER_ERROR); - } - - if ($this->transaction) - { - $this->sql_transaction('rollback'); - } - - return $this->sql_error_returned; - } - - /** - * Explain queries - */ - function sql_report($mode, $query = '') - { - global $cache, $starttime, $phpbb_root_path, $user; - global $request; - - if (is_object($request) && !$request->variable('explain', false)) - { - return false; - } - - if (!$query && $this->query_hold != '') - { - $query = $this->query_hold; - } - - switch ($mode) - { - case 'display': - if (!empty($cache)) - { - $cache->unload(); - } - $this->sql_close(); - - $mtime = explode(' ', microtime()); - $totaltime = $mtime[0] + $mtime[1] - $starttime; - - echo ' - - - - SQL Report - - - -
- -
-
-
- -
-

SQL Report

-
-

Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries['normal']} queries" . (($this->num_queries['cached']) ? " + {$this->num_queries['cached']} " . (($this->num_queries['cached'] == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '

- -

Time spent on ' . $this->sql_layer . ' queries: ' . round($this->sql_time, 5) . 's | Time spent on PHP: ' . round($totaltime - $this->sql_time, 5) . 's

- -

- ' . $this->sql_report . ' -
- -
-
-
- -
- - '; - - exit_handler(); - - break; - - case 'stop': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $this->sql_report .= ' - - - - - - - - - - - - -
Query #' . $this->num_queries['total'] . '
- - ' . $this->html_hold . ' - -

- '; - - if ($this->query_result) - { - if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)) - { - $this->sql_report .= 'Affected rows: ' . $this->sql_affectedrows($this->query_result) . ' | '; - } - $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: ' . sprintf('%.5f', $endtime - $this->curtime) . 's'; - } - else - { - $error = $this->sql_error(); - $this->sql_report .= 'FAILED - ' . $this->sql_layer . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); - } - - $this->sql_report .= '



'; - - $this->sql_time += $endtime - $this->curtime; - break; - - case 'start': - $this->query_hold = $query; - $this->html_hold = ''; - - $this->_sql_report($mode, $query); - - $this->curtime = explode(' ', microtime()); - $this->curtime = $this->curtime[0] + $this->curtime[1]; - - break; - - case 'add_select_row': - - $html_table = func_get_arg(2); - $row = func_get_arg(3); - - if (!$html_table && sizeof($row)) - { - $html_table = true; - $this->html_hold .= ''; - - foreach (array_keys($row) as $val) - { - $this->html_hold .= ''; - } - $this->html_hold .= ''; - } - $this->html_hold .= ''; - - $class = 'row1'; - foreach (array_values($row) as $val) - { - $class = ($class == 'row1') ? 'row2' : 'row1'; - $this->html_hold .= ''; - } - $this->html_hold .= ''; - - return $html_table; - - break; - - case 'fromcache': - - $this->_sql_report($mode, $query); - - break; - - case 'record_fromcache': - - $endtime = func_get_arg(2); - $splittime = func_get_arg(3); - - $time_cache = $endtime - $this->curtime; - $time_db = $splittime - $endtime; - $color = ($time_db > $time_cache) ? 'green' : 'red'; - - $this->sql_report .= '
' . (($val) ? ucwords(str_replace('_', ' ', $val)) : ' ') . '
' . (($val) ? $val : ' ') . '
'; - $this->sql_report .= '
Query results obtained from the cache
'; - $this->sql_report .= '

'; - $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: ' . sprintf('%.5f', ($time_cache)) . 's | Elapsed [db]: ' . sprintf('%.5f', $time_db) . 's



'; - - // Pad the start time to not interfere with page timing - $starttime += $time_db; - - break; - - default: - - $this->_sql_report($mode, $query); - - break; - } - - return true; - } - - /** - * Gets the estimated number of rows in a specified table. - * - * @param string $table_name Table name - * - * @return string Number of rows in $table_name. - * Prefixed with ~ if estimated (otherwise exact). - * - * @access public - */ - function get_estimated_row_count($table_name) - { - return $this->get_row_count($table_name); - } - - /** - * Gets the exact number of rows in a specified table. - * - * @param string $table_name Table name - * - * @return string Exact number of rows in $table_name. - * - * @access public - */ - function get_row_count($table_name) - { - $sql = 'SELECT COUNT(*) AS rows_total - FROM ' . $this->sql_escape($table_name); - $result = $this->sql_query($sql); - $rows_total = $this->sql_fetchfield('rows_total'); - $this->sql_freeresult($result); - - return $rows_total; - } -} - -/** -* This variable holds the class name to use later -*/ -$sql_db = (!empty($dbms)) ? 'dbal_' . basename($dbms) : 'dbal'; diff --git a/phpBB/includes/db/driver/driver.php b/phpBB/includes/db/driver/driver.php index 9692ee71b9..4b831d2f79 100644 --- a/phpBB/includes/db/driver/driver.php +++ b/phpBB/includes/db/driver/driver.php @@ -206,7 +206,7 @@ class phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_rowseek($rownum, $query_id); } @@ -256,7 +256,7 @@ class phpbb_db_driver $this->sql_rowseek($rownum, $query_id); } - if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) + if (!is_object($query_id) && $cache->sql_exists($query_id)) { return $cache->sql_fetchfield($query_id, $field); } @@ -766,8 +766,8 @@ class phpbb_db_driver // Show complete SQL error and path to administrators only // Additionally show complete error on installation or if extended debug mode is enabled - // The DEBUG_EXTRA constant is for development only! - if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || defined('DEBUG_EXTRA')) + // The DEBUG constant is for development only! + if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || defined('DEBUG')) { $message .= ($sql) ? '

SQL

' . htmlspecialchars($sql) : ''; } diff --git a/phpBB/includes/db/driver/firebird.php b/phpBB/includes/db/driver/firebird.php index c793e0a51f..a55175c345 100644 --- a/phpBB/includes/db/driver/firebird.php +++ b/phpBB/includes/db/driver/firebird.php @@ -148,13 +148,13 @@ class phpbb_db_driver_firebird extends phpbb_db_driver global $cache; // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) + if (defined('DEBUG')) { $this->sql_report('start', $query); } $this->last_query_text = $query; - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; + $this->query_result = ($cache_ttl) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); if ($this->query_result === false) @@ -249,7 +249,7 @@ class phpbb_db_driver_firebird extends phpbb_db_driver $this->sql_error($query); } - if (defined('DEBUG_EXTRA')) + if (defined('DEBUG')) { $this->sql_report('stop', $query); } @@ -267,17 +267,17 @@ class phpbb_db_driver_firebird extends phpbb_db_driver } } - if ($cache_ttl && method_exists($cache, 'sql_save')) + if ($cache_ttl) { $this->open_queries[(int) $this->query_result] = $this->query_result; - $cache->sql_save($query, $this->query_result, $cache_ttl); + $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { $this->open_queries[(int) $this->query_result] = $this->query_result; } } - else if (defined('DEBUG_EXTRA')) + else if (defined('DEBUG')) { $this->sql_report('fromcache', $query); } @@ -330,7 +330,7 @@ class phpbb_db_driver_firebird extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_fetchrow($query_id); } @@ -396,7 +396,7 @@ class phpbb_db_driver_firebird extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_freeresult($query_id); } diff --git a/phpBB/includes/db/driver/mssql.php b/phpBB/includes/db/driver/mssql.php index e68738f918..04bb75f5ce 100644 --- a/phpBB/includes/db/driver/mssql.php +++ b/phpBB/includes/db/driver/mssql.php @@ -137,12 +137,12 @@ class phpbb_db_driver_mssql extends phpbb_db_driver global $cache; // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) + if (defined('DEBUG')) { $this->sql_report('start', $query); } - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; + $this->query_result = ($cache_ttl) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); if ($this->query_result === false) @@ -152,7 +152,7 @@ class phpbb_db_driver_mssql extends phpbb_db_driver $this->sql_error($query); } - if (defined('DEBUG_EXTRA')) + if (defined('DEBUG')) { $this->sql_report('stop', $query); } @@ -160,14 +160,14 @@ class phpbb_db_driver_mssql extends phpbb_db_driver if ($cache_ttl && method_exists($cache, 'sql_save')) { $this->open_queries[(int) $this->query_result] = $this->query_result; - $cache->sql_save($query, $this->query_result, $cache_ttl); + $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { $this->open_queries[(int) $this->query_result] = $this->query_result; } } - else if (defined('DEBUG_EXTRA')) + else if (defined('DEBUG')) { $this->sql_report('fromcache', $query); } @@ -232,7 +232,7 @@ class phpbb_db_driver_mssql extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_fetchrow($query_id); } @@ -269,7 +269,7 @@ class phpbb_db_driver_mssql extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_rowseek($rownum, $query_id); } @@ -308,7 +308,7 @@ class phpbb_db_driver_mssql extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_freeresult($query_id); } diff --git a/phpBB/includes/db/driver/mssql_odbc.php b/phpBB/includes/db/driver/mssql_odbc.php index 7b35ce3d11..d1f31a6554 100644 --- a/phpBB/includes/db/driver/mssql_odbc.php +++ b/phpBB/includes/db/driver/mssql_odbc.php @@ -155,13 +155,13 @@ class phpbb_db_driver_mssql_odbc extends phpbb_db_driver global $cache; // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) + if (defined('DEBUG')) { $this->sql_report('start', $query); } $this->last_query_text = $query; - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; + $this->query_result = ($cache_ttl) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); if ($this->query_result === false) @@ -171,22 +171,22 @@ class phpbb_db_driver_mssql_odbc extends phpbb_db_driver $this->sql_error($query); } - if (defined('DEBUG_EXTRA')) + if (defined('DEBUG')) { $this->sql_report('stop', $query); } - if ($cache_ttl && method_exists($cache, 'sql_save')) + if ($cache_ttl) { $this->open_queries[(int) $this->query_result] = $this->query_result; - $cache->sql_save($query, $this->query_result, $cache_ttl); + $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { $this->open_queries[(int) $this->query_result] = $this->query_result; } } - else if (defined('DEBUG_EXTRA')) + else if (defined('DEBUG')) { $this->sql_report('fromcache', $query); } @@ -252,7 +252,7 @@ class phpbb_db_driver_mssql_odbc extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_fetchrow($query_id); } @@ -293,7 +293,7 @@ class phpbb_db_driver_mssql_odbc extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_freeresult($query_id); } diff --git a/phpBB/includes/db/driver/mssqlnative.php b/phpBB/includes/db/driver/mssqlnative.php index 99b9d7975a..67a019f5a5 100644 --- a/phpBB/includes/db/driver/mssqlnative.php +++ b/phpBB/includes/db/driver/mssqlnative.php @@ -216,7 +216,6 @@ class phpbb_db_driver_mssqlnative extends phpbb_db_driver $this->server = $sqlserver . (($port) ? $port_delimiter . $port : ''); //connect to database - error_reporting(E_ALL); $this->db_connect_id = sqlsrv_connect($this->server, array( 'Database' => $this->dbname, 'UID' => $this->user, @@ -310,13 +309,13 @@ class phpbb_db_driver_mssqlnative extends phpbb_db_driver global $cache; // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) + if (defined('DEBUG')) { $this->sql_report('start', $query); } $this->last_query_text = $query; - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; + $this->query_result = ($cache_ttl) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); if ($this->query_result === false) @@ -328,22 +327,22 @@ class phpbb_db_driver_mssqlnative extends phpbb_db_driver // reset options for next query $this->query_options = array(); - if (defined('DEBUG_EXTRA')) + if (defined('DEBUG')) { $this->sql_report('stop', $query); } - if ($cache_ttl && method_exists($cache, 'sql_save')) + if ($cache_ttl) { $this->open_queries[(int) $this->query_result] = $this->query_result; - $cache->sql_save($query, $this->query_result, $cache_ttl); + $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { $this->open_queries[(int) $this->query_result] = $this->query_result; } } - else if (defined('DEBUG_EXTRA')) + else if (defined('DEBUG')) { $this->sql_report('fromcache', $query); } @@ -416,7 +415,7 @@ class phpbb_db_driver_mssqlnative extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_fetchrow($query_id); } @@ -476,7 +475,7 @@ class phpbb_db_driver_mssqlnative extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_freeresult($query_id); } diff --git a/phpBB/includes/db/driver/mysql.php b/phpBB/includes/db/driver/mysql.php index 987691341a..f8c2be2366 100644 --- a/phpBB/includes/db/driver/mysql.php +++ b/phpBB/includes/db/driver/mysql.php @@ -165,12 +165,12 @@ class phpbb_db_driver_mysql extends phpbb_db_driver global $cache; // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) + if (defined('DEBUG')) { $this->sql_report('start', $query); } - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; + $this->query_result = ($cache_ttl) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); if ($this->query_result === false) @@ -180,22 +180,22 @@ class phpbb_db_driver_mysql extends phpbb_db_driver $this->sql_error($query); } - if (defined('DEBUG_EXTRA')) + if (defined('DEBUG')) { $this->sql_report('stop', $query); } - if ($cache_ttl && method_exists($cache, 'sql_save')) + if ($cache_ttl) { $this->open_queries[(int) $this->query_result] = $this->query_result; - $cache->sql_save($query, $this->query_result, $cache_ttl); + $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { $this->open_queries[(int) $this->query_result] = $this->query_result; } } - else if (defined('DEBUG_EXTRA')) + else if (defined('DEBUG')) { $this->sql_report('fromcache', $query); } @@ -247,7 +247,7 @@ class phpbb_db_driver_mysql extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_fetchrow($query_id); } @@ -268,7 +268,7 @@ class phpbb_db_driver_mysql extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_rowseek($rownum, $query_id); } @@ -296,7 +296,7 @@ class phpbb_db_driver_mysql extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_freeresult($query_id); } diff --git a/phpBB/includes/db/driver/mysqli.php b/phpBB/includes/db/driver/mysqli.php index c473c7fe99..0cc3eb359a 100644 --- a/phpBB/includes/db/driver/mysqli.php +++ b/phpBB/includes/db/driver/mysqli.php @@ -172,12 +172,12 @@ class phpbb_db_driver_mysqli extends phpbb_db_driver global $cache; // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) + if (defined('DEBUG')) { $this->sql_report('start', $query); } - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; + $this->query_result = ($cache_ttl) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); if ($this->query_result === false) @@ -187,17 +187,17 @@ class phpbb_db_driver_mysqli extends phpbb_db_driver $this->sql_error($query); } - if (defined('DEBUG_EXTRA')) + if (defined('DEBUG')) { $this->sql_report('stop', $query); } - if ($cache_ttl && method_exists($cache, 'sql_save')) + if ($cache_ttl) { - $cache->sql_save($query, $this->query_result, $cache_ttl); + $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl); } } - else if (defined('DEBUG_EXTRA')) + else if (defined('DEBUG')) { $this->sql_report('fromcache', $query); } @@ -249,7 +249,7 @@ class phpbb_db_driver_mysqli extends phpbb_db_driver $query_id = $this->query_result; } - if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) + if (!is_object($query_id) && $cache->sql_exists($query_id)) { return $cache->sql_fetchrow($query_id); } @@ -276,7 +276,7 @@ class phpbb_db_driver_mysqli extends phpbb_db_driver $query_id = $this->query_result; } - if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) + if (!is_object($query_id) && $cache->sql_exists($query_id)) { return $cache->sql_rowseek($rownum, $query_id); } @@ -304,7 +304,7 @@ class phpbb_db_driver_mysqli extends phpbb_db_driver $query_id = $this->query_result; } - if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) + if (!is_object($query_id) && $cache->sql_exists($query_id)) { return $cache->sql_freeresult($query_id); } diff --git a/phpBB/includes/db/driver/oracle.php b/phpBB/includes/db/driver/oracle.php index 25803e57bd..d8474694e3 100644 --- a/phpBB/includes/db/driver/oracle.php +++ b/phpBB/includes/db/driver/oracle.php @@ -234,13 +234,13 @@ class phpbb_db_driver_oracle extends phpbb_db_driver global $cache; // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) + if (defined('DEBUG')) { $this->sql_report('start', $query); } $this->last_query_text = $query; - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; + $this->query_result = ($cache_ttl) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); if ($this->query_result === false) @@ -411,22 +411,22 @@ class phpbb_db_driver_oracle extends phpbb_db_driver } } - if (defined('DEBUG_EXTRA')) + if (defined('DEBUG')) { $this->sql_report('stop', $query); } - if ($cache_ttl && method_exists($cache, 'sql_save')) + if ($cache_ttl) { $this->open_queries[(int) $this->query_result] = $this->query_result; - $cache->sql_save($query, $this->query_result, $cache_ttl); + $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { $this->open_queries[(int) $this->query_result] = $this->query_result; } } - else if (defined('DEBUG_EXTRA')) + else if (defined('DEBUG')) { $this->sql_report('fromcache', $query); } @@ -471,7 +471,7 @@ class phpbb_db_driver_oracle extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_fetchrow($query_id); } @@ -523,7 +523,7 @@ class phpbb_db_driver_oracle extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_rowseek($rownum, $query_id); } @@ -592,7 +592,7 @@ class phpbb_db_driver_oracle extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_freeresult($query_id); } diff --git a/phpBB/includes/db/driver/postgres.php b/phpBB/includes/db/driver/postgres.php index 3f54936d23..147ecd04d9 100644 --- a/phpBB/includes/db/driver/postgres.php +++ b/phpBB/includes/db/driver/postgres.php @@ -187,13 +187,13 @@ class phpbb_db_driver_postgres extends phpbb_db_driver global $cache; // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) + if (defined('DEBUG')) { $this->sql_report('start', $query); } $this->last_query_text = $query; - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; + $this->query_result = ($cache_ttl) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); if ($this->query_result === false) @@ -203,22 +203,22 @@ class phpbb_db_driver_postgres extends phpbb_db_driver $this->sql_error($query); } - if (defined('DEBUG_EXTRA')) + if (defined('DEBUG')) { $this->sql_report('stop', $query); } - if ($cache_ttl && method_exists($cache, 'sql_save')) + if ($cache_ttl) { $this->open_queries[(int) $this->query_result] = $this->query_result; - $cache->sql_save($query, $this->query_result, $cache_ttl); + $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { $this->open_queries[(int) $this->query_result] = $this->query_result; } } - else if (defined('DEBUG_EXTRA')) + else if (defined('DEBUG')) { $this->sql_report('fromcache', $query); } @@ -278,7 +278,7 @@ class phpbb_db_driver_postgres extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_fetchrow($query_id); } @@ -299,7 +299,7 @@ class phpbb_db_driver_postgres extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_rowseek($rownum, $query_id); } @@ -348,7 +348,7 @@ class phpbb_db_driver_postgres extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_freeresult($query_id); } diff --git a/phpBB/includes/db/driver/sqlite.php b/phpBB/includes/db/driver/sqlite.php index 363f26da2b..0b09fa758d 100644 --- a/phpBB/includes/db/driver/sqlite.php +++ b/phpBB/includes/db/driver/sqlite.php @@ -110,12 +110,12 @@ class phpbb_db_driver_sqlite extends phpbb_db_driver global $cache; // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) + if (defined('DEBUG')) { $this->sql_report('start', $query); } - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; + $this->query_result = ($cache_ttl) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); if ($this->query_result === false) @@ -125,22 +125,22 @@ class phpbb_db_driver_sqlite extends phpbb_db_driver $this->sql_error($query); } - if (defined('DEBUG_EXTRA')) + if (defined('DEBUG')) { $this->sql_report('stop', $query); } - if ($cache_ttl && method_exists($cache, 'sql_save')) + if ($cache_ttl) { $this->open_queries[(int) $this->query_result] = $this->query_result; - $cache->sql_save($query, $this->query_result, $cache_ttl); + $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { $this->open_queries[(int) $this->query_result] = $this->query_result; } } - else if (defined('DEBUG_EXTRA')) + else if (defined('DEBUG')) { $this->sql_report('fromcache', $query); } @@ -191,7 +191,7 @@ class phpbb_db_driver_sqlite extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_fetchrow($query_id); } @@ -212,7 +212,7 @@ class phpbb_db_driver_sqlite extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_rowseek($rownum, $query_id); } @@ -240,7 +240,7 @@ class phpbb_db_driver_sqlite extends phpbb_db_driver $query_id = $this->query_result; } - if (isset($cache->sql_rowset[$query_id])) + if ($cache->sql_exists($query_id)) { return $cache->sql_freeresult($query_id); } diff --git a/tests/di/create_container_test.php b/tests/di/create_container_test.php index c2b8a0fc0b..6de8803df9 100644 --- a/tests/di/create_container_test.php +++ b/tests/di/create_container_test.php @@ -9,7 +9,6 @@ require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; require_once dirname(__FILE__) . '/../../phpBB/includes/functions_container.php'; -require_once dirname(__FILE__) . '/../../phpBB/includes/db/dbal.php'; class phpbb_di_container_test extends phpbb_test_case { @@ -52,7 +51,7 @@ class phpbb_di_container_test extends phpbb_test_case } } -class dbal_container_mock extends dbal +class phpbb_db_driver_container_mock extends phpbb_db_driver { public function sql_connect() { diff --git a/tests/mock/cache.php b/tests/mock/cache.php index c6d08afef0..b64c92ea89 100644 --- a/tests/mock/cache.php +++ b/tests/mock/cache.php @@ -121,7 +121,7 @@ class phpbb_mock_cache implements phpbb_cache_driver_interface public function sql_load($query) { } - public function sql_save($query, &$query_result, $ttl) + public function sql_save($query, $query_result, $ttl) { } public function sql_exists($query_id) From f8841b7f521684eab6fda7fd3487540fa4560249 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Thu, 15 Nov 2012 03:09:57 +0100 Subject: [PATCH 019/497] [ticket/11015] Fix line endings of phpbb_db_driver to LF PHPBB3-11015 --- phpBB/includes/db/driver/driver.php | 2042 +++++++++++++-------------- 1 file changed, 1021 insertions(+), 1021 deletions(-) diff --git a/phpBB/includes/db/driver/driver.php b/phpBB/includes/db/driver/driver.php index 4b831d2f79..49bfcb8007 100644 --- a/phpBB/includes/db/driver/driver.php +++ b/phpBB/includes/db/driver/driver.php @@ -12,7 +12,7 @@ */ if (!defined('IN_PHPBB')) { - exit; + exit; } /** @@ -21,1024 +21,1024 @@ if (!defined('IN_PHPBB')) */ class phpbb_db_driver { - var $db_connect_id; - var $query_result; - var $return_on_error = false; - var $transaction = false; - var $sql_time = 0; - var $num_queries = array(); - var $open_queries = array(); - - var $curtime = 0; - var $query_hold = ''; - var $html_hold = ''; - var $sql_report = ''; - - var $persistency = false; - var $user = ''; - var $server = ''; - var $dbname = ''; - - // Set to true if error triggered - var $sql_error_triggered = false; - - // Holding the last sql query on sql error - var $sql_error_sql = ''; - // Holding the error information - only populated if sql_error_triggered is set - var $sql_error_returned = array(); - - // Holding transaction count - var $transactions = 0; - - // Supports multi inserts? - var $multi_insert = false; - - /** - * Current sql layer - */ - var $sql_layer = ''; - - /** - * Wildcards for matching any (%) or exactly one (_) character within LIKE expressions - */ - var $any_char; - var $one_char; - - /** - * Exact version of the DBAL, directly queried - */ - var $sql_server_version = false; - - /** - * Constructor - */ - function __construct() - { - $this->num_queries = array( - 'cached' => 0, - 'normal' => 0, - 'total' => 0, - ); - - // Fill default sql layer based on the class being called. - // This can be changed by the specified layer itself later if needed. - $this->sql_layer = substr(get_class($this), strlen('phpbb_db_driver_')); - - // Do not change this please! This variable is used to easy the use of it - and is hardcoded. - $this->any_char = chr(0) . '%'; - $this->one_char = chr(0) . '_'; - } - - /** - * return on error or display error message - */ - function sql_return_on_error($fail = false) - { - $this->sql_error_triggered = false; - $this->sql_error_sql = ''; - - $this->return_on_error = $fail; - } - - /** - * Return number of sql queries and cached sql queries used - */ - function sql_num_queries($cached = false) - { - return ($cached) ? $this->num_queries['cached'] : $this->num_queries['normal']; - } - - /** - * Add to query count - */ - function sql_add_num_queries($cached = false) - { - $this->num_queries['cached'] += ($cached !== false) ? 1 : 0; - $this->num_queries['normal'] += ($cached !== false) ? 0 : 1; - $this->num_queries['total'] += 1; - } - - /** - * DBAL garbage collection, close sql connection - */ - function sql_close() - { - if (!$this->db_connect_id) - { - return false; - } - - if ($this->transaction) - { - do - { - $this->sql_transaction('commit'); - } - while ($this->transaction); - } - - foreach ($this->open_queries as $query_id) - { - $this->sql_freeresult($query_id); - } - - // Connection closed correctly. Set db_connect_id to false to prevent errors - if ($result = $this->_sql_close()) - { - $this->db_connect_id = false; - } - - return $result; - } - - /** - * Build LIMIT query - * Doing some validation here. - */ - function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - if (empty($query)) - { - return false; - } - - // Never use a negative total or offset - $total = ($total < 0) ? 0 : $total; - $offset = ($offset < 0) ? 0 : $offset; - - return $this->_sql_query_limit($query, $total, $offset, $cache_ttl); - } - - /** - * Fetch all rows - */ - function sql_fetchrowset($query_id = false) - { - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if ($query_id !== false) - { - $result = array(); - while ($row = $this->sql_fetchrow($query_id)) - { - $result[] = $row; - } - - return $result; - } - - return false; - } - - /** - * Seek to given row number - * rownum is zero-based - */ - function sql_rowseek($rownum, &$query_id) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if ($cache->sql_exists($query_id)) - { - return $cache->sql_rowseek($rownum, $query_id); - } - - if ($query_id === false) - { - return false; - } - - $this->sql_freeresult($query_id); - $query_id = $this->sql_query($this->last_query_text); - - if ($query_id === false) - { - return false; - } - - // We do not fetch the row for rownum == 0 because then the next resultset would be the second row - for ($i = 0; $i < $rownum; $i++) - { - if (!$this->sql_fetchrow($query_id)) - { - return false; - } - } - - return true; - } - - /** - * Fetch field - * if rownum is false, the current row is used, else it is pointing to the row (zero-based) - */ - function sql_fetchfield($field, $rownum = false, $query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if ($query_id !== false) - { - if ($rownum !== false) - { - $this->sql_rowseek($rownum, $query_id); - } - - if (!is_object($query_id) && $cache->sql_exists($query_id)) - { - return $cache->sql_fetchfield($query_id, $field); - } - - $row = $this->sql_fetchrow($query_id); - return (isset($row[$field])) ? $row[$field] : false; - } - - return false; - } - - /** - * Correctly adjust LIKE expression for special characters - * Some DBMS are handling them in a different way - * - * @param string $expression The expression to use. Every wildcard is escaped, except $this->any_char and $this->one_char - * @return string LIKE expression including the keyword! - */ - function sql_like_expression($expression) - { - $expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression); - $expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression); - - return $this->_sql_like_expression('LIKE \'' . $this->sql_escape($expression) . '\''); - } - - /** - * Build a case expression - * - * Note: The two statements action_true and action_false must have the same data type (int, vchar, ...) in the database! - * - * @param string $condition The condition which must be true, to use action_true rather then action_else - * @param string $action_true SQL expression that is used, if the condition is true - * @param string $action_else SQL expression that is used, if the condition is false, optional - * @return string CASE expression including the condition and statements - */ - public function sql_case($condition, $action_true, $action_false = false) - { - $sql_case = 'CASE WHEN ' . $condition; - $sql_case .= ' THEN ' . $action_true; - $sql_case .= ($action_false !== false) ? ' ELSE ' . $action_false : ''; - $sql_case .= ' END'; - return $sql_case; - } - - /** - * Build a concatenated expression - * - * @param string $expr1 Base SQL expression where we append the second one - * @param string $expr2 SQL expression that is appended to the first expression - * @return string Concatenated string - */ - public function sql_concatenate($expr1, $expr2) - { - return $expr1 . ' || ' . $expr2; - } - - /** - * Returns whether results of a query need to be buffered to run a transaction while iterating over them. - * - * @return bool Whether buffering is required. - */ - function sql_buffer_nested_transactions() - { - return false; - } - - /** - * SQL Transaction - * @access private - */ - function sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - // If we are within a transaction we will not open another one, but enclose the current one to not loose data (prevening auto commit) - if ($this->transaction) - { - $this->transactions++; - return true; - } - - $result = $this->_sql_transaction('begin'); - - if (!$result) - { - $this->sql_error(); - } - - $this->transaction = true; - break; - - case 'commit': - // If there was a previously opened transaction we do not commit yet... but count back the number of inner transactions - if ($this->transaction && $this->transactions) - { - $this->transactions--; - return true; - } - - // Check if there is a transaction (no transaction can happen if there was an error, with a combined rollback and error returning enabled) - // This implies we have transaction always set for autocommit db's - if (!$this->transaction) - { - return false; - } - - $result = $this->_sql_transaction('commit'); - - if (!$result) - { - $this->sql_error(); - } - - $this->transaction = false; - $this->transactions = 0; - break; - - case 'rollback': - $result = $this->_sql_transaction('rollback'); - $this->transaction = false; - $this->transactions = 0; - break; - - default: - $result = $this->_sql_transaction($status); - break; - } - - return $result; - } - - /** - * Build sql statement from array for insert/update/select statements - * - * Idea for this from Ikonboard - * Possible query values: INSERT, INSERT_SELECT, UPDATE, SELECT - * - */ - function sql_build_array($query, $assoc_ary = false) - { - if (!is_array($assoc_ary)) - { - return false; - } - - $fields = $values = array(); - - if ($query == 'INSERT' || $query == 'INSERT_SELECT') - { - foreach ($assoc_ary as $key => $var) - { - $fields[] = $key; - - if (is_array($var) && is_string($var[0])) - { - // This is used for INSERT_SELECT(s) - $values[] = $var[0]; - } - else - { - $values[] = $this->_sql_validate_value($var); - } - } - - $query = ($query == 'INSERT') ? ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')' : ' (' . implode(', ', $fields) . ') SELECT ' . implode(', ', $values) . ' '; - } - else if ($query == 'MULTI_INSERT') - { - trigger_error('The MULTI_INSERT query value is no longer supported. Please use sql_multi_insert() instead.', E_USER_ERROR); - } - else if ($query == 'UPDATE' || $query == 'SELECT') - { - $values = array(); - foreach ($assoc_ary as $key => $var) - { - $values[] = "$key = " . $this->_sql_validate_value($var); - } - $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); - } - - return $query; - } - - /** - * Build IN or NOT IN sql comparison string, uses <> or = on single element - * arrays to improve comparison speed - * - * @access public - * @param string $field name of the sql column that shall be compared - * @param array $array array of values that are allowed (IN) or not allowed (NOT IN) - * @param bool $negate true for NOT IN (), false for IN () (default) - * @param bool $allow_empty_set If true, allow $array to be empty, this function will return 1=1 or 1=0 then. Default to false. - */ - function sql_in_set($field, $array, $negate = false, $allow_empty_set = false) - { - if (!sizeof($array)) - { - if (!$allow_empty_set) - { - // Print the backtrace to help identifying the location of the problematic code - $this->sql_error('No values specified for SQL IN comparison'); - } - else - { - // NOT IN () actually means everything so use a tautology - if ($negate) - { - return '1=1'; - } - // IN () actually means nothing so use a contradiction - else - { - return '1=0'; - } - } - } - - if (!is_array($array)) - { - $array = array($array); - } - - if (sizeof($array) == 1) - { - @reset($array); - $var = current($array); - - return $field . ($negate ? ' <> ' : ' = ') . $this->_sql_validate_value($var); - } - else - { - return $field . ($negate ? ' NOT IN ' : ' IN ') . '(' . implode(', ', array_map(array($this, '_sql_validate_value'), $array)) . ')'; - } - } - - /** - * Run binary AND operator on DB column. - * Results in sql statement: "{$column_name} & (1 << {$bit}) {$compare}" - * - * @param string $column_name The column name to use - * @param int $bit The value to use for the AND operator, will be converted to (1 << $bit). Is used by options, using the number schema... 0, 1, 2...29 - * @param string $compare Any custom SQL code after the check (for example "= 0") - */ - function sql_bit_and($column_name, $bit, $compare = '') - { - if (method_exists($this, '_sql_bit_and')) - { - return $this->_sql_bit_and($column_name, $bit, $compare); - } - - return $column_name . ' & ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); - } - - /** - * Run binary OR operator on DB column. - * Results in sql statement: "{$column_name} | (1 << {$bit}) {$compare}" - * - * @param string $column_name The column name to use - * @param int $bit The value to use for the OR operator, will be converted to (1 << $bit). Is used by options, using the number schema... 0, 1, 2...29 - * @param string $compare Any custom SQL code after the check (for example "= 0") - */ - function sql_bit_or($column_name, $bit, $compare = '') - { - if (method_exists($this, '_sql_bit_or')) - { - return $this->_sql_bit_or($column_name, $bit, $compare); - } - - return $column_name . ' | ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); - } - - /** - * Returns SQL string to cast a string expression to an int. - * - * @param string $expression An expression evaluating to string - * @return string Expression returning an int - */ - function cast_expr_to_bigint($expression) - { - return $expression; - } - - /** - * Returns SQL string to cast an integer expression to a string. - * - * @param string $expression An expression evaluating to int - * @return string Expression returning a string - */ - function cast_expr_to_string($expression) - { - return $expression; - } - - /** - * Run LOWER() on DB column of type text (i.e. neither varchar nor char). - * - * @param string $column_name The column name to use - * - * @return string A SQL statement like "LOWER($column_name)" - */ - function sql_lower_text($column_name) - { - return "LOWER($column_name)"; - } - - /** - * Run more than one insert statement. - * - * @param string $table table name to run the statements on - * @param array &$sql_ary multi-dimensional array holding the statement data. - * - * @return bool false if no statements were executed. - * @access public - */ - function sql_multi_insert($table, &$sql_ary) - { - if (!sizeof($sql_ary)) - { - return false; - } - - if ($this->multi_insert) - { - $ary = array(); - foreach ($sql_ary as $id => $_sql_ary) - { - // If by accident the sql array is only one-dimensional we build a normal insert statement - if (!is_array($_sql_ary)) - { - return $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $sql_ary)); - } - - $values = array(); - foreach ($_sql_ary as $key => $var) - { - $values[] = $this->_sql_validate_value($var); - } - $ary[] = '(' . implode(', ', $values) . ')'; - } - - return $this->sql_query('INSERT INTO ' . $table . ' ' . ' (' . implode(', ', array_keys($sql_ary[0])) . ') VALUES ' . implode(', ', $ary)); - } - else - { - foreach ($sql_ary as $ary) - { - if (!is_array($ary)) - { - return false; - } - - $result = $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary)); - - if (!$result) - { - return false; - } - } - } - - return true; - } - - /** - * Function for validating values - * @access private - */ - function _sql_validate_value($var) - { - if (is_null($var)) - { - return 'NULL'; - } - else if (is_string($var)) - { - return "'" . $this->sql_escape($var) . "'"; - } - else - { - return (is_bool($var)) ? intval($var) : $var; - } - } - - /** - * Build sql statement from array for select and select distinct statements - * - * Possible query values: SELECT, SELECT_DISTINCT - */ - function sql_build_query($query, $array) - { - $sql = ''; - switch ($query) - { - case 'SELECT': - case 'SELECT_DISTINCT'; - - $sql = str_replace('_', ' ', $query) . ' ' . $array['SELECT'] . ' FROM '; - - // Build table array. We also build an alias array for later checks. - $table_array = $aliases = array(); - $used_multi_alias = false; - - foreach ($array['FROM'] as $table_name => $alias) - { - if (is_array($alias)) - { - $used_multi_alias = true; - - foreach ($alias as $multi_alias) - { - $table_array[] = $table_name . ' ' . $multi_alias; - $aliases[] = $multi_alias; - } - } - else - { - $table_array[] = $table_name . ' ' . $alias; - $aliases[] = $alias; - } - } - - // We run the following code to determine if we need to re-order the table array. ;) - // The reason for this is that for multi-aliased tables (two equal tables) in the FROM statement the last table need to match the first comparison. - // DBMS who rely on this: Oracle, PostgreSQL and MSSQL. For all other DBMS it makes absolutely no difference in which order the table is. - if (!empty($array['LEFT_JOIN']) && sizeof($array['FROM']) > 1 && $used_multi_alias !== false) - { - // Take first LEFT JOIN - $join = current($array['LEFT_JOIN']); - - // Determine the table used there (even if there are more than one used, we only want to have one - preg_match('/(' . implode('|', $aliases) . ')\.[^\s]+/U', str_replace(array('(', ')', 'AND', 'OR', ' '), '', $join['ON']), $matches); - - // If there is a first join match, we need to make sure the table order is correct - if (!empty($matches[1])) - { - $first_join_match = trim($matches[1]); - $table_array = $last = array(); - - foreach ($array['FROM'] as $table_name => $alias) - { - if (is_array($alias)) - { - foreach ($alias as $multi_alias) - { - ($multi_alias === $first_join_match) ? $last[] = $table_name . ' ' . $multi_alias : $table_array[] = $table_name . ' ' . $multi_alias; - } - } - else - { - ($alias === $first_join_match) ? $last[] = $table_name . ' ' . $alias : $table_array[] = $table_name . ' ' . $alias; - } - } - - $table_array = array_merge($table_array, $last); - } - } - - $sql .= $this->_sql_custom_build('FROM', implode(' CROSS JOIN ', $table_array)); - - if (!empty($array['LEFT_JOIN'])) - { - foreach ($array['LEFT_JOIN'] as $join) - { - $sql .= ' LEFT JOIN ' . key($join['FROM']) . ' ' . current($join['FROM']) . ' ON (' . $join['ON'] . ')'; - } - } - - if (!empty($array['WHERE'])) - { - $sql .= ' WHERE ' . $this->_sql_custom_build('WHERE', $array['WHERE']); - } - - if (!empty($array['GROUP_BY'])) - { - $sql .= ' GROUP BY ' . $array['GROUP_BY']; - } - - if (!empty($array['ORDER_BY'])) - { - $sql .= ' ORDER BY ' . $array['ORDER_BY']; - } - - break; - } - - return $sql; - } - - /** - * display sql error page - */ - function sql_error($sql = '') - { - global $auth, $user, $config; - - // Set var to retrieve errored status - $this->sql_error_triggered = true; - $this->sql_error_sql = $sql; - - $this->sql_error_returned = $this->_sql_error(); - - if (!$this->return_on_error) - { - $message = 'SQL ERROR [ ' . $this->sql_layer . ' ]

' . $this->sql_error_returned['message'] . ' [' . $this->sql_error_returned['code'] . ']'; - - // Show complete SQL error and path to administrators only - // Additionally show complete error on installation or if extended debug mode is enabled - // The DEBUG constant is for development only! - if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || defined('DEBUG')) - { - $message .= ($sql) ? '

SQL

' . htmlspecialchars($sql) : ''; - } - else - { - // If error occurs in initiating the session we need to use a pre-defined language string - // This could happen if the connection could not be established for example (then we are not able to grab the default language) - if (!isset($user->lang['SQL_ERROR_OCCURRED'])) - { - $message .= '

An sql error occurred while fetching this page. Please contact an administrator if this problem persists.'; - } - else - { - if (!empty($config['board_contact'])) - { - $message .= '

' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', ''); - } - else - { - $message .= '

' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', ''); - } - } - } - - if ($this->transaction) - { - $this->sql_transaction('rollback'); - } - - if (strlen($message) > 1024) - { - // We need to define $msg_long_text here to circumvent text stripping. - global $msg_long_text; - $msg_long_text = $message; - - trigger_error(false, E_USER_ERROR); - } - - trigger_error($message, E_USER_ERROR); - } - - if ($this->transaction) - { - $this->sql_transaction('rollback'); - } - - return $this->sql_error_returned; - } - - /** - * Explain queries - */ - function sql_report($mode, $query = '') - { - global $cache, $starttime, $phpbb_root_path, $user; - global $request; - - if (is_object($request) && !$request->variable('explain', false)) - { - return false; - } - - if (!$query && $this->query_hold != '') - { - $query = $this->query_hold; - } - - switch ($mode) - { - case 'display': - if (!empty($cache)) - { - $cache->unload(); - } - $this->sql_close(); - - $mtime = explode(' ', microtime()); - $totaltime = $mtime[0] + $mtime[1] - $starttime; - - echo ' - - - - SQL Report - - - -
- -
-
-
- -
-

SQL Report

-
-

Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries['normal']} queries" . (($this->num_queries['cached']) ? " + {$this->num_queries['cached']} " . (($this->num_queries['cached'] == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '

- -

Time spent on ' . $this->sql_layer . ' queries: ' . round($this->sql_time, 5) . 's | Time spent on PHP: ' . round($totaltime - $this->sql_time, 5) . 's

- -

- ' . $this->sql_report . ' -
- -
-
-
- -
- - '; - - exit_handler(); - - break; - - case 'stop': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $this->sql_report .= ' - - - - - - - - - - - - -
Query #' . $this->num_queries['total'] . '
- - ' . $this->html_hold . ' - -

- '; - - if ($this->query_result) - { - if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)) - { - $this->sql_report .= 'Affected rows: ' . $this->sql_affectedrows($this->query_result) . ' | '; - } - $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: ' . sprintf('%.5f', $endtime - $this->curtime) . 's'; - } - else - { - $error = $this->sql_error(); - $this->sql_report .= 'FAILED - ' . $this->sql_layer . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); - } - - $this->sql_report .= '



'; - - $this->sql_time += $endtime - $this->curtime; - break; - - case 'start': - $this->query_hold = $query; - $this->html_hold = ''; - - $this->_sql_report($mode, $query); - - $this->curtime = explode(' ', microtime()); - $this->curtime = $this->curtime[0] + $this->curtime[1]; - - break; - - case 'add_select_row': - - $html_table = func_get_arg(2); - $row = func_get_arg(3); - - if (!$html_table && sizeof($row)) - { - $html_table = true; - $this->html_hold .= ''; - - foreach (array_keys($row) as $val) - { - $this->html_hold .= ''; - } - $this->html_hold .= ''; - } - $this->html_hold .= ''; - - $class = 'row1'; - foreach (array_values($row) as $val) - { - $class = ($class == 'row1') ? 'row2' : 'row1'; - $this->html_hold .= ''; - } - $this->html_hold .= ''; - - return $html_table; - - break; - - case 'fromcache': - - $this->_sql_report($mode, $query); - - break; - - case 'record_fromcache': - - $endtime = func_get_arg(2); - $splittime = func_get_arg(3); - - $time_cache = $endtime - $this->curtime; - $time_db = $splittime - $endtime; - $color = ($time_db > $time_cache) ? 'green' : 'red'; - - $this->sql_report .= '
' . (($val) ? ucwords(str_replace('_', ' ', $val)) : ' ') . '
' . (($val) ? $val : ' ') . '
'; - $this->sql_report .= '
Query results obtained from the cache
'; - $this->sql_report .= '

'; - $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: ' . sprintf('%.5f', ($time_cache)) . 's | Elapsed [db]: ' . sprintf('%.5f', $time_db) . 's



'; - - // Pad the start time to not interfere with page timing - $starttime += $time_db; - - break; - - default: - - $this->_sql_report($mode, $query); - - break; - } - - return true; - } - - /** - * Gets the estimated number of rows in a specified table. - * - * @param string $table_name Table name - * - * @return string Number of rows in $table_name. - * Prefixed with ~ if estimated (otherwise exact). - * - * @access public - */ - function get_estimated_row_count($table_name) - { - return $this->get_row_count($table_name); - } - - /** - * Gets the exact number of rows in a specified table. - * - * @param string $table_name Table name - * - * @return string Exact number of rows in $table_name. - * - * @access public - */ - function get_row_count($table_name) - { - $sql = 'SELECT COUNT(*) AS rows_total - FROM ' . $this->sql_escape($table_name); - $result = $this->sql_query($sql); - $rows_total = $this->sql_fetchfield('rows_total'); - $this->sql_freeresult($result); - - return $rows_total; - } + var $db_connect_id; + var $query_result; + var $return_on_error = false; + var $transaction = false; + var $sql_time = 0; + var $num_queries = array(); + var $open_queries = array(); + + var $curtime = 0; + var $query_hold = ''; + var $html_hold = ''; + var $sql_report = ''; + + var $persistency = false; + var $user = ''; + var $server = ''; + var $dbname = ''; + + // Set to true if error triggered + var $sql_error_triggered = false; + + // Holding the last sql query on sql error + var $sql_error_sql = ''; + // Holding the error information - only populated if sql_error_triggered is set + var $sql_error_returned = array(); + + // Holding transaction count + var $transactions = 0; + + // Supports multi inserts? + var $multi_insert = false; + + /** + * Current sql layer + */ + var $sql_layer = ''; + + /** + * Wildcards for matching any (%) or exactly one (_) character within LIKE expressions + */ + var $any_char; + var $one_char; + + /** + * Exact version of the DBAL, directly queried + */ + var $sql_server_version = false; + + /** + * Constructor + */ + function __construct() + { + $this->num_queries = array( + 'cached' => 0, + 'normal' => 0, + 'total' => 0, + ); + + // Fill default sql layer based on the class being called. + // This can be changed by the specified layer itself later if needed. + $this->sql_layer = substr(get_class($this), strlen('phpbb_db_driver_')); + + // Do not change this please! This variable is used to easy the use of it - and is hardcoded. + $this->any_char = chr(0) . '%'; + $this->one_char = chr(0) . '_'; + } + + /** + * return on error or display error message + */ + function sql_return_on_error($fail = false) + { + $this->sql_error_triggered = false; + $this->sql_error_sql = ''; + + $this->return_on_error = $fail; + } + + /** + * Return number of sql queries and cached sql queries used + */ + function sql_num_queries($cached = false) + { + return ($cached) ? $this->num_queries['cached'] : $this->num_queries['normal']; + } + + /** + * Add to query count + */ + function sql_add_num_queries($cached = false) + { + $this->num_queries['cached'] += ($cached !== false) ? 1 : 0; + $this->num_queries['normal'] += ($cached !== false) ? 0 : 1; + $this->num_queries['total'] += 1; + } + + /** + * DBAL garbage collection, close sql connection + */ + function sql_close() + { + if (!$this->db_connect_id) + { + return false; + } + + if ($this->transaction) + { + do + { + $this->sql_transaction('commit'); + } + while ($this->transaction); + } + + foreach ($this->open_queries as $query_id) + { + $this->sql_freeresult($query_id); + } + + // Connection closed correctly. Set db_connect_id to false to prevent errors + if ($result = $this->_sql_close()) + { + $this->db_connect_id = false; + } + + return $result; + } + + /** + * Build LIMIT query + * Doing some validation here. + */ + function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) + { + if (empty($query)) + { + return false; + } + + // Never use a negative total or offset + $total = ($total < 0) ? 0 : $total; + $offset = ($offset < 0) ? 0 : $offset; + + return $this->_sql_query_limit($query, $total, $offset, $cache_ttl); + } + + /** + * Fetch all rows + */ + function sql_fetchrowset($query_id = false) + { + if ($query_id === false) + { + $query_id = $this->query_result; + } + + if ($query_id !== false) + { + $result = array(); + while ($row = $this->sql_fetchrow($query_id)) + { + $result[] = $row; + } + + return $result; + } + + return false; + } + + /** + * Seek to given row number + * rownum is zero-based + */ + function sql_rowseek($rownum, &$query_id) + { + global $cache; + + if ($query_id === false) + { + $query_id = $this->query_result; + } + + if ($cache->sql_exists($query_id)) + { + return $cache->sql_rowseek($rownum, $query_id); + } + + if ($query_id === false) + { + return false; + } + + $this->sql_freeresult($query_id); + $query_id = $this->sql_query($this->last_query_text); + + if ($query_id === false) + { + return false; + } + + // We do not fetch the row for rownum == 0 because then the next resultset would be the second row + for ($i = 0; $i < $rownum; $i++) + { + if (!$this->sql_fetchrow($query_id)) + { + return false; + } + } + + return true; + } + + /** + * Fetch field + * if rownum is false, the current row is used, else it is pointing to the row (zero-based) + */ + function sql_fetchfield($field, $rownum = false, $query_id = false) + { + global $cache; + + if ($query_id === false) + { + $query_id = $this->query_result; + } + + if ($query_id !== false) + { + if ($rownum !== false) + { + $this->sql_rowseek($rownum, $query_id); + } + + if (!is_object($query_id) && $cache->sql_exists($query_id)) + { + return $cache->sql_fetchfield($query_id, $field); + } + + $row = $this->sql_fetchrow($query_id); + return (isset($row[$field])) ? $row[$field] : false; + } + + return false; + } + + /** + * Correctly adjust LIKE expression for special characters + * Some DBMS are handling them in a different way + * + * @param string $expression The expression to use. Every wildcard is escaped, except $this->any_char and $this->one_char + * @return string LIKE expression including the keyword! + */ + function sql_like_expression($expression) + { + $expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression); + $expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression); + + return $this->_sql_like_expression('LIKE \'' . $this->sql_escape($expression) . '\''); + } + + /** + * Build a case expression + * + * Note: The two statements action_true and action_false must have the same data type (int, vchar, ...) in the database! + * + * @param string $condition The condition which must be true, to use action_true rather then action_else + * @param string $action_true SQL expression that is used, if the condition is true + * @param string $action_else SQL expression that is used, if the condition is false, optional + * @return string CASE expression including the condition and statements + */ + public function sql_case($condition, $action_true, $action_false = false) + { + $sql_case = 'CASE WHEN ' . $condition; + $sql_case .= ' THEN ' . $action_true; + $sql_case .= ($action_false !== false) ? ' ELSE ' . $action_false : ''; + $sql_case .= ' END'; + return $sql_case; + } + + /** + * Build a concatenated expression + * + * @param string $expr1 Base SQL expression where we append the second one + * @param string $expr2 SQL expression that is appended to the first expression + * @return string Concatenated string + */ + public function sql_concatenate($expr1, $expr2) + { + return $expr1 . ' || ' . $expr2; + } + + /** + * Returns whether results of a query need to be buffered to run a transaction while iterating over them. + * + * @return bool Whether buffering is required. + */ + function sql_buffer_nested_transactions() + { + return false; + } + + /** + * SQL Transaction + * @access private + */ + function sql_transaction($status = 'begin') + { + switch ($status) + { + case 'begin': + // If we are within a transaction we will not open another one, but enclose the current one to not loose data (prevening auto commit) + if ($this->transaction) + { + $this->transactions++; + return true; + } + + $result = $this->_sql_transaction('begin'); + + if (!$result) + { + $this->sql_error(); + } + + $this->transaction = true; + break; + + case 'commit': + // If there was a previously opened transaction we do not commit yet... but count back the number of inner transactions + if ($this->transaction && $this->transactions) + { + $this->transactions--; + return true; + } + + // Check if there is a transaction (no transaction can happen if there was an error, with a combined rollback and error returning enabled) + // This implies we have transaction always set for autocommit db's + if (!$this->transaction) + { + return false; + } + + $result = $this->_sql_transaction('commit'); + + if (!$result) + { + $this->sql_error(); + } + + $this->transaction = false; + $this->transactions = 0; + break; + + case 'rollback': + $result = $this->_sql_transaction('rollback'); + $this->transaction = false; + $this->transactions = 0; + break; + + default: + $result = $this->_sql_transaction($status); + break; + } + + return $result; + } + + /** + * Build sql statement from array for insert/update/select statements + * + * Idea for this from Ikonboard + * Possible query values: INSERT, INSERT_SELECT, UPDATE, SELECT + * + */ + function sql_build_array($query, $assoc_ary = false) + { + if (!is_array($assoc_ary)) + { + return false; + } + + $fields = $values = array(); + + if ($query == 'INSERT' || $query == 'INSERT_SELECT') + { + foreach ($assoc_ary as $key => $var) + { + $fields[] = $key; + + if (is_array($var) && is_string($var[0])) + { + // This is used for INSERT_SELECT(s) + $values[] = $var[0]; + } + else + { + $values[] = $this->_sql_validate_value($var); + } + } + + $query = ($query == 'INSERT') ? ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')' : ' (' . implode(', ', $fields) . ') SELECT ' . implode(', ', $values) . ' '; + } + else if ($query == 'MULTI_INSERT') + { + trigger_error('The MULTI_INSERT query value is no longer supported. Please use sql_multi_insert() instead.', E_USER_ERROR); + } + else if ($query == 'UPDATE' || $query == 'SELECT') + { + $values = array(); + foreach ($assoc_ary as $key => $var) + { + $values[] = "$key = " . $this->_sql_validate_value($var); + } + $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); + } + + return $query; + } + + /** + * Build IN or NOT IN sql comparison string, uses <> or = on single element + * arrays to improve comparison speed + * + * @access public + * @param string $field name of the sql column that shall be compared + * @param array $array array of values that are allowed (IN) or not allowed (NOT IN) + * @param bool $negate true for NOT IN (), false for IN () (default) + * @param bool $allow_empty_set If true, allow $array to be empty, this function will return 1=1 or 1=0 then. Default to false. + */ + function sql_in_set($field, $array, $negate = false, $allow_empty_set = false) + { + if (!sizeof($array)) + { + if (!$allow_empty_set) + { + // Print the backtrace to help identifying the location of the problematic code + $this->sql_error('No values specified for SQL IN comparison'); + } + else + { + // NOT IN () actually means everything so use a tautology + if ($negate) + { + return '1=1'; + } + // IN () actually means nothing so use a contradiction + else + { + return '1=0'; + } + } + } + + if (!is_array($array)) + { + $array = array($array); + } + + if (sizeof($array) == 1) + { + @reset($array); + $var = current($array); + + return $field . ($negate ? ' <> ' : ' = ') . $this->_sql_validate_value($var); + } + else + { + return $field . ($negate ? ' NOT IN ' : ' IN ') . '(' . implode(', ', array_map(array($this, '_sql_validate_value'), $array)) . ')'; + } + } + + /** + * Run binary AND operator on DB column. + * Results in sql statement: "{$column_name} & (1 << {$bit}) {$compare}" + * + * @param string $column_name The column name to use + * @param int $bit The value to use for the AND operator, will be converted to (1 << $bit). Is used by options, using the number schema... 0, 1, 2...29 + * @param string $compare Any custom SQL code after the check (for example "= 0") + */ + function sql_bit_and($column_name, $bit, $compare = '') + { + if (method_exists($this, '_sql_bit_and')) + { + return $this->_sql_bit_and($column_name, $bit, $compare); + } + + return $column_name . ' & ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); + } + + /** + * Run binary OR operator on DB column. + * Results in sql statement: "{$column_name} | (1 << {$bit}) {$compare}" + * + * @param string $column_name The column name to use + * @param int $bit The value to use for the OR operator, will be converted to (1 << $bit). Is used by options, using the number schema... 0, 1, 2...29 + * @param string $compare Any custom SQL code after the check (for example "= 0") + */ + function sql_bit_or($column_name, $bit, $compare = '') + { + if (method_exists($this, '_sql_bit_or')) + { + return $this->_sql_bit_or($column_name, $bit, $compare); + } + + return $column_name . ' | ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); + } + + /** + * Returns SQL string to cast a string expression to an int. + * + * @param string $expression An expression evaluating to string + * @return string Expression returning an int + */ + function cast_expr_to_bigint($expression) + { + return $expression; + } + + /** + * Returns SQL string to cast an integer expression to a string. + * + * @param string $expression An expression evaluating to int + * @return string Expression returning a string + */ + function cast_expr_to_string($expression) + { + return $expression; + } + + /** + * Run LOWER() on DB column of type text (i.e. neither varchar nor char). + * + * @param string $column_name The column name to use + * + * @return string A SQL statement like "LOWER($column_name)" + */ + function sql_lower_text($column_name) + { + return "LOWER($column_name)"; + } + + /** + * Run more than one insert statement. + * + * @param string $table table name to run the statements on + * @param array &$sql_ary multi-dimensional array holding the statement data. + * + * @return bool false if no statements were executed. + * @access public + */ + function sql_multi_insert($table, &$sql_ary) + { + if (!sizeof($sql_ary)) + { + return false; + } + + if ($this->multi_insert) + { + $ary = array(); + foreach ($sql_ary as $id => $_sql_ary) + { + // If by accident the sql array is only one-dimensional we build a normal insert statement + if (!is_array($_sql_ary)) + { + return $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $sql_ary)); + } + + $values = array(); + foreach ($_sql_ary as $key => $var) + { + $values[] = $this->_sql_validate_value($var); + } + $ary[] = '(' . implode(', ', $values) . ')'; + } + + return $this->sql_query('INSERT INTO ' . $table . ' ' . ' (' . implode(', ', array_keys($sql_ary[0])) . ') VALUES ' . implode(', ', $ary)); + } + else + { + foreach ($sql_ary as $ary) + { + if (!is_array($ary)) + { + return false; + } + + $result = $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary)); + + if (!$result) + { + return false; + } + } + } + + return true; + } + + /** + * Function for validating values + * @access private + */ + function _sql_validate_value($var) + { + if (is_null($var)) + { + return 'NULL'; + } + else if (is_string($var)) + { + return "'" . $this->sql_escape($var) . "'"; + } + else + { + return (is_bool($var)) ? intval($var) : $var; + } + } + + /** + * Build sql statement from array for select and select distinct statements + * + * Possible query values: SELECT, SELECT_DISTINCT + */ + function sql_build_query($query, $array) + { + $sql = ''; + switch ($query) + { + case 'SELECT': + case 'SELECT_DISTINCT'; + + $sql = str_replace('_', ' ', $query) . ' ' . $array['SELECT'] . ' FROM '; + + // Build table array. We also build an alias array for later checks. + $table_array = $aliases = array(); + $used_multi_alias = false; + + foreach ($array['FROM'] as $table_name => $alias) + { + if (is_array($alias)) + { + $used_multi_alias = true; + + foreach ($alias as $multi_alias) + { + $table_array[] = $table_name . ' ' . $multi_alias; + $aliases[] = $multi_alias; + } + } + else + { + $table_array[] = $table_name . ' ' . $alias; + $aliases[] = $alias; + } + } + + // We run the following code to determine if we need to re-order the table array. ;) + // The reason for this is that for multi-aliased tables (two equal tables) in the FROM statement the last table need to match the first comparison. + // DBMS who rely on this: Oracle, PostgreSQL and MSSQL. For all other DBMS it makes absolutely no difference in which order the table is. + if (!empty($array['LEFT_JOIN']) && sizeof($array['FROM']) > 1 && $used_multi_alias !== false) + { + // Take first LEFT JOIN + $join = current($array['LEFT_JOIN']); + + // Determine the table used there (even if there are more than one used, we only want to have one + preg_match('/(' . implode('|', $aliases) . ')\.[^\s]+/U', str_replace(array('(', ')', 'AND', 'OR', ' '), '', $join['ON']), $matches); + + // If there is a first join match, we need to make sure the table order is correct + if (!empty($matches[1])) + { + $first_join_match = trim($matches[1]); + $table_array = $last = array(); + + foreach ($array['FROM'] as $table_name => $alias) + { + if (is_array($alias)) + { + foreach ($alias as $multi_alias) + { + ($multi_alias === $first_join_match) ? $last[] = $table_name . ' ' . $multi_alias : $table_array[] = $table_name . ' ' . $multi_alias; + } + } + else + { + ($alias === $first_join_match) ? $last[] = $table_name . ' ' . $alias : $table_array[] = $table_name . ' ' . $alias; + } + } + + $table_array = array_merge($table_array, $last); + } + } + + $sql .= $this->_sql_custom_build('FROM', implode(' CROSS JOIN ', $table_array)); + + if (!empty($array['LEFT_JOIN'])) + { + foreach ($array['LEFT_JOIN'] as $join) + { + $sql .= ' LEFT JOIN ' . key($join['FROM']) . ' ' . current($join['FROM']) . ' ON (' . $join['ON'] . ')'; + } + } + + if (!empty($array['WHERE'])) + { + $sql .= ' WHERE ' . $this->_sql_custom_build('WHERE', $array['WHERE']); + } + + if (!empty($array['GROUP_BY'])) + { + $sql .= ' GROUP BY ' . $array['GROUP_BY']; + } + + if (!empty($array['ORDER_BY'])) + { + $sql .= ' ORDER BY ' . $array['ORDER_BY']; + } + + break; + } + + return $sql; + } + + /** + * display sql error page + */ + function sql_error($sql = '') + { + global $auth, $user, $config; + + // Set var to retrieve errored status + $this->sql_error_triggered = true; + $this->sql_error_sql = $sql; + + $this->sql_error_returned = $this->_sql_error(); + + if (!$this->return_on_error) + { + $message = 'SQL ERROR [ ' . $this->sql_layer . ' ]

' . $this->sql_error_returned['message'] . ' [' . $this->sql_error_returned['code'] . ']'; + + // Show complete SQL error and path to administrators only + // Additionally show complete error on installation or if extended debug mode is enabled + // The DEBUG constant is for development only! + if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || defined('DEBUG')) + { + $message .= ($sql) ? '

SQL

' . htmlspecialchars($sql) : ''; + } + else + { + // If error occurs in initiating the session we need to use a pre-defined language string + // This could happen if the connection could not be established for example (then we are not able to grab the default language) + if (!isset($user->lang['SQL_ERROR_OCCURRED'])) + { + $message .= '

An sql error occurred while fetching this page. Please contact an administrator if this problem persists.'; + } + else + { + if (!empty($config['board_contact'])) + { + $message .= '

' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', ''); + } + else + { + $message .= '

' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', ''); + } + } + } + + if ($this->transaction) + { + $this->sql_transaction('rollback'); + } + + if (strlen($message) > 1024) + { + // We need to define $msg_long_text here to circumvent text stripping. + global $msg_long_text; + $msg_long_text = $message; + + trigger_error(false, E_USER_ERROR); + } + + trigger_error($message, E_USER_ERROR); + } + + if ($this->transaction) + { + $this->sql_transaction('rollback'); + } + + return $this->sql_error_returned; + } + + /** + * Explain queries + */ + function sql_report($mode, $query = '') + { + global $cache, $starttime, $phpbb_root_path, $user; + global $request; + + if (is_object($request) && !$request->variable('explain', false)) + { + return false; + } + + if (!$query && $this->query_hold != '') + { + $query = $this->query_hold; + } + + switch ($mode) + { + case 'display': + if (!empty($cache)) + { + $cache->unload(); + } + $this->sql_close(); + + $mtime = explode(' ', microtime()); + $totaltime = $mtime[0] + $mtime[1] - $starttime; + + echo ' + + + + SQL Report + + + +
+ +
+
+
+ +
+

SQL Report

+
+

Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries['normal']} queries" . (($this->num_queries['cached']) ? " + {$this->num_queries['cached']} " . (($this->num_queries['cached'] == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '

+ +

Time spent on ' . $this->sql_layer . ' queries: ' . round($this->sql_time, 5) . 's | Time spent on PHP: ' . round($totaltime - $this->sql_time, 5) . 's

+ +

+ ' . $this->sql_report . ' +
+ +
+
+
+ +
+ + '; + + exit_handler(); + + break; + + case 'stop': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $this->sql_report .= ' + + + + + + + + + + + + +
Query #' . $this->num_queries['total'] . '
+ + ' . $this->html_hold . ' + +

+ '; + + if ($this->query_result) + { + if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)) + { + $this->sql_report .= 'Affected rows: ' . $this->sql_affectedrows($this->query_result) . ' | '; + } + $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: ' . sprintf('%.5f', $endtime - $this->curtime) . 's'; + } + else + { + $error = $this->sql_error(); + $this->sql_report .= 'FAILED - ' . $this->sql_layer . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); + } + + $this->sql_report .= '



'; + + $this->sql_time += $endtime - $this->curtime; + break; + + case 'start': + $this->query_hold = $query; + $this->html_hold = ''; + + $this->_sql_report($mode, $query); + + $this->curtime = explode(' ', microtime()); + $this->curtime = $this->curtime[0] + $this->curtime[1]; + + break; + + case 'add_select_row': + + $html_table = func_get_arg(2); + $row = func_get_arg(3); + + if (!$html_table && sizeof($row)) + { + $html_table = true; + $this->html_hold .= ''; + + foreach (array_keys($row) as $val) + { + $this->html_hold .= ''; + } + $this->html_hold .= ''; + } + $this->html_hold .= ''; + + $class = 'row1'; + foreach (array_values($row) as $val) + { + $class = ($class == 'row1') ? 'row2' : 'row1'; + $this->html_hold .= ''; + } + $this->html_hold .= ''; + + return $html_table; + + break; + + case 'fromcache': + + $this->_sql_report($mode, $query); + + break; + + case 'record_fromcache': + + $endtime = func_get_arg(2); + $splittime = func_get_arg(3); + + $time_cache = $endtime - $this->curtime; + $time_db = $splittime - $endtime; + $color = ($time_db > $time_cache) ? 'green' : 'red'; + + $this->sql_report .= '
' . (($val) ? ucwords(str_replace('_', ' ', $val)) : ' ') . '
' . (($val) ? $val : ' ') . '
'; + $this->sql_report .= '
Query results obtained from the cache
'; + $this->sql_report .= '

'; + $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: ' . sprintf('%.5f', ($time_cache)) . 's | Elapsed [db]: ' . sprintf('%.5f', $time_db) . 's



'; + + // Pad the start time to not interfere with page timing + $starttime += $time_db; + + break; + + default: + + $this->_sql_report($mode, $query); + + break; + } + + return true; + } + + /** + * Gets the estimated number of rows in a specified table. + * + * @param string $table_name Table name + * + * @return string Number of rows in $table_name. + * Prefixed with ~ if estimated (otherwise exact). + * + * @access public + */ + function get_estimated_row_count($table_name) + { + return $this->get_row_count($table_name); + } + + /** + * Gets the exact number of rows in a specified table. + * + * @param string $table_name Table name + * + * @return string Exact number of rows in $table_name. + * + * @access public + */ + function get_row_count($table_name) + { + $sql = 'SELECT COUNT(*) AS rows_total + FROM ' . $this->sql_escape($table_name); + $result = $this->sql_query($sql); + $rows_total = $this->sql_fetchfield('rows_total'); + $this->sql_freeresult($result); + + return $rows_total; + } } From 9cc7680965ae8091fd488b8210ae66c790c83978 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Thu, 15 Nov 2012 03:24:08 +0100 Subject: [PATCH 020/497] [ticket/11015] Fix some more whitespace in the driver PHPBB3-11015 --- phpBB/includes/db/driver/driver.php | 42 ++++++++++++++--------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/phpBB/includes/db/driver/driver.php b/phpBB/includes/db/driver/driver.php index 49bfcb8007..25daa7243d 100644 --- a/phpBB/includes/db/driver/driver.php +++ b/phpBB/includes/db/driver/driver.php @@ -75,9 +75,9 @@ class phpbb_db_driver function __construct() { $this->num_queries = array( - 'cached' => 0, - 'normal' => 0, - 'total' => 0, + 'cached' => 0, + 'normal' => 0, + 'total' => 0, ); // Fill default sql layer based on the class being called. @@ -288,10 +288,10 @@ class phpbb_db_driver * * Note: The two statements action_true and action_false must have the same data type (int, vchar, ...) in the database! * - * @param string $condition The condition which must be true, to use action_true rather then action_else - * @param string $action_true SQL expression that is used, if the condition is true - * @param string $action_else SQL expression that is used, if the condition is false, optional - * @return string CASE expression including the condition and statements + * @param string $condition The condition which must be true, to use action_true rather then action_else + * @param string $action_true SQL expression that is used, if the condition is true + * @param string $action_else SQL expression that is used, if the condition is false, optional + * @return string CASE expression including the condition and statements */ public function sql_case($condition, $action_true, $action_false = false) { @@ -305,9 +305,9 @@ class phpbb_db_driver /** * Build a concatenated expression * - * @param string $expr1 Base SQL expression where we append the second one - * @param string $expr2 SQL expression that is appended to the first expression - * @return string Concatenated string + * @param string $expr1 Base SQL expression where we append the second one + * @param string $expr2 SQL expression that is appended to the first expression + * @return string Concatenated string */ public function sql_concatenate($expr1, $expr2) { @@ -447,10 +447,10 @@ class phpbb_db_driver * arrays to improve comparison speed * * @access public - * @param string $field name of the sql column that shall be compared - * @param array $array array of values that are allowed (IN) or not allowed (NOT IN) - * @param bool $negate true for NOT IN (), false for IN () (default) - * @param bool $allow_empty_set If true, allow $array to be empty, this function will return 1=1 or 1=0 then. Default to false. + * @param string $field name of the sql column that shall be compared + * @param array $array array of values that are allowed (IN) or not allowed (NOT IN) + * @param bool $negate true for NOT IN (), false for IN () (default) + * @param bool $allow_empty_set If true, allow $array to be empty, this function will return 1=1 or 1=0 then. Default to false. */ function sql_in_set($field, $array, $negate = false, $allow_empty_set = false) { @@ -555,9 +555,9 @@ class phpbb_db_driver /** * Run LOWER() on DB column of type text (i.e. neither varchar nor char). * - * @param string $column_name The column name to use + * @param string $column_name The column name to use * - * @return string A SQL statement like "LOWER($column_name)" + * @return string A SQL statement like "LOWER($column_name)" */ function sql_lower_text($column_name) { @@ -1010,10 +1010,10 @@ class phpbb_db_driver /** * Gets the estimated number of rows in a specified table. * - * @param string $table_name Table name + * @param string $table_name Table name * - * @return string Number of rows in $table_name. - * Prefixed with ~ if estimated (otherwise exact). + * @return string Number of rows in $table_name. + * Prefixed with ~ if estimated (otherwise exact). * * @access public */ @@ -1025,9 +1025,9 @@ class phpbb_db_driver /** * Gets the exact number of rows in a specified table. * - * @param string $table_name Table name + * @param string $table_name Table name * - * @return string Exact number of rows in $table_name. + * @return string Exact number of rows in $table_name. * * @access public */ From bf1325b1b44f466d2b4aac93e02ca0e17d7054ae Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Thu, 15 Nov 2012 23:48:49 +0100 Subject: [PATCH 021/497] [ticket/11015] Re-introduce accidentally removed require in install_convert PHPBB3-11015 --- phpBB/install/install_convert.php | 1 + 1 file changed, 1 insertion(+) diff --git a/phpBB/install/install_convert.php b/phpBB/install/install_convert.php index fc4c39e168..48624dc2b8 100644 --- a/phpBB/install/install_convert.php +++ b/phpBB/install/install_convert.php @@ -208,6 +208,7 @@ class install_convert extends module require($phpbb_root_path . 'config.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); + require($phpbb_root_path . 'includes/functions_convert.' . $phpEx); $db = new $dbms(); $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true); From a23eebdb7bb60c4b910357c1e948b97d48071d6a Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Fri, 16 Nov 2012 01:09:17 +0100 Subject: [PATCH 022/497] [tracker/11015] Prepend phpbb_db_driver_ for PHPBB_TEST_DBMS PHPBB3-11015 --- tests/test_framework/phpbb_test_case_helpers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_framework/phpbb_test_case_helpers.php b/tests/test_framework/phpbb_test_case_helpers.php index 0f4f7fbf34..5c1200657d 100644 --- a/tests/test_framework/phpbb_test_case_helpers.php +++ b/tests/test_framework/phpbb_test_case_helpers.php @@ -96,7 +96,7 @@ class phpbb_test_case_helpers if (isset($_SERVER['PHPBB_TEST_DBMS'])) { $config = array_merge($config, array( - 'dbms' => isset($_SERVER['PHPBB_TEST_DBMS']) ? $_SERVER['PHPBB_TEST_DBMS'] : '', + 'dbms' => isset($_SERVER['PHPBB_TEST_DBMS']) ? 'phpbb_db_driver_' . $_SERVER['PHPBB_TEST_DBMS'] : '', 'dbhost' => isset($_SERVER['PHPBB_TEST_DBHOST']) ? $_SERVER['PHPBB_TEST_DBHOST'] : '', 'dbport' => isset($_SERVER['PHPBB_TEST_DBPORT']) ? $_SERVER['PHPBB_TEST_DBPORT'] : '', 'dbname' => isset($_SERVER['PHPBB_TEST_DBNAME']) ? $_SERVER['PHPBB_TEST_DBNAME'] : '', From 0d4a289778893d44288d9f586852038f6b52d4db Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Fri, 16 Nov 2012 01:26:36 +0100 Subject: [PATCH 023/497] [ticket/11015] Remove strange method_exists call PHPBB3-11015 --- phpBB/includes/db/driver/mssql.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/db/driver/mssql.php b/phpBB/includes/db/driver/mssql.php index 04bb75f5ce..2e9debf84f 100644 --- a/phpBB/includes/db/driver/mssql.php +++ b/phpBB/includes/db/driver/mssql.php @@ -157,7 +157,7 @@ class phpbb_db_driver_mssql extends phpbb_db_driver $this->sql_report('stop', $query); } - if ($cache_ttl && method_exists($cache, 'sql_save')) + if ($cache_ttl) { $this->open_queries[(int) $this->query_result] = $this->query_result; $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl); From fc5385c2a58833af2929c75d132903a3a0918da9 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Fri, 16 Nov 2012 01:48:03 +0100 Subject: [PATCH 024/497] [ticket/11015] Allow full dbms class name in config.php PHPBB3-11015 --- phpBB/includes/di/extension/config.php | 28 ++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/phpBB/includes/di/extension/config.php b/phpBB/includes/di/extension/config.php index 5b2df93ff2..85ab7ab28d 100644 --- a/phpBB/includes/di/extension/config.php +++ b/phpBB/includes/di/extension/config.php @@ -43,8 +43,8 @@ class phpbb_di_extension_config extends Extension require($this->config_file); $container->setParameter('core.table_prefix', $table_prefix); - $container->setParameter('cache.driver.class', $this->fix_acm_type($acm_type)); - $container->setParameter('dbal.driver.class', 'phpbb_db_driver_'.$dbms); + $container->setParameter('cache.driver.class', $this->convert_30_acm_type($acm_type)); + $container->setParameter('dbal.driver.class', $this->convert_30_dbms($dbms)); $container->setParameter('dbal.dbhost', $dbhost); $container->setParameter('dbal.dbuser', $dbuser); $container->setParameter('dbal.dbpasswd', $dbpasswd); @@ -66,12 +66,12 @@ class phpbb_di_extension_config extends Extension } /** - * Convert old (3.0) values to 3.1 class names + * Convert 3.0 ACM type to 3.1 cache driver class name * - * @param style $acm_type ACM type - * @return ACM type class + * @param string $acm_type ACM type + * @return cache driver class */ - protected function fix_acm_type($acm_type) + protected function convert_30_acm_type($acm_type) { if (preg_match('#^[a-z]+$#', $acm_type)) { @@ -80,4 +80,20 @@ class phpbb_di_extension_config extends Extension return $acm_type; } + + /** + * Convert 3.0 dbms to 3.1 db driver class name + * + * @param string $dbms dbms parameter + * @return db driver class + */ + protected function convert_30_dbms($dbms) + { + if (!preg_match('#^phpbb_db_driver_#', $dbms)) + { + return 'phpbb_db_driver_'.$dbms; + } + + return $dbms; + } } From 8f8a7f76374679d2f893245c1f607a3b2db56a9a Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Fri, 16 Nov 2012 01:50:30 +0100 Subject: [PATCH 025/497] [ticket/11015] Allow full dbms class name in tests/test_config.php PHPBB3-11015 --- .../phpbb_test_case_helpers.php | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tests/test_framework/phpbb_test_case_helpers.php b/tests/test_framework/phpbb_test_case_helpers.php index 5c1200657d..9bbdcff440 100644 --- a/tests/test_framework/phpbb_test_case_helpers.php +++ b/tests/test_framework/phpbb_test_case_helpers.php @@ -78,7 +78,7 @@ class phpbb_test_case_helpers include($test_config); $config = array_merge($config, array( - 'dbms' => 'phpbb_db_driver_' . $dbms, + 'dbms' => $this->convert_30_dbms($dbms), 'dbhost' => $dbhost, 'dbport' => $dbport, 'dbname' => $dbname, @@ -96,7 +96,7 @@ class phpbb_test_case_helpers if (isset($_SERVER['PHPBB_TEST_DBMS'])) { $config = array_merge($config, array( - 'dbms' => isset($_SERVER['PHPBB_TEST_DBMS']) ? 'phpbb_db_driver_' . $_SERVER['PHPBB_TEST_DBMS'] : '', + 'dbms' => isset($_SERVER['PHPBB_TEST_DBMS']) ? $this->convert_30_dbms($_SERVER['PHPBB_TEST_DBMS']) : '', 'dbhost' => isset($_SERVER['PHPBB_TEST_DBHOST']) ? $_SERVER['PHPBB_TEST_DBHOST'] : '', 'dbport' => isset($_SERVER['PHPBB_TEST_DBPORT']) ? $_SERVER['PHPBB_TEST_DBPORT'] : '', 'dbname' => isset($_SERVER['PHPBB_TEST_DBNAME']) ? $_SERVER['PHPBB_TEST_DBNAME'] : '', @@ -223,4 +223,20 @@ class phpbb_test_case_helpers } } } + + /** + * Convert 3.0 dbms to 3.1 db driver class name + * + * @param string $dbms dbms parameter + * @return db driver class + */ + protected function convert_30_dbms($dbms) + { + if (!preg_match('#^phpbb_db_driver_#', $dbms)) + { + return 'phpbb_db_driver_'.$dbms; + } + + return $dbms; + } } From 5bc0f4b3d49ed1bea45464beece42906646eb026 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Sat, 17 Nov 2012 00:24:32 +0100 Subject: [PATCH 026/497] [ticket/11015] Move db driver class name fixing to function PHPBB3-11015 --- phpBB/includes/di/extension/config.php | 18 +---------------- phpBB/includes/functions.php | 16 +++++++++++++++ .../includes/questionnaire/questionnaire.php | 2 ++ phpBB/install/convertors/convert_phpbb20.php | 2 ++ phpBB/install/install_convert.php | 8 ++++++++ phpBB/install/install_update.php | 2 ++ .../phpbb_test_case_helpers.php | 20 ++----------------- 7 files changed, 33 insertions(+), 35 deletions(-) diff --git a/phpBB/includes/di/extension/config.php b/phpBB/includes/di/extension/config.php index 85ab7ab28d..97a6290066 100644 --- a/phpBB/includes/di/extension/config.php +++ b/phpBB/includes/di/extension/config.php @@ -44,7 +44,7 @@ class phpbb_di_extension_config extends Extension $container->setParameter('core.table_prefix', $table_prefix); $container->setParameter('cache.driver.class', $this->convert_30_acm_type($acm_type)); - $container->setParameter('dbal.driver.class', $this->convert_30_dbms($dbms)); + $container->setParameter('dbal.driver.class', phpbb_convert_30_dbms_to_31($dbms)); $container->setParameter('dbal.dbhost', $dbhost); $container->setParameter('dbal.dbuser', $dbuser); $container->setParameter('dbal.dbpasswd', $dbpasswd); @@ -80,20 +80,4 @@ class phpbb_di_extension_config extends Extension return $acm_type; } - - /** - * Convert 3.0 dbms to 3.1 db driver class name - * - * @param string $dbms dbms parameter - * @return db driver class - */ - protected function convert_30_dbms($dbms) - { - if (!preg_match('#^phpbb_db_driver_#', $dbms)) - { - return 'phpbb_db_driver_'.$dbms; - } - - return $dbms; - } } diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 804d89d1a2..045a28672b 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -5412,3 +5412,19 @@ function phpbb_to_numeric($input) { return ($input > PHP_INT_MAX) ? (float) $input : (int) $input; } + +/** +* Convert 3.0 dbms to 3.1 db driver class name +* +* @param string $dbms dbms parameter +* @return db driver class +*/ +function phpbb_convert_30_dbms_to_31($dbms) +{ + if (!preg_match('#^phpbb_db_driver_#', $dbms)) + { + return 'phpbb_db_driver_'.$dbms; + } + + return $dbms; +} diff --git a/phpBB/includes/questionnaire/questionnaire.php b/phpBB/includes/questionnaire/questionnaire.php index f0fb8c3c06..6bbedacbe2 100644 --- a/phpBB/includes/questionnaire/questionnaire.php +++ b/phpBB/includes/questionnaire/questionnaire.php @@ -260,6 +260,8 @@ class phpbb_questionnaire_phpbb_data_provider include("{$phpbb_root_path}config.$phpEx"); unset($dbhost, $dbport, $dbname, $dbuser, $dbpasswd); // Just a precaution + $dbms = phpbb_convert_30_dbms_to_31($dbms); + // Only send certain config vars $config_vars = array( 'active_sessions' => true, diff --git a/phpBB/install/convertors/convert_phpbb20.php b/phpBB/install/convertors/convert_phpbb20.php index 68acea02b3..5f30625980 100644 --- a/phpBB/install/convertors/convert_phpbb20.php +++ b/phpBB/install/convertors/convert_phpbb20.php @@ -24,6 +24,8 @@ if (!defined('IN_PHPBB')) include($phpbb_root_path . 'config.' . $phpEx); unset($dbpasswd); +$dbms = phpbb_convert_30_dbms_to_31($dbms); + /** * $convertor_data provides some basic information about this convertor which is * used on the initial list of convertors and to populate the default settings diff --git a/phpBB/install/install_convert.php b/phpBB/install/install_convert.php index 48624dc2b8..9afe341ffa 100644 --- a/phpBB/install/install_convert.php +++ b/phpBB/install/install_convert.php @@ -123,6 +123,8 @@ class install_convert extends module require($phpbb_root_path . 'includes/constants.' . $phpEx); require($phpbb_root_path . 'includes/functions_convert.' . $phpEx); + $dbms = phpbb_convert_30_dbms_to_31($dbms); + $db = new $dbms(); $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true); unset($dbpasswd); @@ -210,6 +212,8 @@ class install_convert extends module require($phpbb_root_path . 'includes/constants.' . $phpEx); require($phpbb_root_path . 'includes/functions_convert.' . $phpEx); + $dbms = phpbb_convert_30_dbms_to_31($dbms); + $db = new $dbms(); $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true); unset($dbpasswd); @@ -332,6 +336,8 @@ class install_convert extends module require($phpbb_root_path . 'includes/constants.' . $phpEx); require($phpbb_root_path . 'includes/functions_convert.' . $phpEx); + $dbms = phpbb_convert_30_dbms_to_31($dbms); + $db = new $dbms(); $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true); unset($dbpasswd); @@ -573,6 +579,8 @@ class install_convert extends module require($phpbb_root_path . 'includes/constants.' . $phpEx); require($phpbb_root_path . 'includes/functions_convert.' . $phpEx); + $dbms = phpbb_convert_30_dbms_to_31($dbms); + $db = new $dbms(); $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true); unset($dbpasswd); diff --git a/phpBB/install/install_update.php b/phpBB/install/install_update.php index 7d0d627e9d..a556056382 100644 --- a/phpBB/install/install_update.php +++ b/phpBB/install/install_update.php @@ -91,6 +91,8 @@ class install_update extends module define('MERGE_NEW_FILE', 3); define('MERGE_MOD_FILE', 4); + $dbms = phpbb_convert_30_dbms_to_31($dbms); + $db = new $dbms(); // Connect to DB diff --git a/tests/test_framework/phpbb_test_case_helpers.php b/tests/test_framework/phpbb_test_case_helpers.php index 9bbdcff440..96a546e538 100644 --- a/tests/test_framework/phpbb_test_case_helpers.php +++ b/tests/test_framework/phpbb_test_case_helpers.php @@ -78,7 +78,7 @@ class phpbb_test_case_helpers include($test_config); $config = array_merge($config, array( - 'dbms' => $this->convert_30_dbms($dbms), + 'dbms' => phpbb_convert_30_dbms_to_31($dbms), 'dbhost' => $dbhost, 'dbport' => $dbport, 'dbname' => $dbname, @@ -96,7 +96,7 @@ class phpbb_test_case_helpers if (isset($_SERVER['PHPBB_TEST_DBMS'])) { $config = array_merge($config, array( - 'dbms' => isset($_SERVER['PHPBB_TEST_DBMS']) ? $this->convert_30_dbms($_SERVER['PHPBB_TEST_DBMS']) : '', + 'dbms' => isset($_SERVER['PHPBB_TEST_DBMS']) ? phpbb_convert_30_dbms_to_31($_SERVER['PHPBB_TEST_DBMS']) : '', 'dbhost' => isset($_SERVER['PHPBB_TEST_DBHOST']) ? $_SERVER['PHPBB_TEST_DBHOST'] : '', 'dbport' => isset($_SERVER['PHPBB_TEST_DBPORT']) ? $_SERVER['PHPBB_TEST_DBPORT'] : '', 'dbname' => isset($_SERVER['PHPBB_TEST_DBNAME']) ? $_SERVER['PHPBB_TEST_DBNAME'] : '', @@ -223,20 +223,4 @@ class phpbb_test_case_helpers } } } - - /** - * Convert 3.0 dbms to 3.1 db driver class name - * - * @param string $dbms dbms parameter - * @return db driver class - */ - protected function convert_30_dbms($dbms) - { - if (!preg_match('#^phpbb_db_driver_#', $dbms)) - { - return 'phpbb_db_driver_'.$dbms; - } - - return $dbms; - } } From 0372ecf14141ba2c174782f29d4fb079b4dd56c3 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Sat, 17 Nov 2012 01:40:32 +0100 Subject: [PATCH 027/497] [ticket/11015] Make phpbb_convert_30_dbms_to_31 more future proof It should allow any class name in the future, as long as that class exists. And it should give a useful error message otherwise. PHPBB3-11015 --- phpBB/includes/functions.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 045a28672b..57136a43ff 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -5421,10 +5421,15 @@ function phpbb_to_numeric($input) */ function phpbb_convert_30_dbms_to_31($dbms) { - if (!preg_match('#^phpbb_db_driver_#', $dbms)) + if (class_exists($dbms)) { - return 'phpbb_db_driver_'.$dbms; + return $dbms; } - return $dbms; + if (class_exists('phpbb_db_driver_' . $dbms)) + { + return 'phpbb_db_driver_' . $dbms; + } + + throw new \RuntimeException('You have specified an invalid dbms driver.'); } From ed548ae8ff0e87035c0c173d40212a96fa642135 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 23 Apr 2011 16:43:55 -0400 Subject: [PATCH 028/497] [feature/template-events] Outline for RUNHOOKS template tag. Ported to the new develop, hopefully this is still sensible. PHPBB3-9550 --- phpBB/includes/template/filter.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 66d28242a3..fc99ba5917 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -317,6 +317,12 @@ class phpbb_template_filter extends php_user_filter return ''; break; + case 'RUNHOOKS': + // return value here will be compiled code (html with embedded php). + // we don't want to wrap it in php tags here. + return 'compile_tag_run_hooks($matches[2]) . '?>'; + break; + default: return $matches[0]; break; @@ -835,6 +841,27 @@ class phpbb_template_filter extends php_user_filter return "\$_template->_php_include('$tag_args');"; } + /** + * Compile RUNHOOKS tag. + * + * $tag_args should be a single string identifying hook location. + */ + private function compile_tag_run_hooks($tag_args) + { + if (!preg_match('/^\w+$/', $tag_args)) + { + // do something + var_dump($tag_args); + } + $location = $tag_args; + // 1. find all mods defining hooks for location + // 2. obtain mods' template fragments + // 3. compile template fragments + // 4. return compiled code + // note: need to make sure we get fragments in the right order + return 'echo "test";'; + } + /** * parse expression * This is from Smarty From d6c881d0c67de80f0b60eab6be0c1dda33296657 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 27 Nov 2011 00:46:36 -0500 Subject: [PATCH 029/497] [feature/template-events] Inject extension manager into template class. Template class passes extension manager to template compiler. Template compiler passes extension manager to template filter. Template filter will use extension manager to locate hooks as it is compiling templates. All extension manager arguments are optional. If an extension manager is not given, template hooks will not be invoked. PHPBB3-9550 --- phpBB/config/services.yml | 1 + phpBB/includes/bbcode.php | 2 +- phpBB/includes/functions_messenger.php | 2 +- phpBB/includes/template/compile.php | 8 +++++--- phpBB/includes/template/filter.php | 8 ++++++++ phpBB/includes/template/template.php | 13 +++++++++++-- 6 files changed, 27 insertions(+), 7 deletions(-) diff --git a/phpBB/config/services.yml b/phpBB/config/services.yml index 20aa0546d5..83a1c1fa69 100644 --- a/phpBB/config/services.yml +++ b/phpBB/config/services.yml @@ -128,6 +128,7 @@ services: - @user - @style.resource_locator - @template_context + - @ext.manager template_context: class: phpbb_template_context diff --git a/phpBB/includes/bbcode.php b/phpBB/includes/bbcode.php index b9ffa8091c..e8681420d4 100644 --- a/phpBB/includes/bbcode.php +++ b/phpBB/includes/bbcode.php @@ -134,7 +134,7 @@ class bbcode $style_resource_locator = new phpbb_style_resource_locator(); $style_path_provider = new phpbb_style_extension_path_provider($phpbb_extension_manager, new phpbb_style_path_provider()); - $template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $style_resource_locator, new phpbb_template_context()); + $template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $style_resource_locator, new phpbb_template_context(), $phpbb_extension_manager); $style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $style_resource_locator, $style_path_provider, $template); $style->set_style(); $template->set_filenames(array('bbcode.html' => 'bbcode.html')); diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php index cf03de08c4..55884caedb 100644 --- a/phpBB/includes/functions_messenger.php +++ b/phpBB/includes/functions_messenger.php @@ -210,7 +210,7 @@ class messenger { $style_resource_locator = new phpbb_style_resource_locator(); $style_path_provider = new phpbb_style_extension_path_provider($phpbb_extension_manager, new phpbb_style_path_provider()); - $tpl = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $style_resource_locator, new phpbb_template_context()); + $tpl = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $style_resource_locator, new phpbb_template_context(), $extension_manager); $style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $style_resource_locator, $style_path_provider, $tpl); $this->tpl_msg[$template_lang . $template_file] = $tpl; diff --git a/phpBB/includes/template/compile.php b/phpBB/includes/template/compile.php index 82b301c1a2..fb7d146701 100644 --- a/phpBB/includes/template/compile.php +++ b/phpBB/includes/template/compile.php @@ -35,16 +35,18 @@ class phpbb_template_compile /** * Constructor. * - * @param bool @allow_php Whether PHP code will be allowed in templates (inline PHP code, PHP tag and INCLUDEPHP tag) + * @param bool $allow_php Whether PHP code will be allowed in templates (inline PHP code, PHP tag and INCLUDEPHP tag) * @param phpbb_style_resource_locator $locator Resource locator * @param string $phpbb_root_path Path to phpBB root directory + * @param phpbb_extension_manager $extension_manager Extension manager to use for finding template fragments in extensions; if null, template hooks will not be invoked */ - public function __construct($allow_php, $locator, $phpbb_root_path) + public function __construct($allow_php, $locator, $phpbb_root_path, $extension_manager = null) { $this->filter_params = array( 'allow_php' => $allow_php, 'locator' => $locator, - 'phpbb_root_path' => $phpbb_root_path + 'phpbb_root_path' => $phpbb_root_path, + 'extension_manager' => $extension_manager, ); } diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index fc99ba5917..911f21ef00 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -87,6 +87,13 @@ class phpbb_template_filter extends php_user_filter */ private $phpbb_root_path; + /** + * Extension manager. + * + * @var phpbb_extension_manager + */ + private $extension_manager; + /** * Stream filter * @@ -148,6 +155,7 @@ class phpbb_template_filter extends php_user_filter $this->allow_php = $this->params['allow_php']; $this->locator = $this->params['locator']; $this->phpbb_root_path = $this->params['phpbb_root_path']; + $this->extension_manager = $this->params['extension_manager']; return true; } diff --git a/phpBB/includes/template/template.php b/phpBB/includes/template/template.php index 5396ddbfad..96a16fee77 100644 --- a/phpBB/includes/template/template.php +++ b/phpBB/includes/template/template.php @@ -74,6 +74,13 @@ class phpbb_template */ private $locator; + /** + * Extension manager. + * + * @var phpbb_extension_manager + */ + private $extension_manager; + /** * Constructor. * @@ -81,8 +88,9 @@ class phpbb_template * @param user $user current user * @param phpbb_template_locator $locator template locator * @param phpbb_template_context $context template context + * @param phpbb_extension_manager $extension_manager extension manager, if null then template hooks will not be invoked */ - public function __construct($phpbb_root_path, $php_ext, $config, $user, phpbb_template_locator $locator, phpbb_template_context $context) + public function __construct($phpbb_root_path, $php_ext, $config, $user, phpbb_template_locator $locator, phpbb_template_context $context, phpbb_extension_manager $extension_manager = null) { $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; @@ -90,6 +98,7 @@ class phpbb_template $this->user = $user; $this->locator = $locator; $this->context = $context; + $this->extension_manager = $extension_manager; } /** @@ -282,7 +291,7 @@ class phpbb_template return new phpbb_template_renderer_include($output_file, $this); } - $compile = new phpbb_template_compile($this->config['tpl_allow_php'], $this->locator, $this->phpbb_root_path); + $compile = new phpbb_template_compile($this->config['tpl_allow_php'], $this->locator, $this->phpbb_root_path, $this->extension_manager); if ($compile->compile_file_to_file($source_file, $output_file) !== false) { From 09aae1ea30b199630c3972bdc483db476bda9a7e Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 3 Dec 2011 21:08:31 -0500 Subject: [PATCH 030/497] [feature/template-events] Inject template compile into template filter. This is needed for hooks in order for the filter to compile template files from extensions. PHPBB3-9550 --- phpBB/includes/template/filter.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 911f21ef00..3d39b3b4ed 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -94,6 +94,13 @@ class phpbb_template_filter extends php_user_filter */ private $extension_manager; + /** + * Template compiler. + * + * @var phpbb_template_compile + */ + private $template_compile; + /** * Stream filter * @@ -156,6 +163,7 @@ class phpbb_template_filter extends php_user_filter $this->locator = $this->params['locator']; $this->phpbb_root_path = $this->params['phpbb_root_path']; $this->extension_manager = $this->params['extension_manager']; + $this->template_compile = $this->params['template_compile']; return true; } From 66232031e4c69a0f5ba25699ba908946bd445967 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 27 Nov 2011 00:49:39 -0500 Subject: [PATCH 031/497] [feature/template-events] Really basic template hook implementation. PHPBB3-9550 --- phpBB/includes/template/filter.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 3d39b3b4ed..6151983be0 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -870,6 +870,26 @@ class phpbb_template_filter extends php_user_filter var_dump($tag_args); } $location = $tag_args; + + if ($this->phpbb_extension_manager) + { + $finder = $this->phpbb_extension_manager->get_finder(); + + $files = $finder + ->extension_prefix($location) + ->extension_suffix('.html') + ->extension_directory("/styles/universal/template") + ->get_files(); + + $all_compiled = ''; + foreach ($files as $file) + { + $compiled = $this->template_compile->compile_file($file); + $all_compiled .= $compiled; + } + return '?>' . $all_compiled . ' Date: Fri, 3 Feb 2012 02:21:37 -0500 Subject: [PATCH 032/497] [feature/template-events] Fix property name for extension manager. PHPBB3-9550 --- phpBB/includes/template/filter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 6151983be0..ea5b17c11a 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -871,9 +871,9 @@ class phpbb_template_filter extends php_user_filter } $location = $tag_args; - if ($this->phpbb_extension_manager) + if ($this->extension_manager) { - $finder = $this->phpbb_extension_manager->get_finder(); + $finder = $this->extension_manager->get_finder(); $files = $finder ->extension_prefix($location) From ea094dd91af624c72ac41fde6073dd8918620e68 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 6 Mar 2012 19:45:13 -0500 Subject: [PATCH 033/497] [feature/template-events] Rename universal to all (for template fragments). PHPBB3-9550 --- phpBB/includes/template/filter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index ea5b17c11a..08eb9bdd97 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -878,7 +878,7 @@ class phpbb_template_filter extends php_user_filter $files = $finder ->extension_prefix($location) ->extension_suffix('.html') - ->extension_directory("/styles/universal/template") + ->extension_directory("/styles/all/template") ->get_files(); $all_compiled = ''; From dd7c5183fbc5401c85f530a304b70fbb0b5d7fbe Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 19 Apr 2012 00:21:54 -0400 Subject: [PATCH 034/497] [feature/template-events] Add template_compile to template filter params. PHPBB3-9550 --- phpBB/includes/template/compile.php | 1 + 1 file changed, 1 insertion(+) diff --git a/phpBB/includes/template/compile.php b/phpBB/includes/template/compile.php index fb7d146701..b63da05394 100644 --- a/phpBB/includes/template/compile.php +++ b/phpBB/includes/template/compile.php @@ -47,6 +47,7 @@ class phpbb_template_compile 'locator' => $locator, 'phpbb_root_path' => $phpbb_root_path, 'extension_manager' => $extension_manager, + 'template_compile' => $this, ); } From a6c7fbc59d02ed44ef90e340c4f957a8c5ac9ca5 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 16 Mar 2012 00:22:42 -0400 Subject: [PATCH 035/497] [feature/template-events] Pass top-level template name to template filter. This will be used to invoke template-specific hooks. PHPBB3-9550 --- phpBB/includes/template/compile.php | 4 +++- phpBB/includes/template/filter.php | 13 ++++++++++++- phpBB/includes/template/template.php | 12 +++++++++++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/phpBB/includes/template/compile.php b/phpBB/includes/template/compile.php index b63da05394..06ff60387a 100644 --- a/phpBB/includes/template/compile.php +++ b/phpBB/includes/template/compile.php @@ -36,14 +36,16 @@ class phpbb_template_compile * Constructor. * * @param bool $allow_php Whether PHP code will be allowed in templates (inline PHP code, PHP tag and INCLUDEPHP tag) + * @param string $template_name Name of top-level template being compiled * @param phpbb_style_resource_locator $locator Resource locator * @param string $phpbb_root_path Path to phpBB root directory * @param phpbb_extension_manager $extension_manager Extension manager to use for finding template fragments in extensions; if null, template hooks will not be invoked */ - public function __construct($allow_php, $locator, $phpbb_root_path, $extension_manager = null) + public function __construct($allow_php, $template_name, $locator, $phpbb_root_path, $extension_manager = null) { $this->filter_params = array( 'allow_php' => $allow_php, + 'template_name' => $template_name, 'locator' => $locator, 'phpbb_root_path' => $phpbb_root_path, 'extension_manager' => $extension_manager, diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 08eb9bdd97..eca9a0d48c 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -87,6 +87,16 @@ class phpbb_template_filter extends php_user_filter */ private $phpbb_root_path; + /** + * Name of the top-level template being compiled and/or rendered. + * + * This is used by hooks implementation to invoke template-specific + * template hooks. + * + * @var string + */ + private $template_name; + /** * Extension manager. * @@ -152,7 +162,7 @@ class phpbb_template_filter extends php_user_filter /** * Initializer, called on creation. * - * Get the allow_php option, root directory and locator from params, + * Get the allow_php option, template_name, root directory and locator from params, * which are passed to stream_filter_append. */ public function onCreate() @@ -162,6 +172,7 @@ class phpbb_template_filter extends php_user_filter $this->allow_php = $this->params['allow_php']; $this->locator = $this->params['locator']; $this->phpbb_root_path = $this->params['phpbb_root_path']; + $this->template_name = $this->params['template_name']; $this->extension_manager = $this->params['extension_manager']; $this->template_compile = $this->params['template_compile']; return true; diff --git a/phpBB/includes/template/template.php b/phpBB/includes/template/template.php index 96a16fee77..c43c1ddf99 100644 --- a/phpBB/includes/template/template.php +++ b/phpBB/includes/template/template.php @@ -81,6 +81,16 @@ class phpbb_template */ private $extension_manager; + /** + * Name of the top-level template being compiled and/or rendered. + * + * This is used by hooks implementation to invoke template-specific + * template hooks. + * + * @var string + */ + private $template_name; + /** * Constructor. * @@ -291,7 +301,7 @@ class phpbb_template return new phpbb_template_renderer_include($output_file, $this); } - $compile = new phpbb_template_compile($this->config['tpl_allow_php'], $this->locator, $this->phpbb_root_path, $this->extension_manager); + $compile = new phpbb_template_compile($this->config['tpl_allow_php'], $this->template_name, $this->locator, $this->phpbb_root_path, $this->extension_manager); if ($compile->compile_file_to_file($source_file, $output_file) !== false) { From bdbb382a26efb4194e2eb1b6ee5f3913829fc9d1 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 16 Mar 2012 00:54:09 -0400 Subject: [PATCH 036/497] [feature/template-events] Invoke template hooks that are template-specific. PHPBB3-9550 --- phpBB/includes/template/filter.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index eca9a0d48c..a158dd4074 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -892,6 +892,13 @@ class phpbb_template_filter extends php_user_filter ->extension_directory("/styles/all/template") ->get_files(); + $files = array_merge($files, $finder + ->extension_prefix($location) + ->extension_suffix('.html') + // XXX is this safe? + ->extension_directory("/styles/" . $this->template_name . "/template") + ->get_files()); + $all_compiled = ''; foreach ($files as $file) { From ecdb54fc048a0805f724d7a3931373f99744923a Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 16 Mar 2012 02:09:46 -0400 Subject: [PATCH 037/497] [feature/template-events] PHP does not parse , avoid generating it. PHPBB3-9550 --- phpBB/includes/template/filter.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index a158dd4074..5129618f03 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -905,7 +905,9 @@ class phpbb_template_filter extends php_user_filter $compiled = $this->template_compile->compile_file($file); $all_compiled .= $compiled; } - return '?>' . $all_compiled . ' sans the spaces + return ' ?>' . $all_compiled . ' Date: Tue, 20 Mar 2012 06:53:48 +0000 Subject: [PATCH 038/497] [feature/template-events] Rename RUNHOOKS to EVENT Rename the way to add template events PHPBB3-9550 --- phpBB/includes/template/filter.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 5129618f03..2c0057b64c 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -344,10 +344,10 @@ class phpbb_template_filter extends php_user_filter return ''; break; - case 'RUNHOOKS': + case 'EVENT': // return value here will be compiled code (html with embedded php). // we don't want to wrap it in php tags here. - return 'compile_tag_run_hooks($matches[2]) . '?>'; + return 'compile_tag_event($matches[2]) . '?>'; break; default: @@ -873,7 +873,7 @@ class phpbb_template_filter extends php_user_filter * * $tag_args should be a single string identifying hook location. */ - private function compile_tag_run_hooks($tag_args) + private function compile_tag_event($tag_args) { if (!preg_match('/^\w+$/', $tag_args)) { From 04f55ba3066d4713b6189062f8a61f12ca02ea34 Mon Sep 17 00:00:00 2001 From: Nathan Guse Date: Thu, 18 Oct 2012 17:21:08 -0500 Subject: [PATCH 039/497] [feature/template-events] Correct indentation PHPBB3-9550 --- phpBB/includes/template/filter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 2c0057b64c..39317c6bf3 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -348,7 +348,7 @@ class phpbb_template_filter extends php_user_filter // return value here will be compiled code (html with embedded php). // we don't want to wrap it in php tags here. return 'compile_tag_event($matches[2]) . '?>'; - break; + break; default: return $matches[0]; From f83627763839e601db6b077e4f2f76436c263cd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Fr=C3=A8rejean?= Date: Thu, 19 Apr 2012 13:06:28 +0200 Subject: [PATCH 040/497] [feature/template-events] RUNHOOKS -> EVENT PHPBB3-9550 --- phpBB/includes/template/filter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 39317c6bf3..f3e0f6017c 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -869,7 +869,7 @@ class phpbb_template_filter extends php_user_filter } /** - * Compile RUNHOOKS tag. + * Compile EVENT tag. * * $tag_args should be a single string identifying hook location. */ From db688c2574fd536e1c5f19ed8797d762713c7b6b Mon Sep 17 00:00:00 2001 From: Vjacheslav Trushkin Date: Sun, 1 Apr 2012 14:27:21 +0300 Subject: [PATCH 041/497] [feature/template-events] Template events unit test Adding template events test PHPBB3-9550 --- tests/template/template_events_test.php | 56 +++++++++++++++++++++++++ tests/template/templates/events.html | 4 ++ 2 files changed, 60 insertions(+) create mode 100644 tests/template/template_events_test.php create mode 100644 tests/template/templates/events.html diff --git a/tests/template/template_events_test.php b/tests/template/template_events_test.php new file mode 100644 index 0000000000..c5b54ebba8 --- /dev/null +++ b/tests/template/template_events_test.php @@ -0,0 +1,56 @@ +setup_engine(); + + // Prepare correct result + $dir = dirname(__FILE__); + $files = array( + $dir . '/templates/child_only.html', + $dir . '/parent_templates/parent_only.html', + $dir . '/templates/parent_and_child.html' + ); + $contents = ''; + foreach ($files as $file) + { + if (file_exists($file)) + { + $contents .= file_get_contents($file); + } + } + $contents = trim($contents); + + // Run test + $cache_file = $this->template->cachepath . 'events.html.php'; + $this->run_template('events.html', array(), array(), array(), $contents, $cache_file); + } + + protected function setup_engine(array $new_config = array()) + { + global $phpbb_root_path, $phpEx, $user; + + $defaults = $this->config_defaults(); + $config = new phpbb_config(array_merge($defaults, $new_config)); + + $this->template_path = dirname(__FILE__) . '/templates'; + $this->parent_template_path = dirname(__FILE__) . '/parent_templates'; + $this->style_resource_locator = new phpbb_style_resource_locator(); + $this->style_provider = new phpbb_style_path_provider(); + $this->template = new phpbb_style_template($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, $this->style_provider); + $this->style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, $this->style_provider, $this->template); + $this->style->set_custom_style('tests', array($this->template_path, $this->parent_template_path), ''); + } +} diff --git a/tests/template/templates/events.html b/tests/template/templates/events.html new file mode 100644 index 0000000000..c44a7469e7 --- /dev/null +++ b/tests/template/templates/events.html @@ -0,0 +1,4 @@ + + + + From 132bbede2b5ca5e1bbb371bdaef0bb3041c67316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Fr=C3=A8rejean?= Date: Wed, 18 Apr 2012 15:35:09 +0200 Subject: [PATCH 042/497] [feature/template-events] Handle incorrect template event identifiers If the template event identifier is wrongly formatted phpBB will triggern an `E_USER_NOTICE` if the `DEBUG` constant is set, otherwise the location is ignored. PHPBB3-9550 --- phpBB/includes/template/filter.php | 12 ++++++++++-- phpBB/language/en/common.php | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index f3e0f6017c..50882b2855 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -877,8 +877,16 @@ class phpbb_template_filter extends php_user_filter { if (!preg_match('/^\w+$/', $tag_args)) { - // do something - var_dump($tag_args); + // The hook location is wrongly formatted, + // if the `DEBUG` constant is set then trigger a waring, + // otherwise drop the hook and continue + if (defined('DEBUG')) + { + global $user; + trigger_error($user->lang('ERR_TEMPLATE_EVENT_LOCATION', $tag_args), E_USER_NOTICE); + } + + return; } $location = $tag_args; diff --git a/phpBB/language/en/common.php b/phpBB/language/en/common.php index 7ce3b5d2e6..5fc1b21e4f 100644 --- a/phpBB/language/en/common.php +++ b/phpBB/language/en/common.php @@ -186,6 +186,7 @@ $lang = array_merge($lang, array( 'ERR_CONNECTING_SERVER' => 'Error connecting to the server.', 'ERR_JAB_AUTH' => 'Could not authorise on Jabber server.', 'ERR_JAB_CONNECT' => 'Could not connect to Jabber server.', + 'ERR_TEMPLATE_EVENT_LOCATION' => 'The specified template event location [%s] is wrongly formatted.', 'ERR_UNABLE_TO_LOGIN' => 'The specified username or password is incorrect.', 'ERR_UNWATCHING' => 'An error occured while trying to unsubscribe.', 'ERR_WATCHING' => 'An error occured while trying to subscribe.', From 6fc0c889fd714945613be1c51316b1386f3c88f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Fr=C3=A8rejean?= Date: Thu, 19 Apr 2012 13:57:11 +0200 Subject: [PATCH 043/497] [feature/template-events] Remove comment Remove comment per Nils in the PR. PHPBB3-9550 --- phpBB/includes/template/filter.php | 1 - 1 file changed, 1 deletion(-) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 50882b2855..798cadaa2a 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -903,7 +903,6 @@ class phpbb_template_filter extends php_user_filter $files = array_merge($files, $finder ->extension_prefix($location) ->extension_suffix('.html') - // XXX is this safe? ->extension_directory("/styles/" . $this->template_name . "/template") ->get_files()); From 2add66c0ebd49bb2f8beee538676fe34f969b33e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Fr=C3=A8rejean?= Date: Thu, 19 Apr 2012 13:58:41 +0200 Subject: [PATCH 044/497] [feature/template-events] Add additional space for editors Use `' ?'. '>'` rather than `' ?>'` as the latter causes problems in some editors. PHPBB3-9550 --- phpBB/includes/template/filter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 798cadaa2a..1ec1467c09 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -914,7 +914,7 @@ class phpbb_template_filter extends php_user_filter } // Need spaces inside php tags as php cannot grok // < ?php? > sans the spaces - return ' ?>' . $all_compiled . '' . $all_compiled . ' Date: Thu, 19 Apr 2012 14:00:42 +0200 Subject: [PATCH 045/497] [feature/template-events] Fix typo (waring -> warning) PHPBB3-9550 --- phpBB/includes/template/filter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 1ec1467c09..453e2a05ce 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -878,7 +878,7 @@ class phpbb_template_filter extends php_user_filter if (!preg_match('/^\w+$/', $tag_args)) { // The hook location is wrongly formatted, - // if the `DEBUG` constant is set then trigger a waring, + // if the `DEBUG` constant is set then trigger a warning, // otherwise drop the hook and continue if (defined('DEBUG')) { From f46f48a2cfbc923f4e4734dfd200cc6ddbfd689e Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 10 May 2012 04:22:39 -0400 Subject: [PATCH 046/497] [feature/template-events] Chase template/style renames and changes. PHPBB3-9550 --- phpBB/includes/template/template.php | 2 +- tests/template/template_compile_test.php | 2 +- tests/template/template_events_test.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/phpBB/includes/template/template.php b/phpBB/includes/template/template.php index c43c1ddf99..19ee59323a 100644 --- a/phpBB/includes/template/template.php +++ b/phpBB/includes/template/template.php @@ -301,7 +301,7 @@ class phpbb_template return new phpbb_template_renderer_include($output_file, $this); } - $compile = new phpbb_template_compile($this->config['tpl_allow_php'], $this->template_name, $this->locator, $this->phpbb_root_path, $this->extension_manager); + $compile = new phpbb_template_compile($this->config['tpl_allow_php'], $this->template_name, $this->locator, $this->phpbb_root_path, $this->extension_manager, $this->user); if ($compile->compile_file_to_file($source_file, $output_file) !== false) { diff --git a/tests/template/template_compile_test.php b/tests/template/template_compile_test.php index 0cfcd6ceb5..7393fc1747 100644 --- a/tests/template/template_compile_test.php +++ b/tests/template/template_compile_test.php @@ -16,7 +16,7 @@ class phpbb_template_template_compile_test extends phpbb_test_case protected function setUp() { - $this->template_compile = new phpbb_template_compile(false, null, ''); + $this->template_compile = new phpbb_template_compile(false, null, $this->style_resource_locator, ''); $this->template_path = dirname(__FILE__) . '/templates'; } diff --git a/tests/template/template_events_test.php b/tests/template/template_events_test.php index c5b54ebba8..2d6fd4bfb2 100644 --- a/tests/template/template_events_test.php +++ b/tests/template/template_events_test.php @@ -49,7 +49,7 @@ class phpbb_template_template_events_test extends phpbb_template_template_test_c $this->parent_template_path = dirname(__FILE__) . '/parent_templates'; $this->style_resource_locator = new phpbb_style_resource_locator(); $this->style_provider = new phpbb_style_path_provider(); - $this->template = new phpbb_style_template($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, $this->style_provider); + $this->template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator); $this->style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, $this->style_provider, $this->template); $this->style->set_custom_style('tests', array($this->template_path, $this->parent_template_path), ''); } From 45a1219886b039fbb4bda740accbfbbdbf971022 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 10 May 2012 03:53:30 -0400 Subject: [PATCH 047/497] [feature/template-events] Always commit suicide for invalid event names. Note: suicide happens for syntactically invalid event names, e.g. event names containing punctuation. Event names for which there are no events are silently dropped. PHPBB3-9550 --- phpBB/includes/template/filter.php | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 453e2a05ce..2706eb9040 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -878,15 +878,8 @@ class phpbb_template_filter extends php_user_filter if (!preg_match('/^\w+$/', $tag_args)) { // The hook location is wrongly formatted, - // if the `DEBUG` constant is set then trigger a warning, - // otherwise drop the hook and continue - if (defined('DEBUG')) - { - global $user; - trigger_error($user->lang('ERR_TEMPLATE_EVENT_LOCATION', $tag_args), E_USER_NOTICE); - } - - return; + global $user; + trigger_error($user->lang('ERR_TEMPLATE_EVENT_LOCATION', $tag_args), E_USER_ERROR); } $location = $tag_args; From 1b36fc3a6074a661a1b32c015fb9931f3470c61c Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 10 May 2012 04:23:18 -0400 Subject: [PATCH 048/497] [feature/template-events] Handle user access correctly. Pass through $user from template to filter. Allow $user to be null for standalone usage of the template engine. PHPBB3-9550 --- phpBB/includes/template/compile.php | 4 +++- phpBB/includes/template/filter.php | 20 ++++++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/phpBB/includes/template/compile.php b/phpBB/includes/template/compile.php index 06ff60387a..e2e9a095dc 100644 --- a/phpBB/includes/template/compile.php +++ b/phpBB/includes/template/compile.php @@ -40,8 +40,9 @@ class phpbb_template_compile * @param phpbb_style_resource_locator $locator Resource locator * @param string $phpbb_root_path Path to phpBB root directory * @param phpbb_extension_manager $extension_manager Extension manager to use for finding template fragments in extensions; if null, template hooks will not be invoked + * @param phpbb_user $user Current user */ - public function __construct($allow_php, $template_name, $locator, $phpbb_root_path, $extension_manager = null) + public function __construct($allow_php, $template_name, $locator, $phpbb_root_path, $extension_manager = null, $user = null) { $this->filter_params = array( 'allow_php' => $allow_php, @@ -49,6 +50,7 @@ class phpbb_template_compile 'locator' => $locator, 'phpbb_root_path' => $phpbb_root_path, 'extension_manager' => $extension_manager, + 'user' => $user, 'template_compile' => $this, ); } diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 2706eb9040..ed81c4cd8a 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -104,6 +104,12 @@ class phpbb_template_filter extends php_user_filter */ private $extension_manager; + /** + * Current user + * @var phpbb_user + */ + private $user; + /** * Template compiler. * @@ -174,6 +180,10 @@ class phpbb_template_filter extends php_user_filter $this->phpbb_root_path = $this->params['phpbb_root_path']; $this->template_name = $this->params['template_name']; $this->extension_manager = $this->params['extension_manager']; + if (isset($this->params['user'])) + { + $this->user = $this->params['user']; + } $this->template_compile = $this->params['template_compile']; return true; } @@ -878,8 +888,14 @@ class phpbb_template_filter extends php_user_filter if (!preg_match('/^\w+$/', $tag_args)) { // The hook location is wrongly formatted, - global $user; - trigger_error($user->lang('ERR_TEMPLATE_EVENT_LOCATION', $tag_args), E_USER_ERROR); + if ($this->user) + { + trigger_error($this->user->lang('ERR_TEMPLATE_EVENT_LOCATION', $tag_args), E_USER_ERROR); + } + else + { + trigger_error(sprintf('The specified template event location [%s] is wrongly formatted.', $tag_args), E_USER_ERROR); + } } $location = $tag_args; From bd63b17d0030706e080188ab6bf3bdec8466ae82 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 10 May 2012 05:06:00 -0400 Subject: [PATCH 049/497] [feature/template-events] Move comment to the function docblock. PHPBB3-9550 --- phpBB/includes/template/filter.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index ed81c4cd8a..9f77c4a1b7 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -266,7 +266,9 @@ class phpbb_template_filter extends php_user_filter } /** - * Callback for replacing matched tokens with PHP code + * Callback for replacing matched tokens with compiled template code. + * + * Compiled template code is an HTML stream with embedded PHP. * * @param array $matches Regular expression matches * @return string compiled template code @@ -355,8 +357,6 @@ class phpbb_template_filter extends php_user_filter break; case 'EVENT': - // return value here will be compiled code (html with embedded php). - // we don't want to wrap it in php tags here. return 'compile_tag_event($matches[2]) . '?>'; break; From faf96a1b4017c2bdceb4458c1d84959cb07da9bb Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 10 May 2012 05:11:45 -0400 Subject: [PATCH 050/497] [feature/template-events] Delete old comments/test code. PHPBB3-9550 --- phpBB/includes/template/filter.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 9f77c4a1b7..cb0b2b0cd9 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -925,13 +925,6 @@ class phpbb_template_filter extends php_user_filter // < ?php? > sans the spaces return ' ?' . '>' . $all_compiled . ' Date: Thu, 10 May 2012 05:23:54 -0400 Subject: [PATCH 051/497] [feature/template-events] Update EVENT tag documentation. It should now fairly closely reflect what actually happens. PHPBB3-9550 --- phpBB/includes/template/filter.php | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index cb0b2b0cd9..9f814f5c5f 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -881,7 +881,27 @@ class phpbb_template_filter extends php_user_filter /** * Compile EVENT tag. * - * $tag_args should be a single string identifying hook location. + * $tag_args should be a single string identifying the event. + * The event name can contain letters, numbers and underscores only. + * If an invalid event name is specified, an E_USER_ERROR will be + * triggered. + * + * Event tags are only functional when the template engine has + * an instance of the extension manager. Extension manager would + * be called upon to find all extensions listening for the specified + * event, and to obtain additional template fragments. All such + * template fragments will be compiled and included in the generated + * compiled template code for the current template being compiled. + * + * The above means that whenever an extension is enabled or disabled, + * template cache should be cleared in order to update the compiled + * template code for the active set of template event listeners. + * + * This also means that extensions cannot return different template + * fragments at different times. Once templates are compiled, changing + * such template fragments would have no effect. + * + * @param string $tag_args EVENT tag arguments, as a string - for EVENT this is the event name */ private function compile_tag_event($tag_args) { From 09b4cf2f4c6df4d967f4df66f2bb29e38ee10a1d Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 11 May 2012 13:38:10 -0400 Subject: [PATCH 052/497] [feature/template-events] Report when templates cannot be compiled. PHPBB3-9550 --- phpBB/includes/template/filter.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 9f814f5c5f..385612b094 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -939,6 +939,10 @@ class phpbb_template_filter extends php_user_filter foreach ($files as $file) { $compiled = $this->template_compile->compile_file($file); + if ($compiled === false) + { + trigger_error(sprintf('The file could not be compiled: %s', phpbb_filter_root_path($file)), E_USER_ERROR); + } $all_compiled .= $compiled; } // Need spaces inside php tags as php cannot grok From 667f8d581f8534a386e8293caafb4b7b5f063dde Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 11 May 2012 13:39:38 -0400 Subject: [PATCH 053/497] [feature/template-events] Add a universal template event test. Also drop the irrelevant includejs code and add a simple template event test. The simple test is not working yet however due to the template engine not correctly tracking which template it is rendering. PHPBB3-9550 --- .../styles/all/template/universal.html | 1 + .../styles/silver/template/simple.html | 1 + tests/template/template_events_test.php | 50 +++++++++++-------- tests/template/templates/event_simple.html | 1 + tests/template/templates/event_universal.html | 1 + 5 files changed, 33 insertions(+), 21 deletions(-) create mode 100644 tests/template/ext/trivial/styles/all/template/universal.html create mode 100644 tests/template/ext/trivial/styles/silver/template/simple.html create mode 100644 tests/template/templates/event_simple.html create mode 100644 tests/template/templates/event_universal.html diff --git a/tests/template/ext/trivial/styles/all/template/universal.html b/tests/template/ext/trivial/styles/all/template/universal.html new file mode 100644 index 0000000000..f2c5762ade --- /dev/null +++ b/tests/template/ext/trivial/styles/all/template/universal.html @@ -0,0 +1 @@ +Universal in trivial extension. diff --git a/tests/template/ext/trivial/styles/silver/template/simple.html b/tests/template/ext/trivial/styles/silver/template/simple.html new file mode 100644 index 0000000000..fe32a1ed3f --- /dev/null +++ b/tests/template/ext/trivial/styles/silver/template/simple.html @@ -0,0 +1 @@ +Simple in trivial extension. diff --git a/tests/template/template_events_test.php b/tests/template/template_events_test.php index 2d6fd4bfb2..3ad6e924cb 100644 --- a/tests/template/template_events_test.php +++ b/tests/template/template_events_test.php @@ -11,31 +11,30 @@ require_once dirname(__FILE__) . '/template_test_case.php'; class phpbb_template_template_events_test extends phpbb_template_template_test_case { - public function test_includejs_compilation() + public function test_simple_event() { // Reset the engine state $this->setup_engine(); // Prepare correct result - $dir = dirname(__FILE__); - $files = array( - $dir . '/templates/child_only.html', - $dir . '/parent_templates/parent_only.html', - $dir . '/templates/parent_and_child.html' - ); - $contents = ''; - foreach ($files as $file) - { - if (file_exists($file)) - { - $contents .= file_get_contents($file); - } - } - $contents = trim($contents); + $contents = "Simple in trivial extension."; // Run test - $cache_file = $this->template->cachepath . 'events.html.php'; - $this->run_template('events.html', array(), array(), array(), $contents, $cache_file); + $cache_file = $this->template->cachepath . 'event_simple.html.php'; + $this->run_template('event_simple.html', array(), array(), array(), $contents, $cache_file); + } + + public function test_universal_event() + { + // Reset the engine state + $this->setup_engine(); + + // Prepare correct result + $contents = "Universal in trivial extension."; + + // Run test + $cache_file = $this->template->cachepath . 'event_universal.html.php'; + $this->run_template('event_universal.html', array(), array(), array(), $contents, $cache_file); } protected function setup_engine(array $new_config = array()) @@ -46,11 +45,20 @@ class phpbb_template_template_events_test extends phpbb_template_template_test_c $config = new phpbb_config(array_merge($defaults, $new_config)); $this->template_path = dirname(__FILE__) . '/templates'; - $this->parent_template_path = dirname(__FILE__) . '/parent_templates'; $this->style_resource_locator = new phpbb_style_resource_locator(); + $this->extension_manager = new phpbb_mock_extension_manager( + dirname(__FILE__) . '/', + array( + 'trivial' => array( + 'ext_name' => 'trivial', + 'ext_active' => true, + 'ext_path' => 'ext/trivial/', + ), + ) + ); + $this->template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, $this->extension_manager); $this->style_provider = new phpbb_style_path_provider(); - $this->template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator); $this->style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, $this->style_provider, $this->template); - $this->style->set_custom_style('tests', array($this->template_path, $this->parent_template_path), ''); + $this->style->set_custom_style('tests', array($this->template_path), ''); } } diff --git a/tests/template/templates/event_simple.html b/tests/template/templates/event_simple.html new file mode 100644 index 0000000000..604c1acdce --- /dev/null +++ b/tests/template/templates/event_simple.html @@ -0,0 +1 @@ + diff --git a/tests/template/templates/event_universal.html b/tests/template/templates/event_universal.html new file mode 100644 index 0000000000..15425cacc3 --- /dev/null +++ b/tests/template/templates/event_universal.html @@ -0,0 +1 @@ + From 0df0c6199b89f154eb6371118b4a796a4d05f36f Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 11 May 2012 13:46:04 -0400 Subject: [PATCH 054/497] [feature/template-events] Switch template event test to data providers. PHPBB3-9550 --- tests/template/template_events_test.php | 50 +++++++++++++++++-------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/tests/template/template_events_test.php b/tests/template/template_events_test.php index 3ad6e924cb..f1d13c1fd6 100644 --- a/tests/template/template_events_test.php +++ b/tests/template/template_events_test.php @@ -11,30 +11,48 @@ require_once dirname(__FILE__) . '/template_test_case.php'; class phpbb_template_template_events_test extends phpbb_template_template_test_case { - public function test_simple_event() + public function template_data() { - // Reset the engine state - $this->setup_engine(); - - // Prepare correct result - $contents = "Simple in trivial extension."; - - // Run test - $cache_file = $this->template->cachepath . 'event_simple.html.php'; - $this->run_template('event_simple.html', array(), array(), array(), $contents, $cache_file); + return array( + /* + array( + '', // File + array(), // vars + array(), // block vars + array(), // destroy + '', // Expected result + ), + */ + array( + 'Simple template event', + 'event_simple.html', + array(), + array(), + array(), + "Simple in trivial extension.", + ), + array( + 'Universal template event ("all" style)', + 'event_universal.html', + array(), + array(), + array(), + "Universal in trivial extension.", + ), + ); } - public function test_universal_event() + /** + * @dataProvider template_data + */ + public function test_event($desc, $file, array $vars, array $block_vars, array $destroy, $expected) { // Reset the engine state $this->setup_engine(); - // Prepare correct result - $contents = "Universal in trivial extension."; - // Run test - $cache_file = $this->template->cachepath . 'event_universal.html.php'; - $this->run_template('event_universal.html', array(), array(), array(), $contents, $cache_file); + $cache_file = $this->template->cachepath . str_replace('/', '.', $file) . '.php'; + $this->run_template($file, $vars, $block_vars, $destroy, $expected, $cache_file); } protected function setup_engine(array $new_config = array()) From 9c31a0ffc785e30c4ff87e8d9d66e7989b55d8ef Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 11 May 2012 14:10:45 -0400 Subject: [PATCH 055/497] [feature/template-events] Rename template_name to style_name. "Style name" makes a lot more sense and should be in line with recent style/template changes. PHPBB3-9550 --- phpBB/includes/template/compile.php | 6 +++--- phpBB/includes/template/filter.php | 20 ++++++++++---------- phpBB/includes/template/template.php | 9 +++++---- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/phpBB/includes/template/compile.php b/phpBB/includes/template/compile.php index e2e9a095dc..c2762bfd59 100644 --- a/phpBB/includes/template/compile.php +++ b/phpBB/includes/template/compile.php @@ -36,17 +36,17 @@ class phpbb_template_compile * Constructor. * * @param bool $allow_php Whether PHP code will be allowed in templates (inline PHP code, PHP tag and INCLUDEPHP tag) - * @param string $template_name Name of top-level template being compiled + * @param string $style_name Name of style to which the template being compiled belongs * @param phpbb_style_resource_locator $locator Resource locator * @param string $phpbb_root_path Path to phpBB root directory * @param phpbb_extension_manager $extension_manager Extension manager to use for finding template fragments in extensions; if null, template hooks will not be invoked * @param phpbb_user $user Current user */ - public function __construct($allow_php, $template_name, $locator, $phpbb_root_path, $extension_manager = null, $user = null) + public function __construct($allow_php, $style_name, $locator, $phpbb_root_path, $extension_manager = null, $user = null) { $this->filter_params = array( 'allow_php' => $allow_php, - 'template_name' => $template_name, + 'style_name' => $style_name, 'locator' => $locator, 'phpbb_root_path' => $phpbb_root_path, 'extension_manager' => $extension_manager, diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 385612b094..a87bfaef34 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -88,14 +88,15 @@ class phpbb_template_filter extends php_user_filter private $phpbb_root_path; /** - * Name of the top-level template being compiled and/or rendered. + * Name of the style that the template being compiled and/or rendered + * belongs to. * - * This is used by hooks implementation to invoke template-specific + * This is used by hooks implementation to invoke style-specific * template hooks. * * @var string */ - private $template_name; + private $style_name; /** * Extension manager. @@ -168,7 +169,7 @@ class phpbb_template_filter extends php_user_filter /** * Initializer, called on creation. * - * Get the allow_php option, template_name, root directory and locator from params, + * Get the allow_php option, style_name, root directory and locator from params, * which are passed to stream_filter_append. */ public function onCreate() @@ -178,7 +179,7 @@ class phpbb_template_filter extends php_user_filter $this->allow_php = $this->params['allow_php']; $this->locator = $this->params['locator']; $this->phpbb_root_path = $this->params['phpbb_root_path']; - $this->template_name = $this->params['template_name']; + $this->style_name = $this->params['style_name']; $this->extension_manager = $this->params['extension_manager']; if (isset($this->params['user'])) { @@ -932,17 +933,16 @@ class phpbb_template_filter extends php_user_filter $files = array_merge($files, $finder ->extension_prefix($location) ->extension_suffix('.html') - ->extension_directory("/styles/" . $this->template_name . "/template") + ->extension_directory("/styles/" . $this->style_name . "/template") ->get_files()); $all_compiled = ''; foreach ($files as $file) { $compiled = $this->template_compile->compile_file($file); - if ($compiled === false) - { - trigger_error(sprintf('The file could not be compiled: %s', phpbb_filter_root_path($file)), E_USER_ERROR); - } + if ($compiled === false) { + trigger_error(sprintf('The file could not be compiled: %s', phpbb_filter_root_path($file)), E_USER_ERROR); + } $all_compiled .= $compiled; } // Need spaces inside php tags as php cannot grok diff --git a/phpBB/includes/template/template.php b/phpBB/includes/template/template.php index 19ee59323a..3de5cd45a5 100644 --- a/phpBB/includes/template/template.php +++ b/phpBB/includes/template/template.php @@ -82,14 +82,15 @@ class phpbb_template private $extension_manager; /** - * Name of the top-level template being compiled and/or rendered. + * Name of the style that the template being compiled and/or rendered + * belongs to. * - * This is used by hooks implementation to invoke template-specific + * This is used by hooks implementation to invoke style-specific * template hooks. * * @var string */ - private $template_name; + private $style_name; /** * Constructor. @@ -301,7 +302,7 @@ class phpbb_template return new phpbb_template_renderer_include($output_file, $this); } - $compile = new phpbb_template_compile($this->config['tpl_allow_php'], $this->template_name, $this->locator, $this->phpbb_root_path, $this->extension_manager, $this->user); + $compile = new phpbb_template_compile($this->config['tpl_allow_php'], $this->style_name, $this->locator, $this->phpbb_root_path, $this->extension_manager, $this->user); if ($compile->compile_file_to_file($source_file, $output_file) !== false) { From 2fb40060562dc7efcfda06cde05c2abb78a2c3c2 Mon Sep 17 00:00:00 2001 From: Nathan Guse Date: Wed, 31 Oct 2012 11:10:40 -0400 Subject: [PATCH 056/497] [feature/template-events] Indentation fix. PHPBB3-9550 --- phpBB/includes/template/filter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index a87bfaef34..8c102ea0fe 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -89,7 +89,7 @@ class phpbb_template_filter extends php_user_filter /** * Name of the style that the template being compiled and/or rendered - * belongs to. + * belongs to. * * This is used by hooks implementation to invoke style-specific * template hooks. From 4ed9e4124e592ddb7fe2696e45261e74edb89ddd Mon Sep 17 00:00:00 2001 From: Nathan Guse Date: Wed, 31 Oct 2012 11:11:33 -0400 Subject: [PATCH 057/497] [feature/template-events] Wording: wrongly -> improperly. PHPBB3-9550 --- phpBB/includes/template/filter.php | 4 ++-- phpBB/language/en/common.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 8c102ea0fe..8df43e5b01 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -908,14 +908,14 @@ class phpbb_template_filter extends php_user_filter { if (!preg_match('/^\w+$/', $tag_args)) { - // The hook location is wrongly formatted, + // The hook location is improperly formatted, if ($this->user) { trigger_error($this->user->lang('ERR_TEMPLATE_EVENT_LOCATION', $tag_args), E_USER_ERROR); } else { - trigger_error(sprintf('The specified template event location [%s] is wrongly formatted.', $tag_args), E_USER_ERROR); + trigger_error(sprintf('The specified template event location [%s] is improperly formatted.', $tag_args), E_USER_ERROR); } } $location = $tag_args; diff --git a/phpBB/language/en/common.php b/phpBB/language/en/common.php index 5fc1b21e4f..feb5c18d84 100644 --- a/phpBB/language/en/common.php +++ b/phpBB/language/en/common.php @@ -186,7 +186,7 @@ $lang = array_merge($lang, array( 'ERR_CONNECTING_SERVER' => 'Error connecting to the server.', 'ERR_JAB_AUTH' => 'Could not authorise on Jabber server.', 'ERR_JAB_CONNECT' => 'Could not connect to Jabber server.', - 'ERR_TEMPLATE_EVENT_LOCATION' => 'The specified template event location [%s] is wrongly formatted.', + 'ERR_TEMPLATE_EVENT_LOCATION' => 'The specified template event location [%s] is improperly formatted.', 'ERR_UNABLE_TO_LOGIN' => 'The specified username or password is incorrect.', 'ERR_UNWATCHING' => 'An error occured while trying to unsubscribe.', 'ERR_WATCHING' => 'An error occured while trying to subscribe.', From 6c7f1f7bdeba88fdef27fab537f973464bba6183 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 2 Nov 2012 19:58:01 -0400 Subject: [PATCH 058/497] [feature/template-events] Cosmetic changes. PHPBB3-9550 --- phpBB/includes/template/locator.php | 4 ++-- phpBB/includes/template/template.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/phpBB/includes/template/locator.php b/phpBB/includes/template/locator.php index 42db91efb2..f6fd20bcc2 100644 --- a/phpBB/includes/template/locator.php +++ b/phpBB/includes/template/locator.php @@ -39,7 +39,7 @@ interface phpbb_template_locator * Sets the template filenames for handles. $filename_array * should be a hash of handle => filename pairs. * - * @param array $filname_array Should be a hash of handle => filename pairs. + * @param array $filename_array Should be a hash of handle => filename pairs. */ public function set_filenames(array $filename_array); @@ -66,7 +66,7 @@ interface phpbb_template_locator * returns actually exists, it is faster than get_source_file_for_handle. * * Use get_source_file_for_handle to obtain the actual path that is - * guaranteed to exist (which might come from the parent style + * guaranteed to exist (which might come from the parent style * directory if primary style has parent styles). * * This function will trigger an error if the handle was never diff --git a/phpBB/includes/template/template.php b/phpBB/includes/template/template.php index 3de5cd45a5..52c08326d5 100644 --- a/phpBB/includes/template/template.php +++ b/phpBB/includes/template/template.php @@ -83,7 +83,7 @@ class phpbb_template /** * Name of the style that the template being compiled and/or rendered - * belongs to. + * belongs to. * * This is used by hooks implementation to invoke style-specific * template hooks. @@ -115,7 +115,7 @@ class phpbb_template /** * Sets the template filenames for handles. * - * @param array $filname_array Should be a hash of handle => filename pairs. + * @param array $filename_array Should be a hash of handle => filename pairs. */ public function set_filenames(array $filename_array) { From 0141154ceb58702a308c76b45242cc47f51d3e01 Mon Sep 17 00:00:00 2001 From: Nathan Guse Date: Wed, 31 Oct 2012 12:03:22 -0400 Subject: [PATCH 059/497] [feature/template-events] Indentation fix. PHPBB3-9550 --- phpBB/includes/template/filter.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 8df43e5b01..5d9e00553f 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -940,9 +940,12 @@ class phpbb_template_filter extends php_user_filter foreach ($files as $file) { $compiled = $this->template_compile->compile_file($file); - if ($compiled === false) { - trigger_error(sprintf('The file could not be compiled: %s', phpbb_filter_root_path($file)), E_USER_ERROR); - } + + if ($compiled === false) + { + trigger_error(sprintf('The file could not be compiled: %s', phpbb_filter_root_path($file)), E_USER_ERROR); + } + $all_compiled .= $compiled; } // Need spaces inside php tags as php cannot grok From 48adf8c5de7b946c1b0e10461605373a01d50196 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 31 Oct 2012 11:58:33 -0400 Subject: [PATCH 060/497] [feature/template-events] Create a dataset for template event tests. Having all files in one directory is too much of a mess. PHPBB3-9550 --- .../ext_trivial}/ext/trivial/styles/all/template/universal.html | 0 .../ext_trivial}/ext/trivial/styles/silver/template/simple.html | 0 .../{ => datasets/ext_trivial}/templates/event_simple.html | 0 .../{ => datasets/ext_trivial}/templates/event_universal.html | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename tests/template/{ => datasets/ext_trivial}/ext/trivial/styles/all/template/universal.html (100%) rename tests/template/{ => datasets/ext_trivial}/ext/trivial/styles/silver/template/simple.html (100%) rename tests/template/{ => datasets/ext_trivial}/templates/event_simple.html (100%) rename tests/template/{ => datasets/ext_trivial}/templates/event_universal.html (100%) diff --git a/tests/template/ext/trivial/styles/all/template/universal.html b/tests/template/datasets/ext_trivial/ext/trivial/styles/all/template/universal.html similarity index 100% rename from tests/template/ext/trivial/styles/all/template/universal.html rename to tests/template/datasets/ext_trivial/ext/trivial/styles/all/template/universal.html diff --git a/tests/template/ext/trivial/styles/silver/template/simple.html b/tests/template/datasets/ext_trivial/ext/trivial/styles/silver/template/simple.html similarity index 100% rename from tests/template/ext/trivial/styles/silver/template/simple.html rename to tests/template/datasets/ext_trivial/ext/trivial/styles/silver/template/simple.html diff --git a/tests/template/templates/event_simple.html b/tests/template/datasets/ext_trivial/templates/event_simple.html similarity index 100% rename from tests/template/templates/event_simple.html rename to tests/template/datasets/ext_trivial/templates/event_simple.html diff --git a/tests/template/templates/event_universal.html b/tests/template/datasets/ext_trivial/templates/event_universal.html similarity index 100% rename from tests/template/templates/event_universal.html rename to tests/template/datasets/ext_trivial/templates/event_universal.html From 9a7c8721ce2f23dc1bc5080cd8924f29a9545bd5 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 31 Oct 2012 11:59:12 -0400 Subject: [PATCH 061/497] [feature/template-events] Adjust template events test to use the dataset. PHPBB3-9550 --- tests/template/template_events_test.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/template/template_events_test.php b/tests/template/template_events_test.php index f1d13c1fd6..918de445d7 100644 --- a/tests/template/template_events_test.php +++ b/tests/template/template_events_test.php @@ -62,10 +62,10 @@ class phpbb_template_template_events_test extends phpbb_template_template_test_c $defaults = $this->config_defaults(); $config = new phpbb_config(array_merge($defaults, $new_config)); - $this->template_path = dirname(__FILE__) . '/templates'; + $this->template_path = dirname(__FILE__) . '/datasets/ext_trivial/templates'; $this->style_resource_locator = new phpbb_style_resource_locator(); $this->extension_manager = new phpbb_mock_extension_manager( - dirname(__FILE__) . '/', + dirname(__FILE__) . '/datasets/ext_trivial/', array( 'trivial' => array( 'ext_name' => 'trivial', From 0a29312d830c65dc293822c291bf2efd6f93a29b Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 8 Nov 2012 12:18:39 -0500 Subject: [PATCH 062/497] [feature/template-events] Chase dependency injection for template context. PHPBB3-9550 --- tests/template/template_events_test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/template/template_events_test.php b/tests/template/template_events_test.php index 918de445d7..274af7d7cf 100644 --- a/tests/template/template_events_test.php +++ b/tests/template/template_events_test.php @@ -74,7 +74,7 @@ class phpbb_template_template_events_test extends phpbb_template_template_test_c ), ) ); - $this->template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, $this->extension_manager); + $this->template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, new phpbb_template_context, $this->extension_manager); $this->style_provider = new phpbb_style_path_provider(); $this->style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, $this->style_provider, $this->template); $this->style->set_custom_style('tests', array($this->template_path), ''); From 44d6dc4c4ccf969fd3d84f3b39bfd24ecd3a3f9d Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 8 Nov 2012 12:21:06 -0500 Subject: [PATCH 063/497] [feature/template-events] Convert a single style name to array of them. This allows template code to know the entire style hierarchy for templates being rendered. PHPBB3-9550 --- phpBB/adm/index.php | 2 +- phpBB/adm/swatch.php | 2 +- phpBB/includes/functions_messenger.php | 2 +- phpBB/includes/style/style.php | 11 ++++++++++- phpBB/includes/template/compile.php | 6 +++--- phpBB/includes/template/filter.php | 13 ++++++------- phpBB/includes/template/template.php | 11 +++++------ phpBB/install/index.php | 2 +- phpBB/install/install_update.php | 2 +- tests/template/includephp_test.php | 2 +- tests/template/template_events_test.php | 2 +- tests/template/template_test_case.php | 2 +- tests/template/template_test_case_with_tree.php | 2 +- 13 files changed, 33 insertions(+), 26 deletions(-) diff --git a/phpBB/adm/index.php b/phpBB/adm/index.php index e20bbe4bec..0f84af6f9e 100644 --- a/phpBB/adm/index.php +++ b/phpBB/adm/index.php @@ -52,7 +52,7 @@ $mode = request_var('mode', ''); // Set custom style for admin area $phpbb_style->set_ext_dir_prefix('adm/'); -$phpbb_style->set_custom_style('admin', $phpbb_admin_path . 'style', ''); +$phpbb_style->set_custom_style('admin', $phpbb_admin_path . 'style', array(), ''); $template->assign_var('T_ASSETS_PATH', $phpbb_root_path . 'assets'); $template->assign_var('T_TEMPLATE_PATH', $phpbb_admin_path . 'style'); diff --git a/phpBB/adm/swatch.php b/phpBB/adm/swatch.php index 86498a255f..c01651e0f0 100644 --- a/phpBB/adm/swatch.php +++ b/phpBB/adm/swatch.php @@ -24,7 +24,7 @@ $user->setup(); $phpbb_admin_path = (defined('PHPBB_ADMIN_PATH')) ? PHPBB_ADMIN_PATH : './'; // Set custom template for admin area -$phpbb_style->set_custom_style('admin', $phpbb_admin_path . 'style', ''); +$phpbb_style->set_custom_style('admin', $phpbb_admin_path . 'style', array(), ''); $template->set_filenames(array( 'body' => 'colour_swatch.html') diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php index 55884caedb..2043e2f7be 100644 --- a/phpBB/includes/functions_messenger.php +++ b/phpBB/includes/functions_messenger.php @@ -231,7 +231,7 @@ class messenger } } - $style->set_custom_style($template_lang . '_email', array($template_path, $fallback_template_path), ''); + $style->set_custom_style($template_lang . '_email', array($template_path, $fallback_template_path), array(), ''); $tpl->set_filenames(array( 'body' => $template_file . '.txt', diff --git a/phpBB/includes/style/style.php b/phpBB/includes/style/style.php index effd496fb9..9ce96c5da5 100644 --- a/phpBB/includes/style/style.php +++ b/phpBB/includes/style/style.php @@ -110,18 +110,27 @@ class phpbb_style * * @param string $name Name of style, used for cache prefix. Examples: "admin", "prosilver" * @param array or string $paths Array of style paths, relative to current root directory + * @param array $names Array of names of templates in inheritance tree order, used by extensions. If empty, $name will be used. * @param string $template_path Path to templates, relative to style directory. False if path should be set to default (templates/). */ - public function set_custom_style($name, $paths, $template_path = false) + public function set_custom_style($name, $paths, $names = array(), $template_path = false) { if (is_string($paths)) { $paths = array($paths); } + if (empty($names)) + { + $names = array($name); + } + $this->names = $names; + $this->provider->set_styles($paths); $this->locator->set_paths($this->provider); + $this->template->style_names = $names; + if ($template_path !== false) { $this->locator->set_template_path($template_path); diff --git a/phpBB/includes/template/compile.php b/phpBB/includes/template/compile.php index c2762bfd59..76ad2317c9 100644 --- a/phpBB/includes/template/compile.php +++ b/phpBB/includes/template/compile.php @@ -36,17 +36,17 @@ class phpbb_template_compile * Constructor. * * @param bool $allow_php Whether PHP code will be allowed in templates (inline PHP code, PHP tag and INCLUDEPHP tag) - * @param string $style_name Name of style to which the template being compiled belongs + * @param array $style_names Name of style to which the template being compiled belongs and parents in style tree order * @param phpbb_style_resource_locator $locator Resource locator * @param string $phpbb_root_path Path to phpBB root directory * @param phpbb_extension_manager $extension_manager Extension manager to use for finding template fragments in extensions; if null, template hooks will not be invoked * @param phpbb_user $user Current user */ - public function __construct($allow_php, $style_name, $locator, $phpbb_root_path, $extension_manager = null, $user = null) + public function __construct($allow_php, $style_names, $locator, $phpbb_root_path, $extension_manager = null, $user = null) { $this->filter_params = array( 'allow_php' => $allow_php, - 'style_name' => $style_name, + 'style_names' => $style_names, 'locator' => $locator, 'phpbb_root_path' => $phpbb_root_path, 'extension_manager' => $extension_manager, diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 5d9e00553f..a5a0865569 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -89,14 +89,13 @@ class phpbb_template_filter extends php_user_filter /** * Name of the style that the template being compiled and/or rendered - * belongs to. + * belongs to, and its parents, in inheritance tree order. * - * This is used by hooks implementation to invoke style-specific - * template hooks. + * Used to invoke style-specific template events. * - * @var string + * @var array */ - private $style_name; + private $style_names; /** * Extension manager. @@ -169,7 +168,7 @@ class phpbb_template_filter extends php_user_filter /** * Initializer, called on creation. * - * Get the allow_php option, style_name, root directory and locator from params, + * Get the allow_php option, style_names, root directory and locator from params, * which are passed to stream_filter_append. */ public function onCreate() @@ -179,7 +178,7 @@ class phpbb_template_filter extends php_user_filter $this->allow_php = $this->params['allow_php']; $this->locator = $this->params['locator']; $this->phpbb_root_path = $this->params['phpbb_root_path']; - $this->style_name = $this->params['style_name']; + $this->style_names = $this->params['style_names']; $this->extension_manager = $this->params['extension_manager']; if (isset($this->params['user'])) { diff --git a/phpBB/includes/template/template.php b/phpBB/includes/template/template.php index 52c08326d5..4d257d2510 100644 --- a/phpBB/includes/template/template.php +++ b/phpBB/includes/template/template.php @@ -83,14 +83,13 @@ class phpbb_template /** * Name of the style that the template being compiled and/or rendered - * belongs to. + * belongs to, and its parents, in inheritance tree order. * - * This is used by hooks implementation to invoke style-specific - * template hooks. + * Used to invoke style-specific template events. * - * @var string + * @var array */ - private $style_name; + public $style_names; /** * Constructor. @@ -302,7 +301,7 @@ class phpbb_template return new phpbb_template_renderer_include($output_file, $this); } - $compile = new phpbb_template_compile($this->config['tpl_allow_php'], $this->style_name, $this->locator, $this->phpbb_root_path, $this->extension_manager, $this->user); + $compile = new phpbb_template_compile($this->config['tpl_allow_php'], $this->style_names, $this->locator, $this->phpbb_root_path, $this->extension_manager, $this->user); if ($compile->compile_file_to_file($source_file, $output_file) !== false) { diff --git a/phpBB/install/index.php b/phpBB/install/index.php index 09560946a6..2be5adaaac 100644 --- a/phpBB/install/index.php +++ b/phpBB/install/index.php @@ -215,7 +215,7 @@ $phpbb_style_path_provider = new phpbb_style_path_provider(); $template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $phpbb_style_resource_locator, new phpbb_template_context()); $phpbb_style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $phpbb_style_resource_locator, $phpbb_style_path_provider, $template); $phpbb_style->set_ext_dir_prefix('adm/'); -$phpbb_style->set_custom_style('admin', '../adm/style', ''); +$phpbb_style->set_custom_style('admin', '../adm/style', array(), ''); $template->assign_var('T_ASSETS_PATH', '../assets'); $template->assign_var('T_TEMPLATE_PATH', '../adm/style'); diff --git a/phpBB/install/install_update.php b/phpBB/install/install_update.php index 8c044550f3..3964dbfe2b 100644 --- a/phpBB/install/install_update.php +++ b/phpBB/install/install_update.php @@ -131,7 +131,7 @@ class install_update extends module } // Set custom template again. ;) - $phpbb_style->set_custom_style('admin', '../adm/style', ''); + $phpbb_style->set_custom_style('admin', '../adm/style', array(), ''); $template->assign_vars(array( 'S_USER_LANG' => $user->lang['USER_LANG'], diff --git a/tests/template/includephp_test.php b/tests/template/includephp_test.php index c93a53e2ad..f1012b6939 100644 --- a/tests/template/includephp_test.php +++ b/tests/template/includephp_test.php @@ -48,7 +48,7 @@ class phpbb_template_includephp_test extends phpbb_template_template_test_case $this->setup_engine(array('tpl_allow_php' => true)); - $this->style->set_custom_style('tests', $cache_dir, ''); + $this->style->set_custom_style('tests', $cache_dir, array(), ''); $cache_file = $this->template->cachepath . 'includephp_absolute.html.php'; $this->run_template('includephp_absolute.html', array(), array(), array(), "Path is absolute.\ntesting included php", $cache_file); diff --git a/tests/template/template_events_test.php b/tests/template/template_events_test.php index 274af7d7cf..22aa2e88d5 100644 --- a/tests/template/template_events_test.php +++ b/tests/template/template_events_test.php @@ -77,6 +77,6 @@ class phpbb_template_template_events_test extends phpbb_template_template_test_c $this->template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, new phpbb_template_context, $this->extension_manager); $this->style_provider = new phpbb_style_path_provider(); $this->style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, $this->style_provider, $this->template); - $this->style->set_custom_style('tests', array($this->template_path), ''); + $this->style->set_custom_style('silver', array($this->template_path), array(), ''); } } diff --git a/tests/template/template_test_case.php b/tests/template/template_test_case.php index 2e6f703eb1..3c997cb00e 100644 --- a/tests/template/template_test_case.php +++ b/tests/template/template_test_case.php @@ -69,7 +69,7 @@ class phpbb_template_template_test_case extends phpbb_test_case $this->style_provider = new phpbb_style_path_provider(); $this->template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, new phpbb_template_context()); $this->style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, $this->style_provider, $this->template); - $this->style->set_custom_style('tests', $this->template_path, ''); + $this->style->set_custom_style('tests', $this->template_path, array(), ''); } protected function setUp() diff --git a/tests/template/template_test_case_with_tree.php b/tests/template/template_test_case_with_tree.php index 6a226f317a..7585be5728 100644 --- a/tests/template/template_test_case_with_tree.php +++ b/tests/template/template_test_case_with_tree.php @@ -24,6 +24,6 @@ class phpbb_template_template_test_case_with_tree extends phpbb_template_templat $this->style_provider = new phpbb_style_path_provider(); $this->template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, new phpbb_template_context()); $this->style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, $this->style_provider, $this->template); - $this->style->set_custom_style('tests', array($this->template_path, $this->parent_template_path), ''); + $this->style->set_custom_style('tests', array($this->template_path, $this->parent_template_path), array(), ''); } } From 729eeef2bf4aad74c8170a54098e6679a1e9fadb Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 8 Nov 2012 12:22:15 -0500 Subject: [PATCH 064/497] [feature/template-events] Generate style names array in set_style. PHPBB3-9550 --- phpBB/includes/style/style.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/phpBB/includes/style/style.php b/phpBB/includes/style/style.php index 9ce96c5da5..6aec5c6ba4 100644 --- a/phpBB/includes/style/style.php +++ b/phpBB/includes/style/style.php @@ -91,16 +91,22 @@ class phpbb_style { $style_path = $this->user->style['style_path']; $style_dirs = ($this->user->style['style_parent_id']) ? array_reverse(explode('/', $this->user->style['style_parent_tree'])) : array(); - $paths = array($this->get_style_path($style_path)); + + $names = array($style_path); foreach ($style_dirs as $dir) { - $paths[] = $this->get_style_path($dir); + $names[] = $dir; + } + // Add 'all' path, used as last fallback path by hooks and extensions + //$names[] = 'all'; + + $paths = array(); + foreach ($names as $name) + { + $paths[] = $this->get_style_path($name); } - // Add 'all' path, used as last fallback path by hooks and extensions - $paths[] = $this->get_style_path('all'); - - return $this->set_custom_style($style_path, $paths); + return $this->set_custom_style($style_path, $names, $paths); } /** From af47779f51e44d34a78087327a3958fb35c50936 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 8 Nov 2012 12:22:39 -0500 Subject: [PATCH 065/497] [feature/template-events] Use style names array in template filter. This provides a straightforward way of iterating over all styles looking for templates in extensions. PHPBB3-9550 --- phpBB/includes/template/filter.php | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index a5a0865569..fd2ce9d859 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -929,11 +929,19 @@ class phpbb_template_filter extends php_user_filter ->extension_directory("/styles/all/template") ->get_files(); - $files = array_merge($files, $finder - ->extension_prefix($location) - ->extension_suffix('.html') - ->extension_directory("/styles/" . $this->style_name . "/template") - ->get_files()); + foreach ($this->style_names as $style_name) + { + $more_files = $finder + ->extension_prefix($location) + ->extension_suffix('.html') + ->extension_directory("/styles/" . $style_name . "/template") + ->get_files(); + if (!empty($more_files)) + { + $files = array_merge($files, $more_files); + break; + } + } $all_compiled = ''; foreach ($files as $file) From 99d93a3f0f0004b480a0d6b3b82bd59b64d24468 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 31 Oct 2012 13:02:48 -0400 Subject: [PATCH 066/497] [feature/template-events] Dataset for template event testing with inheritance. PHPBB3-9550 --- .../event_inheritance/ext/kappa/styles/all/template/test.html | 1 + .../event_inheritance/ext/kappa/styles/silver/template/test.html | 1 + .../ext/kappa/styles/silver_inherit/template/test.html | 1 + .../event_inheritance/ext/omega/styles/all/template/test.html | 1 + .../event_inheritance/ext/omega/styles/silver/template/test.html | 1 + .../event_inheritance/ext/zeta/styles/all/template/test.html | 1 + .../event_inheritance/styles/silver/template/event_test.html | 1 + .../styles/silver_inherit/template/event_test.html | 1 + 8 files changed, 8 insertions(+) create mode 100644 tests/template/datasets/event_inheritance/ext/kappa/styles/all/template/test.html create mode 100644 tests/template/datasets/event_inheritance/ext/kappa/styles/silver/template/test.html create mode 100644 tests/template/datasets/event_inheritance/ext/kappa/styles/silver_inherit/template/test.html create mode 100644 tests/template/datasets/event_inheritance/ext/omega/styles/all/template/test.html create mode 100644 tests/template/datasets/event_inheritance/ext/omega/styles/silver/template/test.html create mode 100644 tests/template/datasets/event_inheritance/ext/zeta/styles/all/template/test.html create mode 100644 tests/template/datasets/event_inheritance/styles/silver/template/event_test.html create mode 100644 tests/template/datasets/event_inheritance/styles/silver_inherit/template/event_test.html diff --git a/tests/template/datasets/event_inheritance/ext/kappa/styles/all/template/test.html b/tests/template/datasets/event_inheritance/ext/kappa/styles/all/template/test.html new file mode 100644 index 0000000000..3eb906a09e --- /dev/null +++ b/tests/template/datasets/event_inheritance/ext/kappa/styles/all/template/test.html @@ -0,0 +1 @@ +Kappa test event in all diff --git a/tests/template/datasets/event_inheritance/ext/kappa/styles/silver/template/test.html b/tests/template/datasets/event_inheritance/ext/kappa/styles/silver/template/test.html new file mode 100644 index 0000000000..3b65d80a6d --- /dev/null +++ b/tests/template/datasets/event_inheritance/ext/kappa/styles/silver/template/test.html @@ -0,0 +1 @@ +Kappa test event in silver diff --git a/tests/template/datasets/event_inheritance/ext/kappa/styles/silver_inherit/template/test.html b/tests/template/datasets/event_inheritance/ext/kappa/styles/silver_inherit/template/test.html new file mode 100644 index 0000000000..26826d59e3 --- /dev/null +++ b/tests/template/datasets/event_inheritance/ext/kappa/styles/silver_inherit/template/test.html @@ -0,0 +1 @@ +Kappa test event in silver_inherit diff --git a/tests/template/datasets/event_inheritance/ext/omega/styles/all/template/test.html b/tests/template/datasets/event_inheritance/ext/omega/styles/all/template/test.html new file mode 100644 index 0000000000..003d193dc3 --- /dev/null +++ b/tests/template/datasets/event_inheritance/ext/omega/styles/all/template/test.html @@ -0,0 +1 @@ +Omega test event in all diff --git a/tests/template/datasets/event_inheritance/ext/omega/styles/silver/template/test.html b/tests/template/datasets/event_inheritance/ext/omega/styles/silver/template/test.html new file mode 100644 index 0000000000..6bf06f5457 --- /dev/null +++ b/tests/template/datasets/event_inheritance/ext/omega/styles/silver/template/test.html @@ -0,0 +1 @@ +Omega test event in silver diff --git a/tests/template/datasets/event_inheritance/ext/zeta/styles/all/template/test.html b/tests/template/datasets/event_inheritance/ext/zeta/styles/all/template/test.html new file mode 100644 index 0000000000..5fc7e5ac12 --- /dev/null +++ b/tests/template/datasets/event_inheritance/ext/zeta/styles/all/template/test.html @@ -0,0 +1 @@ +Zeta test event in all diff --git a/tests/template/datasets/event_inheritance/styles/silver/template/event_test.html b/tests/template/datasets/event_inheritance/styles/silver/template/event_test.html new file mode 100644 index 0000000000..4d78dddb12 --- /dev/null +++ b/tests/template/datasets/event_inheritance/styles/silver/template/event_test.html @@ -0,0 +1 @@ + diff --git a/tests/template/datasets/event_inheritance/styles/silver_inherit/template/event_test.html b/tests/template/datasets/event_inheritance/styles/silver_inherit/template/event_test.html new file mode 100644 index 0000000000..4d78dddb12 --- /dev/null +++ b/tests/template/datasets/event_inheritance/styles/silver_inherit/template/event_test.html @@ -0,0 +1 @@ + From 0e6d12dfc41f97348ecf4b04943ed23e40f22f1b Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 8 Nov 2012 20:17:44 -0500 Subject: [PATCH 067/497] [feature/template-events] Allow dataset to be correctly selectable. PHPBB3-9550 --- tests/mock/filesystem_extension_manager.php | 31 +++++++++++++++++++++ tests/template/template_events_test.php | 22 ++++++--------- 2 files changed, 40 insertions(+), 13 deletions(-) create mode 100644 tests/mock/filesystem_extension_manager.php diff --git a/tests/mock/filesystem_extension_manager.php b/tests/mock/filesystem_extension_manager.php new file mode 100644 index 0000000000..3332e2b82d --- /dev/null +++ b/tests/mock/filesystem_extension_manager.php @@ -0,0 +1,31 @@ +isDir() && substr($fileinfo->getFilename(), 0, 1) != '.') + { + $name = $fileinfo->getFilename(); + $extension = array( + 'ext_name' => $name, + 'ext_active' => true, + 'ext_path' => 'ext/' . $name . '/', + ); + $extensions[$name] = $extension; + } + } + parent::__construct($phpbb_root_path, $extensions); + } +} diff --git a/tests/template/template_events_test.php b/tests/template/template_events_test.php index 22aa2e88d5..9652f341c3 100644 --- a/tests/template/template_events_test.php +++ b/tests/template/template_events_test.php @@ -17,6 +17,7 @@ class phpbb_template_template_events_test extends phpbb_template_template_test_c /* array( '', // File + '', // Dataset array(), // vars array(), // block vars array(), // destroy @@ -25,6 +26,7 @@ class phpbb_template_template_events_test extends phpbb_template_template_test_c */ array( 'Simple template event', + 'ext_trivial', 'event_simple.html', array(), array(), @@ -33,6 +35,7 @@ class phpbb_template_template_events_test extends phpbb_template_template_test_c ), array( 'Universal template event ("all" style)', + 'ext_trivial', 'event_universal.html', array(), array(), @@ -45,34 +48,27 @@ class phpbb_template_template_events_test extends phpbb_template_template_test_c /** * @dataProvider template_data */ - public function test_event($desc, $file, array $vars, array $block_vars, array $destroy, $expected) + public function test_event($desc, $dataset, $file, array $vars, array $block_vars, array $destroy, $expected) { // Reset the engine state - $this->setup_engine(); + $this->setup_engine_with_dataset($dataset); // Run test $cache_file = $this->template->cachepath . str_replace('/', '.', $file) . '.php'; $this->run_template($file, $vars, $block_vars, $destroy, $expected, $cache_file); } - protected function setup_engine(array $new_config = array()) + protected function setup_engine_with_dataset($dataset, array $new_config = array()) { global $phpbb_root_path, $phpEx, $user; $defaults = $this->config_defaults(); $config = new phpbb_config(array_merge($defaults, $new_config)); - $this->template_path = dirname(__FILE__) . '/datasets/ext_trivial/templates'; + $this->template_path = dirname(__FILE__) . "/datasets/$dataset/templates"; $this->style_resource_locator = new phpbb_style_resource_locator(); - $this->extension_manager = new phpbb_mock_extension_manager( - dirname(__FILE__) . '/datasets/ext_trivial/', - array( - 'trivial' => array( - 'ext_name' => 'trivial', - 'ext_active' => true, - 'ext_path' => 'ext/trivial/', - ), - ) + $this->extension_manager = new phpbb_mock_filesystem_extension_manager( + dirname(__FILE__) . "/datasets/$dataset/" ); $this->template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, new phpbb_template_context, $this->extension_manager); $this->style_provider = new phpbb_style_path_provider(); From 21a244543dbe960cdb97da61fa27dc61e6411932 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 8 Nov 2012 20:31:12 -0500 Subject: [PATCH 068/497] [feature/template-events] Normalize expected directory trees. PHPBB3-9550 --- .../{templates => styles/silver/template}/event_simple.html | 0 .../{templates => styles/silver/template}/event_universal.html | 0 tests/template/template_events_test.php | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename tests/template/datasets/ext_trivial/{templates => styles/silver/template}/event_simple.html (100%) rename tests/template/datasets/ext_trivial/{templates => styles/silver/template}/event_universal.html (100%) diff --git a/tests/template/datasets/ext_trivial/templates/event_simple.html b/tests/template/datasets/ext_trivial/styles/silver/template/event_simple.html similarity index 100% rename from tests/template/datasets/ext_trivial/templates/event_simple.html rename to tests/template/datasets/ext_trivial/styles/silver/template/event_simple.html diff --git a/tests/template/datasets/ext_trivial/templates/event_universal.html b/tests/template/datasets/ext_trivial/styles/silver/template/event_universal.html similarity index 100% rename from tests/template/datasets/ext_trivial/templates/event_universal.html rename to tests/template/datasets/ext_trivial/styles/silver/template/event_universal.html diff --git a/tests/template/template_events_test.php b/tests/template/template_events_test.php index 9652f341c3..15c8d846b8 100644 --- a/tests/template/template_events_test.php +++ b/tests/template/template_events_test.php @@ -65,7 +65,7 @@ class phpbb_template_template_events_test extends phpbb_template_template_test_c $defaults = $this->config_defaults(); $config = new phpbb_config(array_merge($defaults, $new_config)); - $this->template_path = dirname(__FILE__) . "/datasets/$dataset/templates"; + $this->template_path = dirname(__FILE__) . "/datasets/$dataset/styles/silver/template"; $this->style_resource_locator = new phpbb_style_resource_locator(); $this->extension_manager = new phpbb_mock_filesystem_extension_manager( dirname(__FILE__) . "/datasets/$dataset/" From 5f88bbbef3bfed93b4a575a1f2e58635b69f58e5 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 8 Nov 2012 20:38:01 -0500 Subject: [PATCH 069/497] [feature/template-events] Specify style names, add inheritance tests. PHPBB3-9550 --- tests/template/template_events_test.php | 44 +++++++++++++++++++++---- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/tests/template/template_events_test.php b/tests/template/template_events_test.php index 15c8d846b8..642745d53d 100644 --- a/tests/template/template_events_test.php +++ b/tests/template/template_events_test.php @@ -16,17 +16,19 @@ class phpbb_template_template_events_test extends phpbb_template_template_test_c return array( /* array( - '', // File - '', // Dataset + '', // file + '', // dataset + array(), // style names array(), // vars array(), // block vars array(), // destroy - '', // Expected result + '', // expected result ), */ array( 'Simple template event', 'ext_trivial', + array(), 'event_simple.html', array(), array(), @@ -36,29 +38,57 @@ class phpbb_template_template_events_test extends phpbb_template_template_test_c array( 'Universal template event ("all" style)', 'ext_trivial', + array(), 'event_universal.html', array(), array(), array(), "Universal in trivial extension.", ), + array( + 'Template event with inheritance - parent', + 'event_inheritance', + array('silver'), + 'event_test.html', + array(), + array(), + array(), +'Kappa test event in all +Omega test event in all +Zeta test event in all +Kappa test event in silver +Omega test event in silver', + ), + array( + 'Template event with inheritance - child', + 'event_inheritance', + array('silver_inherit', 'silver'), + 'event_test.html', + array(), + array(), + array(), +'Kappa test event in all +Omega test event in all +Zeta test event in all +Kappa test event in silver_inherit', + ), ); } /** * @dataProvider template_data */ - public function test_event($desc, $dataset, $file, array $vars, array $block_vars, array $destroy, $expected) + public function test_event($desc, $dataset, $style_names, $file, array $vars, array $block_vars, array $destroy, $expected) { // Reset the engine state - $this->setup_engine_with_dataset($dataset); + $this->setup_engine_for_events($dataset, $style_names); // Run test $cache_file = $this->template->cachepath . str_replace('/', '.', $file) . '.php'; $this->run_template($file, $vars, $block_vars, $destroy, $expected, $cache_file); } - protected function setup_engine_with_dataset($dataset, array $new_config = array()) + protected function setup_engine_for_events($dataset, $style_names, array $new_config = array()) { global $phpbb_root_path, $phpEx, $user; @@ -73,6 +103,6 @@ class phpbb_template_template_events_test extends phpbb_template_template_test_c $this->template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, new phpbb_template_context, $this->extension_manager); $this->style_provider = new phpbb_style_path_provider(); $this->style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, $this->style_provider, $this->template); - $this->style->set_custom_style('silver', array($this->template_path), array(), ''); + $this->style->set_custom_style('silver', array($this->template_path), $style_names, ''); } } From d42d71b47d76ab36d2c7a985f0b63c9c4686bfd0 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 8 Nov 2012 20:53:24 -0500 Subject: [PATCH 070/497] [feature/template-events] Test for event that is defined in parent style only. PHPBB3-9550 --- .../ext/omega/styles/silver/template/two.html | 1 + .../styles/silver/template/event_two.html | 1 + tests/template/template_events_test.php | 10 ++++++++++ 3 files changed, 12 insertions(+) create mode 100644 tests/template/datasets/event_inheritance/ext/omega/styles/silver/template/two.html create mode 100644 tests/template/datasets/event_inheritance/styles/silver/template/event_two.html diff --git a/tests/template/datasets/event_inheritance/ext/omega/styles/silver/template/two.html b/tests/template/datasets/event_inheritance/ext/omega/styles/silver/template/two.html new file mode 100644 index 0000000000..7f8058f4e4 --- /dev/null +++ b/tests/template/datasets/event_inheritance/ext/omega/styles/silver/template/two.html @@ -0,0 +1 @@ +two in silver in omega diff --git a/tests/template/datasets/event_inheritance/styles/silver/template/event_two.html b/tests/template/datasets/event_inheritance/styles/silver/template/event_two.html new file mode 100644 index 0000000000..fe46be3782 --- /dev/null +++ b/tests/template/datasets/event_inheritance/styles/silver/template/event_two.html @@ -0,0 +1 @@ + diff --git a/tests/template/template_events_test.php b/tests/template/template_events_test.php index 642745d53d..6cea9b92e3 100644 --- a/tests/template/template_events_test.php +++ b/tests/template/template_events_test.php @@ -72,6 +72,16 @@ Omega test event in all Zeta test event in all Kappa test event in silver_inherit', ), + array( + 'Definition in parent style', + 'event_inheritance', + array('silver_inherit', 'silver'), + 'event_two.html', + array(), + array(), + array(), +'two in silver in omega', + ), ); } From da7d888448cba2160b16010b982f886be9cb1bcb Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 8 Nov 2012 21:02:02 -0500 Subject: [PATCH 071/497] [feature/template-events] Make style names private on template. PHPBB3-9550 --- phpBB/includes/style/style.php | 2 +- phpBB/includes/template/template.php | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/phpBB/includes/style/style.php b/phpBB/includes/style/style.php index 6aec5c6ba4..7d31df9886 100644 --- a/phpBB/includes/style/style.php +++ b/phpBB/includes/style/style.php @@ -135,7 +135,7 @@ class phpbb_style $this->provider->set_styles($paths); $this->locator->set_paths($this->provider); - $this->template->style_names = $names; + $this->template->set_style_names($names); if ($template_path !== false) { diff --git a/phpBB/includes/template/template.php b/phpBB/includes/template/template.php index 4d257d2510..97e23f34e0 100644 --- a/phpBB/includes/template/template.php +++ b/phpBB/includes/template/template.php @@ -89,7 +89,7 @@ class phpbb_template * * @var array */ - public $style_names; + private $style_names; /** * Constructor. @@ -123,6 +123,18 @@ class phpbb_template return true; } + /** + * Sets the style names corresponding to style hierarchy being compiled + * and/or rendered. + * + * @param array $style_names List of style names in inheritance tree order + * @return null + */ + public function set_style_names(array $style_names) + { + $this->style_names = $style_names; + } + /** * Clears all variables and blocks assigned to this template. */ From 47a90f815d210d84f0c70ae678cb129e69963436 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 14 Nov 2012 17:31:05 -0500 Subject: [PATCH 072/497] [feature/template-events] Changes per imkingdavid's review. PHPBB3-9550 --- phpBB/includes/style/style.php | 2 +- phpBB/includes/template/compile.php | 2 +- phpBB/includes/template/filter.php | 15 +++++++++++++-- phpBB/includes/template/template.php | 2 +- phpBB/language/en/common.php | 1 + 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/phpBB/includes/style/style.php b/phpBB/includes/style/style.php index 7d31df9886..7c91edd034 100644 --- a/phpBB/includes/style/style.php +++ b/phpBB/includes/style/style.php @@ -97,7 +97,7 @@ class phpbb_style { $names[] = $dir; } - // Add 'all' path, used as last fallback path by hooks and extensions + // Add 'all' path, used as last fallback path by events and extensions //$names[] = 'all'; $paths = array(); diff --git a/phpBB/includes/template/compile.php b/phpBB/includes/template/compile.php index 76ad2317c9..ba7f45e41d 100644 --- a/phpBB/includes/template/compile.php +++ b/phpBB/includes/template/compile.php @@ -39,7 +39,7 @@ class phpbb_template_compile * @param array $style_names Name of style to which the template being compiled belongs and parents in style tree order * @param phpbb_style_resource_locator $locator Resource locator * @param string $phpbb_root_path Path to phpBB root directory - * @param phpbb_extension_manager $extension_manager Extension manager to use for finding template fragments in extensions; if null, template hooks will not be invoked + * @param phpbb_extension_manager $extension_manager Extension manager to use for finding template fragments in extensions; if null, template events will not be invoked * @param phpbb_user $user Current user */ public function __construct($allow_php, $style_names, $locator, $phpbb_root_path, $extension_manager = null, $user = null) diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index fd2ce9d859..f73ad28ba1 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -106,6 +106,7 @@ class phpbb_template_filter extends php_user_filter /** * Current user + * * @var phpbb_user */ private $user; @@ -170,6 +171,8 @@ class phpbb_template_filter extends php_user_filter * * Get the allow_php option, style_names, root directory and locator from params, * which are passed to stream_filter_append. + * + * @return boolean Returns true */ public function onCreate() { @@ -902,12 +905,13 @@ class phpbb_template_filter extends php_user_filter * such template fragments would have no effect. * * @param string $tag_args EVENT tag arguments, as a string - for EVENT this is the event name + * @return string compiled template code */ private function compile_tag_event($tag_args) { if (!preg_match('/^\w+$/', $tag_args)) { - // The hook location is improperly formatted, + // The event location is improperly formatted, if ($this->user) { trigger_error($this->user->lang('ERR_TEMPLATE_EVENT_LOCATION', $tag_args), E_USER_ERROR); @@ -950,7 +954,14 @@ class phpbb_template_filter extends php_user_filter if ($compiled === false) { - trigger_error(sprintf('The file could not be compiled: %s', phpbb_filter_root_path($file)), E_USER_ERROR); + if ($this->user) + { + trigger_error($this->user->lang('ERR_TEMPLATE_COMPILATION', phpbb_filter_root_path($file)), E_USER_ERROR); + } + else + { + trigger_error(sprintf('The file could not be compiled: %s', phpbb_filter_root_path($file)), E_USER_ERROR); + } } $all_compiled .= $compiled; diff --git a/phpBB/includes/template/template.php b/phpBB/includes/template/template.php index 97e23f34e0..bbec768613 100644 --- a/phpBB/includes/template/template.php +++ b/phpBB/includes/template/template.php @@ -98,7 +98,7 @@ class phpbb_template * @param user $user current user * @param phpbb_template_locator $locator template locator * @param phpbb_template_context $context template context - * @param phpbb_extension_manager $extension_manager extension manager, if null then template hooks will not be invoked + * @param phpbb_extension_manager $extension_manager extension manager, if null then template events will not be invoked */ public function __construct($phpbb_root_path, $php_ext, $config, $user, phpbb_template_locator $locator, phpbb_template_context $context, phpbb_extension_manager $extension_manager = null) { diff --git a/phpBB/language/en/common.php b/phpBB/language/en/common.php index feb5c18d84..6ebbb54c62 100644 --- a/phpBB/language/en/common.php +++ b/phpBB/language/en/common.php @@ -187,6 +187,7 @@ $lang = array_merge($lang, array( 'ERR_JAB_AUTH' => 'Could not authorise on Jabber server.', 'ERR_JAB_CONNECT' => 'Could not connect to Jabber server.', 'ERR_TEMPLATE_EVENT_LOCATION' => 'The specified template event location [%s] is improperly formatted.', + 'ERR_TEMPLATE_COMPILATION' => 'The file could not be compiled: %s', 'ERR_UNABLE_TO_LOGIN' => 'The specified username or password is incorrect.', 'ERR_UNWATCHING' => 'An error occured while trying to unsubscribe.', 'ERR_WATCHING' => 'An error occured while trying to subscribe.', From 29f7e729ed389f4312dbe8455d927a4bc2204f35 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 27 Nov 2012 11:11:50 -0500 Subject: [PATCH 073/497] [feature/template-events] Order extensions in mock extension manager. PHPBB3-9550 --- tests/mock/filesystem_extension_manager.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/mock/filesystem_extension_manager.php b/tests/mock/filesystem_extension_manager.php index 3332e2b82d..c5a51bbb3f 100644 --- a/tests/mock/filesystem_extension_manager.php +++ b/tests/mock/filesystem_extension_manager.php @@ -26,6 +26,7 @@ class phpbb_mock_filesystem_extension_manager extends phpbb_mock_extension_manag $extensions[$name] = $extension; } } + ksort($extensions); parent::__construct($phpbb_root_path, $extensions); } } From 83e85810aa7b04b992c8c24ec8b2eac700c4594e Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 6 Nov 2012 14:28:46 -0500 Subject: [PATCH 074/497] [ticket/11095] Use get method in jumpboxes. PHPBB3-11095 --- phpBB/styles/prosilver/template/jumpbox.html | 2 +- phpBB/styles/subsilver2/template/jumpbox.html | 2 +- phpBB/styles/subsilver2/template/mcp_jumpbox.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/phpBB/styles/prosilver/template/jumpbox.html b/phpBB/styles/prosilver/template/jumpbox.html index ff234464dc..562c115495 100644 --- a/phpBB/styles/prosilver/template/jumpbox.html +++ b/phpBB/styles/prosilver/template/jumpbox.html @@ -10,7 +10,7 @@ -
+
diff --git a/phpBB/styles/subsilver2/template/jumpbox.html b/phpBB/styles/subsilver2/template/jumpbox.html index f4153d7692..0a11524813 100644 --- a/phpBB/styles/subsilver2/template/jumpbox.html +++ b/phpBB/styles/subsilver2/template/jumpbox.html @@ -1,6 +1,6 @@ - + diff --git a/phpBB/styles/subsilver2/template/mcp_jumpbox.html b/phpBB/styles/subsilver2/template/mcp_jumpbox.html index 734222bc77..0e3433e3d6 100644 --- a/phpBB/styles/subsilver2/template/mcp_jumpbox.html +++ b/phpBB/styles/subsilver2/template/mcp_jumpbox.html @@ -1,6 +1,6 @@ - +{L_JUMP_TO}{L_COLON} "; + } + } + return $hidden; +} + /** * Generate page header */ function page_header($page_title = '', $display_online_list = true, $item_id = 0, $item = 'forum') { global $db, $config, $template, $SID, $_SID, $_EXTRA_URL, $user, $auth, $phpEx, $phpbb_root_path; - global $phpbb_dispatcher; + global $phpbb_dispatcher, $request; if (defined('HEADER_INC')) { @@ -5135,6 +5169,8 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 $timezone_name = $user->lang['timezones'][$timezone_name]; } + $hidden_fields_for_jumpbox = phpbb_build_hidden_fields_for_query_params($request, array('f')); + // The following assigns all _common_ variables that may be used at any point in a template. $template->assign_vars(array( 'SITENAME' => $config['sitename'], @@ -5149,6 +5185,7 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 'RECORD_USERS' => $l_online_record, 'PRIVATE_MESSAGE_INFO' => $l_privmsgs_text, 'PRIVATE_MESSAGE_INFO_UNREAD' => $l_privmsgs_text_unread, + 'HIDDEN_FIELDS_FOR_JUMPBOX' => $hidden_fields_for_jumpbox, 'S_USER_NEW_PRIVMSG' => $user->data['user_new_privmsg'], 'S_USER_UNREAD_PRIVMSG' => $user->data['user_unread_privmsg'], @@ -5507,7 +5544,8 @@ function phpbb_to_numeric($input) function phpbb_create_symfony_request(phpbb_request $request) { // This function is meant to sanitize the global input arrays - $sanitizer = function(&$value, $key) { + $sanitizer = function(&$value, $key) + { $type_cast_helper = new phpbb_request_type_cast_helper(); $type_cast_helper->set_var($value, $value, gettype($value), true); }; diff --git a/phpBB/styles/prosilver/template/jumpbox.html b/phpBB/styles/prosilver/template/jumpbox.html index 562c115495..dd793fbadc 100644 --- a/phpBB/styles/prosilver/template/jumpbox.html +++ b/phpBB/styles/prosilver/template/jumpbox.html @@ -17,6 +17,7 @@
+ {HIDDEN_FIELDS_FOR_JUMPBOX}
-
{L_SELECT_TOPICS_FROM}{L_MODERATE_FORUM}{L_JUMP_TO}{L_COLON} {HIDDEN_FIELDS_FOR_JUMPBOX}{L_SELECT_TOPICS_FROM}{L_MODERATE_FORUM}{L_JUMP_TO}{L_COLON}  From 3e907265d5782c535d43e503c32390cfde8dc4a8 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 29 Nov 2012 14:41:48 -0500 Subject: [PATCH 077/497] [ticket/11095] Docs and tests for phpbb_build_hidden_fields_for_query_params. PHPBB3-11095 --- phpBB/includes/functions.php | 14 ++++ ...ld_hidden_fields_for_query_params_test.php | 71 +++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 tests/functions/build_hidden_fields_for_query_params_test.php diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index ee5a1afd30..9c92adb0ec 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -4940,6 +4940,20 @@ function phpbb_quoteattr($data, $entities = null) return $data; } +/** +* Converts query string (GET) parameters in request into hidden fields. +* +* Useful for forwarding GET parameters when submitting forms with GET method. +* +* It is possible to omit some of the GET parameters, which is useful if +* they are specified in the form being submitted. +* +* sid is always omitted. +* +* @param phpbb_request $request Request object +* @param array $exclude A list of variable names that should not be forwarded +* @return string HTML with hidden fields +*/ function phpbb_build_hidden_fields_for_query_params($request, $exclude = null) { $names = $request->variable_names(phpbb_request_interface::GET); diff --git a/tests/functions/build_hidden_fields_for_query_params_test.php b/tests/functions/build_hidden_fields_for_query_params_test.php new file mode 100644 index 0000000000..ef2f5744d3 --- /dev/null +++ b/tests/functions/build_hidden_fields_for_query_params_test.php @@ -0,0 +1,71 @@ + 'bar'), + array(), + array(), + "", + ), + array( + array('foo' => 'bar', 'a' => 'b'), + array(), + array(), + "", + ), + array( + array('a' => 'quote"', 'b' => ''), + array(), + array(), + "", + ), + array( + array('a' => "quotes'\""), + array(), + array(), + "", + ), + array( + array('foo' => 'bar', 'a' => 'b'), + array('a' => 'c'), + array(), + "", + ), + // strict equality check + array( + array('foo' => 'bar', 'a' => '0'), + array('a' => ''), + array(), + "", + ), + ); + } + + /** + * @dataProvider build_hidden_fields_for_query_params_test_data + */ + public function test_build_hidden_fields_for_query_params($get, $post, $exclude, $expected) + { + $request = new phpbb_mock_request($get, $post); + $result = phpbb_build_hidden_fields_for_query_params($request, $exclude); + + $this->assertEquals($expected, $result); + } +} From 11ca272692ed1b46d4ff208705cb30636c98704f Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 29 Nov 2012 14:42:56 -0500 Subject: [PATCH 078/497] [ticket/11095] Restore brace on previous line. PHPBB3-11095 --- phpBB/includes/functions.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 9c92adb0ec..8df40b26f6 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -5558,8 +5558,7 @@ function phpbb_to_numeric($input) function phpbb_create_symfony_request(phpbb_request $request) { // This function is meant to sanitize the global input arrays - $sanitizer = function(&$value, $key) - { + $sanitizer = function(&$value, $key) { $type_cast_helper = new phpbb_request_type_cast_helper(); $type_cast_helper->set_var($value, $value, gettype($value), true); }; From d0338531cb2a3a386a3894a1b1b081025f53ea05 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 1 Dec 2012 20:12:31 -0500 Subject: [PATCH 079/497] [ticket/11162] An implementation that actually works. PHPBB3-11162 --- phpBB/includes/functions.php | 73 +++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 8608c6ca4f..13690e79bb 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -1311,12 +1311,75 @@ function tz_select($default = '', $truncate = false) */ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_values, $to_value) { - $db->sql_return_on_error(true); - $condition = $db->sql_in_set($column, $from_values); - $db->sql_query('UPDATE ' . $table . ' SET ' . $column . ' = ' . (int) $to_value. ' WHERE ' . $condition); - $db->sql_return_on_error(false); + $sql = "SELECT $column, user_id + FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $result = $db->sql_query($sql); - $db->sql_query('DELETE FROM ' . $table . ' WHERE ' . $condition); + $old_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $old_user_ids[$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $sql = "SELECT $column, user_id + FROM $table + WHERE $column = '" . (int) $to_value . "'"; + $result = $db->sql_query($sql); + + $new_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $new_user_ids[$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $queries = array(); + $any_found = false; + foreach ($from_values as $from_value) + { + if (!isset($old_user_ids[$from_value])) + { + continue; + } + $any_found = true; + if (empty($new_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value. " + WHERE $column = '" . $db->sql_escape($from_value) . "'"; + $queries[] = $sql; + } + else + { + $different_user_ids = array_diff($old_user_ids[$from_value], $new_user_ids[$to_value]); + if (!empty($different_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value. " + WHERE $column = '" . $db->sql_escape($from_value) . "' + AND " . $db->sql_in_set('user_id', $different_user_ids); + $queries[] = $sql; + } + } + } + + if ($any_found) + { + //$db->sql_transaction('begin'); + + foreach ($queries as $sql) + { + $db->sql_query($sql); + } + + $sql = "DELETE FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $db->sql_query($sql); + + //$db->sql_transaction('commit'); + } } // Functions handling topic/post tracking/marking From 2e947334e563f122c597d7072eddd962453a84ef Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 1 Dec 2012 20:17:01 -0500 Subject: [PATCH 080/497] [ticket/11162] Uncomment transactions. PHPBB3-11162 --- phpBB/includes/functions.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 13690e79bb..a24dcfdf5b 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -1367,7 +1367,7 @@ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_value if ($any_found) { - //$db->sql_transaction('begin'); + $db->sql_transaction('begin'); foreach ($queries as $sql) { @@ -1378,7 +1378,7 @@ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_value WHERE " . $db->sql_in_set($column, $from_values); $db->sql_query($sql); - //$db->sql_transaction('commit'); + $db->sql_transaction('commit'); } } From c2c105df9ff1d8fd48afa1d3abdf23a39584d7ed Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 1 Dec 2012 20:21:29 -0500 Subject: [PATCH 081/497] [ticket/11162] Clarify that only the two tables actually work. PHPBB3-11162 --- phpBB/includes/functions.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index a24dcfdf5b..09487ce10d 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -1302,6 +1302,8 @@ function tz_select($default = '', $truncate = false) * If this results in rows violating uniqueness constraints, the duplicate * rows are eliminated. * +* The only supported tables are bookmarks and topics_watch. +* * @param dbal $db Database object * @param string $table Table on which to perform the update * @param string $column Column whose values to change From 69225bd0a6005e81b7cb58631eb5de7c3d175697 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 1 Dec 2012 20:21:51 -0500 Subject: [PATCH 082/497] [ticket/11162] Use phpbb_update_rows_avoiding_duplicates in mcp. PHPBB3-11162 --- phpBB/includes/mcp/mcp_forum.php | 7 +------ phpBB/includes/mcp/mcp_topic.php | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index b70601b479..913c55a9d1 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -415,12 +415,7 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) $success_msg = 'POSTS_MERGED_SUCCESS'; // If the topic no longer exist, we will update the topic watch table. - // To not let it error out on users watching both topics, we just return on an error... - $db->sql_return_on_error(true); - $db->sql_query('UPDATE ' . TOPICS_WATCH_TABLE . ' SET topic_id = ' . (int) $to_topic_id . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); - $db->sql_return_on_error(false); - - $db->sql_query('DELETE FROM ' . TOPICS_WATCH_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); + phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); // Link to the new topic $return_link .= (($return_link) ? '

' : '') . sprintf($user->lang['RETURN_NEW_TOPIC'], '', ''); diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index 7d4edaf362..f40a4bc044 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -620,12 +620,7 @@ function merge_posts($topic_id, $to_topic_id) else { // If the topic no longer exist, we will update the topic watch table. - // To not let it error out on users watching both topics, we just return on an error... - $db->sql_return_on_error(true); - $db->sql_query('UPDATE ' . TOPICS_WATCH_TABLE . ' SET topic_id = ' . (int) $to_topic_id . ' WHERE topic_id = ' . (int) $topic_id); - $db->sql_return_on_error(false); - - $db->sql_query('DELETE FROM ' . TOPICS_WATCH_TABLE . ' WHERE topic_id = ' . (int) $topic_id); + phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); } // Link to the new topic From 05053dacd350c6bacd529df803bdc9876104a278 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 1 Dec 2012 20:24:25 -0500 Subject: [PATCH 083/497] [ticket/11162] Fix inaccurately copy pasted comment. PHPBB3-11162 --- phpBB/includes/mcp/mcp_forum.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index 913c55a9d1..e392bef157 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -414,7 +414,7 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) // Message and return links $success_msg = 'POSTS_MERGED_SUCCESS'; - // If the topic no longer exist, we will update the topic watch table. + // Update the topic watch table. phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); // Link to the new topic From 2fc43e6ed71e4b9abdb76aa179b4e64efaa47ffa Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 1 Dec 2012 23:11:14 -0500 Subject: [PATCH 084/497] [ticket/11162] No whitespace changes in olympus. PHPBB3-11162 --- phpBB/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 09487ce10d..e3feb59d41 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3442,7 +3442,7 @@ function parse_cfg_file($filename, $lines = false) $parsed_items[$key] = $value; } - + if (isset($parsed_items['inherit_from']) && isset($parsed_items['name']) && $parsed_items['inherit_from'] == $parsed_items['name']) { unset($parsed_items['inherit_from']); From e765ccd075a19be7ec9c60970677d62dc75f0845 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 04:22:10 -0500 Subject: [PATCH 085/497] [ticket/11015] Include dbms name in exception message. PHPBB3-11015 --- phpBB/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 57136a43ff..501257956a 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -5431,5 +5431,5 @@ function phpbb_convert_30_dbms_to_31($dbms) return 'phpbb_db_driver_' . $dbms; } - throw new \RuntimeException('You have specified an invalid dbms driver.'); + throw new \RuntimeException("You have specified an invalid dbms driver: $dbms"); } From 3687febdacc9b1629fd6f09e15305d61eacc9b78 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 04:29:31 -0500 Subject: [PATCH 086/497] [ticket/11015] Change more docblocks. PHPBB3-11015 --- phpBB/includes/db/db_tools.php | 2 +- phpBB/includes/extension/manager.php | 2 +- phpBB/includes/extension/metadata_manager.php | 2 +- phpBB/includes/functions_download.php | 8 ++++---- phpBB/includes/lock/db.php | 4 ++-- phpBB/includes/search/fulltext_mysql.php | 4 ++-- phpBB/includes/search/fulltext_native.php | 4 ++-- phpBB/includes/search/fulltext_postgres.php | 4 ++-- phpBB/includes/search/fulltext_sphinx.php | 4 ++-- tests/session/testable_factory.php | 2 +- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index 6df3aac9ce..2bb016cebd 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -300,7 +300,7 @@ class phpbb_db_tools /** * Constructor. Set DB Object and set {@link $return_statements return_statements}. * - * @param phpbb_dbal $db DBAL object + * @param phpbb_db_driver $db Database connection * @param bool $return_statements True if only statements should be returned and no SQL being executed */ function phpbb_db_tools(&$db, $return_statements = false) diff --git a/phpBB/includes/extension/manager.php b/phpBB/includes/extension/manager.php index 862bca1855..67cc81e407 100644 --- a/phpBB/includes/extension/manager.php +++ b/phpBB/includes/extension/manager.php @@ -34,7 +34,7 @@ class phpbb_extension_manager /** * Creates a manager and loads information from database * - * @param dbal $db A database connection + * @param phpbb_db_driver $db A database connection * @param phpbb_config $config phpbb_config * @param string $extension_table The name of the table holding extensions * @param string $phpbb_root_path Path to the phpbb includes directory. diff --git a/phpBB/includes/extension/metadata_manager.php b/phpBB/includes/extension/metadata_manager.php index 813459eb67..36b0f8b184 100644 --- a/phpBB/includes/extension/metadata_manager.php +++ b/phpBB/includes/extension/metadata_manager.php @@ -34,7 +34,7 @@ class phpbb_extension_metadata_manager /** * Creates the metadata manager * - * @param dbal $db A database connection + * @param phpbb_db_driver $db A database connection * @param string $extension_manager An instance of the phpbb extension manager * @param string $phpbb_root_path Path to the phpbb includes directory. * @param string $phpEx php file extension diff --git a/phpBB/includes/functions_download.php b/phpBB/includes/functions_download.php index b6371dbecc..89bcf7c8d9 100644 --- a/phpBB/includes/functions_download.php +++ b/phpBB/includes/functions_download.php @@ -596,7 +596,7 @@ function phpbb_parse_range_request($request_array, $filesize) /** * Increments the download count of all provided attachments * -* @param dbal $db The database object +* @param phpbb_db_driver $db The database object * @param array|int $ids The attach_id of each attachment * * @return null @@ -617,7 +617,7 @@ function phpbb_increment_downloads($db, $ids) /** * Handles authentication when downloading attachments from a post or topic * -* @param dbal $db The database object +* @param phpbb_db_driver $db The database object * @param phpbb_auth $auth The authentication object * @param int $topic_id The id of the topic that we are downloading from * @@ -651,7 +651,7 @@ function phpbb_download_handle_forum_auth($db, $auth, $topic_id) /** * Handles authentication when downloading attachments from PMs * -* @param dbal $db The database object +* @param phpbb_db_driver $db The database object * @param phpbb_auth $auth The authentication object * @param int $user_id The user id * @param int $msg_id The id of the PM that we are downloading from @@ -678,7 +678,7 @@ function phpbb_download_handle_pm_auth($db, $auth, $user_id, $msg_id) /** * Checks whether a user can download from a particular PM * -* @param dbal $db The database object +* @param phpbb_db_driver $db The database object * @param int $user_id The user id * @param int $msg_id The id of the PM that we are downloading from * diff --git a/phpBB/includes/lock/db.php b/phpBB/includes/lock/db.php index 40690144b1..2bb2e25f97 100644 --- a/phpBB/includes/lock/db.php +++ b/phpBB/includes/lock/db.php @@ -48,7 +48,7 @@ class phpbb_lock_db /** * A database connection - * @var dbal + * @var phpbb_db_driver */ private $db; @@ -59,7 +59,7 @@ class phpbb_lock_db * * @param string $config_name A config variable to be used for locking * @param array $config The phpBB configuration - * @param dbal $db A database connection + * @param phpbb_db_driver $db A database connection */ public function __construct($config_name, phpbb_config $config, phpbb_db_driver $db) { diff --git a/phpBB/includes/search/fulltext_mysql.php b/phpBB/includes/search/fulltext_mysql.php index 58a4dd7d6a..693f663f23 100644 --- a/phpBB/includes/search/fulltext_mysql.php +++ b/phpBB/includes/search/fulltext_mysql.php @@ -41,8 +41,8 @@ class phpbb_search_fulltext_mysql extends phpbb_search_base protected $config; /** - * DBAL object - * @var dbal + * Database connection + * @var phpbb_db_driver */ protected $db; diff --git a/phpBB/includes/search/fulltext_native.php b/phpBB/includes/search/fulltext_native.php index 4623326fc7..53df8348ae 100644 --- a/phpBB/includes/search/fulltext_native.php +++ b/phpBB/includes/search/fulltext_native.php @@ -85,8 +85,8 @@ class phpbb_search_fulltext_native extends phpbb_search_base protected $config; /** - * DBAL object - * @var dbal + * Database connection + * @var phpbb_db_driver */ protected $db; diff --git a/phpBB/includes/search/fulltext_postgres.php b/phpBB/includes/search/fulltext_postgres.php index 08f64735b6..cf613076d0 100644 --- a/phpBB/includes/search/fulltext_postgres.php +++ b/phpBB/includes/search/fulltext_postgres.php @@ -66,8 +66,8 @@ class phpbb_search_fulltext_postgres extends phpbb_search_base protected $config; /** - * DBAL object - * @var dbal + * Database connection + * @var phpbb_db_driver */ protected $db; diff --git a/phpBB/includes/search/fulltext_sphinx.php b/phpBB/includes/search/fulltext_sphinx.php index dd5634b623..a84a64825c 100644 --- a/phpBB/includes/search/fulltext_sphinx.php +++ b/phpBB/includes/search/fulltext_sphinx.php @@ -84,8 +84,8 @@ class phpbb_search_fulltext_sphinx protected $config; /** - * DBAL object - * @var dbal + * Database connection + * @var phpbb_db_driver */ protected $db; diff --git a/tests/session/testable_factory.php b/tests/session/testable_factory.php index 0b42255562..1e2b194ece 100644 --- a/tests/session/testable_factory.php +++ b/tests/session/testable_factory.php @@ -59,7 +59,7 @@ class phpbb_session_testable_factory /** * Retrieve the configured session class instance * - * @param dbal $dbal The database connection to use for session data + * @param phpbb_db_driver $dbal The database connection to use for session data * @return phpbb_mock_session_testable A session instance */ public function get_session(phpbb_db_driver $dbal) From 74093d0fd383619ec8b58914ebe2edd68145e070 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 04:32:37 -0500 Subject: [PATCH 087/497] [ticket/11015] Fix functional test case. PHPBB3-11015 --- tests/test_framework/phpbb_functional_test_case.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index f9c1d64ff8..2a24e96a25 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -86,7 +86,7 @@ class phpbb_functional_test_case extends phpbb_test_case { global $phpbb_root_path, $phpEx; // so we don't reopen an open connection - if (!($this->db instanceof dbal)) + if (!($this->db instanceof phpbb_db_driver)) { $dbms = self::$config['dbms']; $this->db = new $dbms(); From 025a95ea909d449e14cb22564983fb005e3f8c06 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 9 Mar 2011 21:50:45 -0500 Subject: [PATCH 088/497] [ticket/10205] Account for potentially missing extensions in dbal. PHPBB3-10205 --- phpBB/includes/db/mssql_odbc.php | 20 +++++++++++++++++++- phpBB/includes/db/mysql.php | 20 +++++++++++++++++++- phpBB/includes/db/mysqli.php | 7 +++++++ phpBB/includes/db/oracle.php | 29 ++++++++++++++++++++++++++++- phpBB/includes/db/sqlite.php | 21 ++++++++++++++++++++- 5 files changed, 93 insertions(+), 4 deletions(-) diff --git a/phpBB/includes/db/mssql_odbc.php b/phpBB/includes/db/mssql_odbc.php index 2ecc42cadf..dabdbd1a44 100644 --- a/phpBB/includes/db/mssql_odbc.php +++ b/phpBB/includes/db/mssql_odbc.php @@ -32,6 +32,7 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); class dbal_mssql_odbc extends dbal { var $last_query_text = ''; + var $connect_error = ''; /** * Connect to server @@ -68,7 +69,24 @@ class dbal_mssql_odbc extends dbal @ini_set('odbc.defaultlrl', $max_size); } - $this->db_connect_id = ($this->persistency) ? @odbc_pconnect($this->server, $this->user, $sqlpassword) : @odbc_connect($this->server, $this->user, $sqlpassword); + if ($this->persistency) + { + if (!function_exists('odbc_pconnect')) + { + $this->connect_error = 'odbc_pconnect function does not exist, is odbc extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @odbc_pconnect($this->server, $this->user, $sqlpassword); + } + else + { + if (!function_exists('odbc_connect')) + { + $this->connect_error = 'odbc_connect function does not exist, is odbc extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @odbc_connect($this->server, $this->user, $sqlpassword); + } return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); } diff --git a/phpBB/includes/db/mysql.php b/phpBB/includes/db/mysql.php index 1ccb785150..ae36fe6425 100644 --- a/phpBB/includes/db/mysql.php +++ b/phpBB/includes/db/mysql.php @@ -30,6 +30,7 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); class dbal_mysql extends dbal { var $multi_insert = true; + var $connect_error = ''; /** * Connect to server @@ -44,7 +45,24 @@ class dbal_mysql extends dbal $this->sql_layer = 'mysql4'; - $this->db_connect_id = ($this->persistency) ? @mysql_pconnect($this->server, $this->user, $sqlpassword) : @mysql_connect($this->server, $this->user, $sqlpassword, $new_link); + if ($this->persistency) + { + if (!function_exists('mysql_pconnect')) + { + $this->connect_error = 'mysql_pconnect function does not exist, is mysql extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @mysql_pconnect($this->server, $this->user, $sqlpassword); + } + else + { + if (!function_exists('mysql_connect')) + { + $this->connect_error = 'mysql_connect function does not exist, is mysql extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @mysql_connect($this->server, $this->user, $sqlpassword, $new_link); + } if ($this->db_connect_id && $this->dbname != '') { diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/mysqli.php index a311b8cda6..98b659723f 100644 --- a/phpBB/includes/db/mysqli.php +++ b/phpBB/includes/db/mysqli.php @@ -27,12 +27,19 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); class dbal_mysqli extends dbal { var $multi_insert = true; + var $connect_error = ''; /** * Connect to server */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false , $new_link = false) { + if (!function_exists('mysqli_connect')) + { + $this->connect_error = 'mysqli_connect function does not exist, is mysqli extension installed?'; + 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->user = $sqluser; diff --git a/phpBB/includes/db/oracle.php b/phpBB/includes/db/oracle.php index 62b36aa8bf..42f5de1b24 100644 --- a/phpBB/includes/db/oracle.php +++ b/phpBB/includes/db/oracle.php @@ -25,6 +25,7 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); class dbal_oracle extends dbal { var $last_query_text = ''; + var $connect_error = ''; /** * Connect to server @@ -48,7 +49,33 @@ class dbal_oracle extends dbal $connect = $sqlserver . (($port) ? ':' . $port : '') . '/' . $database; } - $this->db_connect_id = ($new_link) ? @ocinlogon($this->user, $sqlpassword, $connect, 'UTF8') : (($this->persistency) ? @ociplogon($this->user, $sqlpassword, $connect, 'UTF8') : @ocilogon($this->user, $sqlpassword, $connect, 'UTF8')); + if ($new_link) + { + if (!function_exists('ocinlogon')) + { + $this->connect_error = 'ocinlogon function does not exist, is oci extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @ocinlogon($this->user, $sqlpassword, $connect, 'UTF8'); + } + else if ($this->persistency) + { + if (!function_exists('ociplogon')) + { + $this->connect_error = 'ociplogon function does not exist, is oci extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @ociplogon($this->user, $sqlpassword, $connect, 'UTF8'); + } + else + { + if (!function_exists('ocilogon')) + { + $this->connect_error = 'ocilogon function does not exist, is oci extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @ocilogon($this->user, $sqlpassword, $connect, 'UTF8')); + } return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); } diff --git a/phpBB/includes/db/sqlite.php b/phpBB/includes/db/sqlite.php index 8de72fd394..be0ad4fc8f 100644 --- a/phpBB/includes/db/sqlite.php +++ b/phpBB/includes/db/sqlite.php @@ -25,6 +25,8 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); */ class dbal_sqlite extends dbal { + var $connect_error = ''; + /** * Connect to server */ @@ -36,7 +38,24 @@ class dbal_sqlite extends dbal $this->dbname = $database; $error = ''; - $this->db_connect_id = ($this->persistency) ? @sqlite_popen($this->server, 0666, $error) : @sqlite_open($this->server, 0666, $error); + if ($this->persistency) + { + if (!function_exists('sqlite_popen')) + { + $this->connect_error = 'sqlite_popen function does not exist, is sqlite extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @sqlite_popen($this->server, 0666, $error); + } + else + { + if (!function_exists('sqlite_open')) + { + $this->connect_error = 'sqlite_open function does not exist, is sqlite extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @sqlite_open($this->server, 0666, $error); + } if ($this->db_connect_id) { From 1a7e2211c35218094e30ddc399d4aa6b45fe75f4 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 04:06:30 -0500 Subject: [PATCH 089/497] [ticket/10205] Avoid calling mysqli functions when mysqli is missing. PHPBB3-10205 --- phpBB/includes/db/mysqli.php | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/mysqli.php index 98b659723f..cd82a12b58 100644 --- a/phpBB/includes/db/mysqli.php +++ b/phpBB/includes/db/mysqli.php @@ -425,10 +425,20 @@ class dbal_mysqli extends dbal { if (!$this->db_connect_id) { - return array( - 'message' => @mysqli_connect_error(), - 'code' => @mysqli_connect_errno() - ); + if (function_exists('mysqli_connect_error')) + { + return array( + 'message' => @mysqli_connect_error(), + 'code' => @mysqli_connect_errno(), + ); + } + else + { + return array( + 'message' => $this->connect_error, + 'code' => '', + ); + } } return array( From 9f549e8249acbd82b68e961a6e0a31de47d9ca32 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 04:50:41 -0500 Subject: [PATCH 090/497] [ticket/10205] Fix remaining db drivers. PHPBB3-10205 --- phpBB/includes/db/mssql.php | 58 +++++++++++++++++++------------- phpBB/includes/db/mssql_odbc.php | 18 +++++++--- phpBB/includes/db/mysql.php | 18 +++++++--- phpBB/includes/db/oracle.php | 24 +++++++++---- phpBB/includes/db/sqlite.php | 18 +++++++--- 5 files changed, 93 insertions(+), 43 deletions(-) diff --git a/phpBB/includes/db/mssql.php b/phpBB/includes/db/mssql.php index b7178593dc..bc0a870885 100644 --- a/phpBB/includes/db/mssql.php +++ b/phpBB/includes/db/mssql.php @@ -355,34 +355,44 @@ class dbal_mssql extends dbal */ function _sql_error() { - $error = array( - 'message' => @mssql_get_last_message(), - 'code' => '' - ); - - // Get error code number - $result_id = @mssql_query('SELECT @@ERROR as code', $this->db_connect_id); - if ($result_id) + if (function_exists('mssql_get_last_message')) { - $row = @mssql_fetch_assoc($result_id); - $error['code'] = $row['code']; - @mssql_free_result($result_id); - } + $error = array( + 'message' => @mssql_get_last_message(), + 'code' => '' + ); - // Get full error message if possible - $sql = 'SELECT CAST(description as varchar(255)) as message - FROM master.dbo.sysmessages - WHERE error = ' . $error['code']; - $result_id = @mssql_query($sql); - - if ($result_id) - { - $row = @mssql_fetch_assoc($result_id); - if (!empty($row['message'])) + // Get error code number + $result_id = @mssql_query('SELECT @@ERROR as code', $this->db_connect_id); + if ($result_id) { - $error['message'] .= '
' . $row['message']; + $row = @mssql_fetch_assoc($result_id); + $error['code'] = $row['code']; + @mssql_free_result($result_id); } - @mssql_free_result($result_id); + + // Get full error message if possible + $sql = 'SELECT CAST(description as varchar(255)) as message + FROM master.dbo.sysmessages + WHERE error = ' . $error['code']; + $result_id = @mssql_query($sql); + + if ($result_id) + { + $row = @mssql_fetch_assoc($result_id); + if (!empty($row['message'])) + { + $error['message'] .= '
' . $row['message']; + } + @mssql_free_result($result_id); + } + } + else + { + $error = array( + 'message' => $this->connect_error, + 'code' => '', + ); } return $error; diff --git a/phpBB/includes/db/mssql_odbc.php b/phpBB/includes/db/mssql_odbc.php index dabdbd1a44..e1234389df 100644 --- a/phpBB/includes/db/mssql_odbc.php +++ b/phpBB/includes/db/mssql_odbc.php @@ -360,10 +360,20 @@ class dbal_mssql_odbc extends dbal */ function _sql_error() { - return array( - 'message' => @odbc_errormsg(), - 'code' => @odbc_error() - ); + if (function_exists('odbc_errormsg')) + { + return array( + 'message' => @odbc_errormsg(), + 'code' => @odbc_error() + ); + } + else + { + return array( + 'message' => $this->connect_error, + 'code' => '', + ); + } } /** diff --git a/phpBB/includes/db/mysql.php b/phpBB/includes/db/mysql.php index ae36fe6425..7314e92087 100644 --- a/phpBB/includes/db/mysql.php +++ b/phpBB/includes/db/mysql.php @@ -439,10 +439,20 @@ class dbal_mysql extends dbal { if (!$this->db_connect_id) { - return array( - 'message' => @mysql_error(), - 'code' => @mysql_errno() - ); + if (function_exists('mysql_error')) + { + return array( + 'message' => @mysql_error(), + 'code' => @mysql_errno() + ); + } + else + { + return array( + 'message' => $this->connect_error, + 'code' => '', + ); + } } return array( diff --git a/phpBB/includes/db/oracle.php b/phpBB/includes/db/oracle.php index 42f5de1b24..b234d8b45e 100644 --- a/phpBB/includes/db/oracle.php +++ b/phpBB/includes/db/oracle.php @@ -674,17 +674,27 @@ class dbal_oracle extends dbal */ function _sql_error() { - $error = @ocierror(); - $error = (!$error) ? @ocierror($this->query_result) : $error; - $error = (!$error) ? @ocierror($this->db_connect_id) : $error; - - if ($error) + if (function_exists('ocierror')) { - $this->last_error_result = $error; + $error = @ocierror(); + $error = (!$error) ? @ocierror($this->query_result) : $error; + $error = (!$error) ? @ocierror($this->db_connect_id) : $error; + + if ($error) + { + $this->last_error_result = $error; + } + else + { + $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); + } } else { - $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); + $error = array( + 'message' => $this->connect_error, + 'code' => '', + ); } return $error; diff --git a/phpBB/includes/db/sqlite.php b/phpBB/includes/db/sqlite.php index be0ad4fc8f..3c9b2cce34 100644 --- a/phpBB/includes/db/sqlite.php +++ b/phpBB/includes/db/sqlite.php @@ -300,10 +300,20 @@ class dbal_sqlite extends dbal */ function _sql_error() { - return array( - 'message' => @sqlite_error_string(@sqlite_last_error($this->db_connect_id)), - 'code' => @sqlite_last_error($this->db_connect_id) - ); + if (function_exists('sqlite_error_string')) + { + return array( + 'message' => @sqlite_error_string(@sqlite_last_error($this->db_connect_id)), + 'code' => @sqlite_last_error($this->db_connect_id) + ); + } + else + { + return array( + 'message' => $this->connect_error, + 'code' => '', + ); + } } /** From 40db60e45f3d7af01a96f9da6b36db2606b3d147 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 16:07:02 -0500 Subject: [PATCH 091/497] [ticket/10205] Fix a parse error in oracle driver. PHPBB3-10205 --- phpBB/includes/db/oracle.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/db/oracle.php b/phpBB/includes/db/oracle.php index b234d8b45e..4a7a4ecc8c 100644 --- a/phpBB/includes/db/oracle.php +++ b/phpBB/includes/db/oracle.php @@ -74,7 +74,7 @@ class dbal_oracle extends dbal $this->connect_error = 'ocilogon function does not exist, is oci extension installed?'; return $this->sql_error(''); } - $this->db_connect_id = @ocilogon($this->user, $sqlpassword, $connect, 'UTF8')); + $this->db_connect_id = @ocilogon($this->user, $sqlpassword, $connect, 'UTF8'); } return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); From de2fe1a308b08af868f22d6d9c0b7007f66de676 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 16:12:31 -0500 Subject: [PATCH 092/497] [ticket/10205] Convert mssqlnative driver to the same logic. PHPBB3-10205 --- phpBB/includes/db/mssqlnative.php | 52 +++++++++++++++++++------------ 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php index 3ad0ff3e11..e5de30faf6 100644 --- a/phpBB/includes/db/mssqlnative.php +++ b/phpBB/includes/db/mssqlnative.php @@ -199,16 +199,18 @@ class dbal_mssqlnative extends dbal var $m_insert_id = NULL; var $last_query_text = ''; var $query_options = array(); + var $connect_error = ''; /** * Connect to server */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) { - # Test for driver support, to avoid suppressed fatal error + // Test for driver support, to avoid suppressed fatal error if (!function_exists('sqlsrv_connect')) { - trigger_error('Native MS SQL Server driver for PHP is missing or needs to be updated. Version 1.1 or later is required to install phpBB3. You can download the driver from: http://www.microsoft.com/sqlserver/2005/en/us/PHP-Driver.aspx\n', E_USER_ERROR); + $this->connect_error = 'Native MS SQL Server driver for PHP is missing or needs to be updated. Version 1.1 or later is required to install phpBB3. You can download the driver from: http://www.microsoft.com/sqlserver/2005/en/us/PHP-Driver.aspx'; + return $this->sql_error(''); } //set up connection variables @@ -514,31 +516,41 @@ class dbal_mssqlnative extends dbal */ function _sql_error() { - $errors = @sqlsrv_errors(SQLSRV_ERR_ERRORS); - $error_message = ''; - $code = 0; - - if ($errors != null) + if (function_exists('sqlsrv_errors')) { - foreach ($errors as $error) + $errors = @sqlsrv_errors(SQLSRV_ERR_ERRORS); + $error_message = ''; + $code = 0; + + if ($errors != null) { - $error_message .= "SQLSTATE: ".$error[ 'SQLSTATE']."\n"; - $error_message .= "code: ".$error[ 'code']."\n"; - $code = $error['code']; - $error_message .= "message: ".$error[ 'message']."\n"; + foreach ($errors as $error) + { + $error_message .= "SQLSTATE: ".$error[ 'SQLSTATE']."\n"; + $error_message .= "code: ".$error[ 'code']."\n"; + $code = $error['code']; + $error_message .= "message: ".$error[ 'message']."\n"; + } + $this->last_error_result = $error_message; + $error = $this->last_error_result; } - $this->last_error_result = $error_message; - $error = $this->last_error_result; + else + { + $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); + } + + return array( + 'message' => $error, + 'code' => $code, + ); } else { - $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); + return array( + 'message' => $this->connect_error, + 'code' => '', + ); } - - return array( - 'message' => $error, - 'code' => $code, - ); } /** From dc521692f3c6d65b842a42f68bc727c8a36c9042 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 16:14:39 -0500 Subject: [PATCH 093/497] [ticket/10205] Check for function existence in mssql connect method. PHPBB3-10205 --- phpBB/includes/db/mssql.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/phpBB/includes/db/mssql.php b/phpBB/includes/db/mssql.php index bc0a870885..3792e82aa0 100644 --- a/phpBB/includes/db/mssql.php +++ b/phpBB/includes/db/mssql.php @@ -25,11 +25,19 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); */ class dbal_mssql extends dbal { + var $connect_error = ''; + /** * Connect to server */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) { + if (!function_exists('mssql_connect')) + { + $this->connect_error = 'mssql_connect function does not exist, is mssql extension installed?'; + return $this->sql_error(''); + } + $this->persistency = $persistency; $this->user = $sqluser; $this->dbname = $database; From f3c043a5696610ed1312a734b3f3ed1b613fc4f4 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 16:29:37 -0500 Subject: [PATCH 094/497] [ticket/10205] Test failed connection attempts. PHPBB3-10205 --- tests/dbal/connect_test.php | 44 +++++++++++++++++++++++++++++++++++++ tests/fixtures/empty.xml | 5 +++++ 2 files changed, 49 insertions(+) create mode 100644 tests/dbal/connect_test.php create mode 100644 tests/fixtures/empty.xml diff --git a/tests/dbal/connect_test.php b/tests/dbal/connect_test.php new file mode 100644 index 0000000000..4964f24ba2 --- /dev/null +++ b/tests/dbal/connect_test.php @@ -0,0 +1,44 @@ +createXMLDataSet(dirname(__FILE__) . '/../fixtures/empty.xml'); + } + + public function test_failing_connect() + { + global $phpbb_root_path, $phpEx; + + $config = $this->get_database_config(); + + require_once dirname(__FILE__) . '/../../phpBB/includes/db/' . $config['dbms'] . '.php'; + $dbal = 'dbal_' . $config['dbms']; + $db = new $dbal(); + + // Failure to connect results in a trigger_error call in dbal. + // phpunit converts triggered errors to exceptions. + // In particular there should be no fatals here. + try + { + $db->sql_connect($config['dbhost'], 'phpbbogus', 'phpbbogus', 'phpbbogus', $config['dbport']); + $this->assertFalse(true); + } catch (Exception $e) + { + // should have a legitimate message + $this->assertNotEmpty($e->getMessage()); + } + + return $db; + } +} diff --git a/tests/fixtures/empty.xml b/tests/fixtures/empty.xml new file mode 100644 index 0000000000..96eb1ab483 --- /dev/null +++ b/tests/fixtures/empty.xml @@ -0,0 +1,5 @@ + + + +
+
From 2d3882c4124e928dccd050da3d3ccafa54b9ff20 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 16:32:57 -0500 Subject: [PATCH 095/497] [ticket/10205] Delete stray return. PHPBB3-10205 --- tests/dbal/connect_test.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/dbal/connect_test.php b/tests/dbal/connect_test.php index 4964f24ba2..cefd76aa16 100644 --- a/tests/dbal/connect_test.php +++ b/tests/dbal/connect_test.php @@ -38,7 +38,5 @@ class phpbb_dbal_connect_test extends phpbb_database_test_case // should have a legitimate message $this->assertNotEmpty($e->getMessage()); } - - return $db; } } From bdc3ddf2bcec3caa9047d03e954c9de82f4916aa Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 17:19:25 -0500 Subject: [PATCH 096/497] [ticket/10491] Set up functional tests sensibly. PHPBB_FUNCTIONAL_URL goes into setup before class. Drop PHPBB_FUNCTIONAL_URL check in board installation and silent return if it is not set. Take board installation out of constructor. Install board in setup method. PHPBB3-10491 --- .../phpbb_functional_test_case.php | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 7c03f874e9..85019a5e31 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -33,11 +33,27 @@ class phpbb_functional_test_case extends phpbb_test_case static protected $config = array(); static protected $already_installed = false; - public function setUp() + static public function setUpBeforeClass() { + parent::setUpBeforeClass(); + + self::$config = phpbb_test_case_helpers::get_test_config(); + if (!isset(self::$config['phpbb_functional_url'])) { - $this->markTestSkipped('phpbb_functional_url was not set in test_config and wasn\'t set as PHPBB_FUNCTIONAL_URL environment variable either.'); + self::markTestSkipped('phpbb_functional_url was not set in test_config and wasn\'t set as PHPBB_FUNCTIONAL_URL environment variable either.'); + } + } + + public function setUp() + { + parent::setUp(); + + if (!static::$already_installed) + { + $this->install_board(); + $this->bootstrap(); + static::$already_installed = true; } $this->cookieJar = new CookieJar; @@ -91,26 +107,12 @@ class phpbb_functional_test_case extends phpbb_test_case $this->backupStaticAttributesBlacklist += array( 'phpbb_functional_test_case' => array('config', 'already_installed'), ); - - if (!static::$already_installed) - { - $this->install_board(); - $this->bootstrap(); - static::$already_installed = true; - } } protected function install_board() { global $phpbb_root_path, $phpEx; - self::$config = phpbb_test_case_helpers::get_test_config(); - - if (!isset(self::$config['phpbb_functional_url'])) - { - return; - } - self::$config['table_prefix'] = 'phpbb_'; $this->recreate_database(self::$config); @@ -158,6 +160,7 @@ class phpbb_functional_test_case extends phpbb_test_case // end data $content = $this->do_request('install'); + $this->assertNotSame(false, $content); $this->assertContains('Welcome to Installation', $content); $this->do_request('create_table', $data); From 38d2868ba8db0f6e24fdfb7bbdfef4925a97770c Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 17:37:46 -0500 Subject: [PATCH 097/497] [ticket/10491] Move board installation into setup before class. Functional posting test already assumed that board is installed once per test case and not once per test. PHPBB3-10491 --- .../phpbb_functional_test_case.php | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 85019a5e31..66f4b6db65 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -31,7 +31,6 @@ class phpbb_functional_test_case extends phpbb_test_case protected $lang = array(); static protected $config = array(); - static protected $already_installed = false; static public function setUpBeforeClass() { @@ -43,18 +42,15 @@ class phpbb_functional_test_case extends phpbb_test_case { self::markTestSkipped('phpbb_functional_url was not set in test_config and wasn\'t set as PHPBB_FUNCTIONAL_URL environment variable either.'); } + + self::install_board(); } public function setUp() { parent::setUp(); - if (!static::$already_installed) - { - $this->install_board(); - $this->bootstrap(); - static::$already_installed = true; - } + $this->bootstrap(); $this->cookieJar = new CookieJar; $this->client = new Goutte\Client(array(), null, $this->cookieJar); @@ -109,12 +105,12 @@ class phpbb_functional_test_case extends phpbb_test_case ); } - protected function install_board() + static protected function install_board() { global $phpbb_root_path, $phpEx; self::$config['table_prefix'] = 'phpbb_'; - $this->recreate_database(self::$config); + self::recreate_database(self::$config); if (file_exists($phpbb_root_path . "config.$phpEx")) { @@ -159,20 +155,20 @@ class phpbb_functional_test_case extends phpbb_test_case )); // end data - $content = $this->do_request('install'); - $this->assertNotSame(false, $content); - $this->assertContains('Welcome to Installation', $content); + $content = self::do_request('install'); + self::assertNotSame(false, $content); + self::assertContains('Welcome to Installation', $content); - $this->do_request('create_table', $data); + self::do_request('create_table', $data); - $this->do_request('config_file', $data); + self::do_request('config_file', $data); file_put_contents($phpbb_root_path . "config.$phpEx", phpbb_create_config_file_data($data, self::$config['dbms'], array(), true, true)); - $this->do_request('final', $data); + self::do_request('final', $data); copy($phpbb_root_path . "config.$phpEx", $phpbb_root_path . "config_test.$phpEx"); } - private function do_request($sub, $post_data = null) + static private function do_request($sub, $post_data = null) { $context = null; From 29c4da6162902d3c0d766a8acb17e5a2cf02f901 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 19:00:42 -0500 Subject: [PATCH 098/497] [ticket/10205] Add some columns to the empty fixture file for mssqlnative. Supposedly it choked on the version without any columns thusly: phpbb_dbal_connect_test::test_failing_connect PDOException: SQLSTATE[HY090]: [Microsoft][ODBC Driver Manager] Invalid string or buffer length PHPBB3-10205 --- tests/fixtures/empty.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/fixtures/empty.xml b/tests/fixtures/empty.xml index 96eb1ab483..195e30e38d 100644 --- a/tests/fixtures/empty.xml +++ b/tests/fixtures/empty.xml @@ -1,5 +1,9 @@ - +
+ session_id + session_user_id + session_ip + session_browser
From 89c9c9d4b0daa7308fd015e8a6fca6386a8b8016 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 21:22:33 -0500 Subject: [PATCH 099/497] [ticket/10205] Cosmetic changes. PHPBB3-10205 --- phpBB/includes/db/mssql.php | 2 +- phpBB/includes/db/mssql_odbc.php | 2 +- phpBB/includes/db/mssqlnative.php | 6 +++--- phpBB/includes/db/mysql.php | 4 ++-- phpBB/includes/db/sqlite.php | 2 +- tests/dbal/connect_test.php | 3 ++- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/phpBB/includes/db/mssql.php b/phpBB/includes/db/mssql.php index 3792e82aa0..2dd95c2508 100644 --- a/phpBB/includes/db/mssql.php +++ b/phpBB/includes/db/mssql.php @@ -367,7 +367,7 @@ class dbal_mssql extends dbal { $error = array( 'message' => @mssql_get_last_message(), - 'code' => '' + 'code' => '', ); // Get error code number diff --git a/phpBB/includes/db/mssql_odbc.php b/phpBB/includes/db/mssql_odbc.php index e1234389df..47792d74ab 100644 --- a/phpBB/includes/db/mssql_odbc.php +++ b/phpBB/includes/db/mssql_odbc.php @@ -364,7 +364,7 @@ class dbal_mssql_odbc extends dbal { return array( 'message' => @odbc_errormsg(), - 'code' => @odbc_error() + 'code' => @odbc_error(), ); } else diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php index e5de30faf6..41ac0a1784 100644 --- a/phpBB/includes/db/mssqlnative.php +++ b/phpBB/includes/db/mssqlnative.php @@ -526,10 +526,10 @@ class dbal_mssqlnative extends dbal { foreach ($errors as $error) { - $error_message .= "SQLSTATE: ".$error[ 'SQLSTATE']."\n"; - $error_message .= "code: ".$error[ 'code']."\n"; + $error_message .= "SQLSTATE: " . $error[ 'SQLSTATE'] . "\n"; + $error_message .= "code: " . $error[ 'code'] . "\n"; $code = $error['code']; - $error_message .= "message: ".$error[ 'message']."\n"; + $error_message .= "message: " . $error[ 'message'] . "\n"; } $this->last_error_result = $error_message; $error = $this->last_error_result; diff --git a/phpBB/includes/db/mysql.php b/phpBB/includes/db/mysql.php index 7314e92087..0125be0917 100644 --- a/phpBB/includes/db/mysql.php +++ b/phpBB/includes/db/mysql.php @@ -443,7 +443,7 @@ class dbal_mysql extends dbal { return array( 'message' => @mysql_error(), - 'code' => @mysql_errno() + 'code' => @mysql_errno(), ); } else @@ -457,7 +457,7 @@ class dbal_mysql extends dbal return array( 'message' => @mysql_error($this->db_connect_id), - 'code' => @mysql_errno($this->db_connect_id) + 'code' => @mysql_errno($this->db_connect_id), ); } diff --git a/phpBB/includes/db/sqlite.php b/phpBB/includes/db/sqlite.php index 3c9b2cce34..199b4eed23 100644 --- a/phpBB/includes/db/sqlite.php +++ b/phpBB/includes/db/sqlite.php @@ -304,7 +304,7 @@ class dbal_sqlite extends dbal { return array( 'message' => @sqlite_error_string(@sqlite_last_error($this->db_connect_id)), - 'code' => @sqlite_last_error($this->db_connect_id) + 'code' => @sqlite_last_error($this->db_connect_id), ); } else diff --git a/tests/dbal/connect_test.php b/tests/dbal/connect_test.php index cefd76aa16..505ce28fa1 100644 --- a/tests/dbal/connect_test.php +++ b/tests/dbal/connect_test.php @@ -33,7 +33,8 @@ class phpbb_dbal_connect_test extends phpbb_database_test_case { $db->sql_connect($config['dbhost'], 'phpbbogus', 'phpbbogus', 'phpbbogus', $config['dbport']); $this->assertFalse(true); - } catch (Exception $e) + } + catch (Exception $e) { // should have a legitimate message $this->assertNotEmpty($e->getMessage()); From 597dea1e047b94f0a862f7f6e650771ffc780141 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 21:32:02 -0500 Subject: [PATCH 100/497] [ticket/10205] Rewrite _sql_error implementations to have a single return. PHPBB3-10205 --- phpBB/includes/db/mssql_odbc.php | 6 ++++-- phpBB/includes/db/mssqlnative.php | 6 ++++-- phpBB/includes/db/mysql.php | 18 +++++++++++------- phpBB/includes/db/mysqli.php | 18 +++++++++++------- phpBB/includes/db/sqlite.php | 6 ++++-- 5 files changed, 34 insertions(+), 20 deletions(-) diff --git a/phpBB/includes/db/mssql_odbc.php b/phpBB/includes/db/mssql_odbc.php index 47792d74ab..04501cce8b 100644 --- a/phpBB/includes/db/mssql_odbc.php +++ b/phpBB/includes/db/mssql_odbc.php @@ -362,18 +362,20 @@ class dbal_mssql_odbc extends dbal { if (function_exists('odbc_errormsg')) { - return array( + $error = array( 'message' => @odbc_errormsg(), 'code' => @odbc_error(), ); } else { - return array( + $error = array( 'message' => $this->connect_error, 'code' => '', ); } + + return $error; } /** diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php index 41ac0a1784..b91372ac61 100644 --- a/phpBB/includes/db/mssqlnative.php +++ b/phpBB/includes/db/mssqlnative.php @@ -539,18 +539,20 @@ class dbal_mssqlnative extends dbal $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); } - return array( + $error = array( 'message' => $error, 'code' => $code, ); } else { - return array( + $error = array( 'message' => $this->connect_error, 'code' => '', ); } + + return $error; } /** diff --git a/phpBB/includes/db/mysql.php b/phpBB/includes/db/mysql.php index 0125be0917..e638531f51 100644 --- a/phpBB/includes/db/mysql.php +++ b/phpBB/includes/db/mysql.php @@ -437,28 +437,32 @@ class dbal_mysql extends dbal */ function _sql_error() { - if (!$this->db_connect_id) + if ($this->db_connect_id) + { + $error = array( + 'message' => @mysql_error($this->db_connect_id), + 'code' => @mysql_errno($this->db_connect_id), + ); + } + else { if (function_exists('mysql_error')) { - return array( + $error = array( 'message' => @mysql_error(), 'code' => @mysql_errno(), ); } else { - return array( + $error = array( 'message' => $this->connect_error, 'code' => '', ); } } - return array( - 'message' => @mysql_error($this->db_connect_id), - 'code' => @mysql_errno($this->db_connect_id), - ); + return $error; } /** diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/mysqli.php index cd82a12b58..b2a43d35f9 100644 --- a/phpBB/includes/db/mysqli.php +++ b/phpBB/includes/db/mysqli.php @@ -423,28 +423,32 @@ class dbal_mysqli extends dbal */ function _sql_error() { - if (!$this->db_connect_id) + if ($this->db_connect_id) + { + $error = array( + 'message' => @mysqli_error($this->db_connect_id), + 'code' => @mysqli_errno($this->db_connect_id) + ); + } + else { if (function_exists('mysqli_connect_error')) { - return array( + $error = array( 'message' => @mysqli_connect_error(), 'code' => @mysqli_connect_errno(), ); } else { - return array( + $error = array( 'message' => $this->connect_error, 'code' => '', ); } } - return array( - 'message' => @mysqli_error($this->db_connect_id), - 'code' => @mysqli_errno($this->db_connect_id) - ); + return $error; } /** diff --git a/phpBB/includes/db/sqlite.php b/phpBB/includes/db/sqlite.php index 199b4eed23..557b057cce 100644 --- a/phpBB/includes/db/sqlite.php +++ b/phpBB/includes/db/sqlite.php @@ -302,18 +302,20 @@ class dbal_sqlite extends dbal { if (function_exists('sqlite_error_string')) { - return array( + $error = array( 'message' => @sqlite_error_string(@sqlite_last_error($this->db_connect_id)), 'code' => @sqlite_last_error($this->db_connect_id), ); } else { - return array( + $error = array( 'message' => $this->connect_error, 'code' => '', ); } + + return $error; } /** From 5120f36a258ffcbffd5c10e9a1056d64ea794a16 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 21:33:13 -0500 Subject: [PATCH 101/497] [ticket/10205] Reduce nesting in mysql drivers. PHPBB3-10205 --- phpBB/includes/db/mysql.php | 25 +++++++++++-------------- phpBB/includes/db/mysqli.php | 25 +++++++++++-------------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/phpBB/includes/db/mysql.php b/phpBB/includes/db/mysql.php index e638531f51..252cb20bd4 100644 --- a/phpBB/includes/db/mysql.php +++ b/phpBB/includes/db/mysql.php @@ -444,22 +444,19 @@ class dbal_mysql extends dbal 'code' => @mysql_errno($this->db_connect_id), ); } + else if (function_exists('mysql_error')) + { + $error = array( + 'message' => @mysql_error(), + 'code' => @mysql_errno(), + ); + } else { - if (function_exists('mysql_error')) - { - $error = array( - 'message' => @mysql_error(), - 'code' => @mysql_errno(), - ); - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } + $error = array( + 'message' => $this->connect_error, + 'code' => '', + ); } return $error; diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/mysqli.php index b2a43d35f9..69f1d26a40 100644 --- a/phpBB/includes/db/mysqli.php +++ b/phpBB/includes/db/mysqli.php @@ -430,22 +430,19 @@ class dbal_mysqli extends dbal 'code' => @mysqli_errno($this->db_connect_id) ); } + else if (function_exists('mysqli_connect_error')) + { + $error = array( + 'message' => @mysqli_connect_error(), + 'code' => @mysqli_connect_errno(), + ); + } else { - if (function_exists('mysqli_connect_error')) - { - $error = array( - 'message' => @mysqli_connect_error(), - 'code' => @mysqli_connect_errno(), - ); - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } + $error = array( + 'message' => $this->connect_error, + 'code' => '', + ); } return $error; From 0f96b1aad378b1fc40620ea57df5ee89224fd5eb Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 23:35:34 -0500 Subject: [PATCH 102/497] [ticket/11162] Move to a separate file to avoid blowing out functions.php. PHPBB3-11162 --- phpBB/includes/functions.php | 87 --------------- phpBB/includes/functions_tricky_update.php | 103 ++++++++++++++++++ .../fixtures/duplicates.xml | 0 .../update_rows_avoiding_duplicates_test.php | 2 +- 4 files changed, 104 insertions(+), 88 deletions(-) create mode 100644 phpBB/includes/functions_tricky_update.php rename tests/{functions => functions_tricky_update}/fixtures/duplicates.xml (100%) rename tests/{functions => functions_tricky_update}/update_rows_avoiding_duplicates_test.php (98%) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index e3feb59d41..65d8be32ad 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -1297,93 +1297,6 @@ function tz_select($default = '', $truncate = false) return $tz_select; } -/** -* Updates rows in given table from a set of values to a new value. -* If this results in rows violating uniqueness constraints, the duplicate -* rows are eliminated. -* -* The only supported tables are bookmarks and topics_watch. -* -* @param dbal $db Database object -* @param string $table Table on which to perform the update -* @param string $column Column whose values to change -* @param array $from_values An array of values that should be changed -* @param int $to_value The new value -* @return null -*/ -function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_values, $to_value) -{ - $sql = "SELECT $column, user_id - FROM $table - WHERE " . $db->sql_in_set($column, $from_values); - $result = $db->sql_query($sql); - - $old_user_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $old_user_ids[$row[$column]][] = $row['user_id']; - } - $db->sql_freeresult($result); - - $sql = "SELECT $column, user_id - FROM $table - WHERE $column = '" . (int) $to_value . "'"; - $result = $db->sql_query($sql); - - $new_user_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $new_user_ids[$row[$column]][] = $row['user_id']; - } - $db->sql_freeresult($result); - - $queries = array(); - $any_found = false; - foreach ($from_values as $from_value) - { - if (!isset($old_user_ids[$from_value])) - { - continue; - } - $any_found = true; - if (empty($new_user_ids)) - { - $sql = "UPDATE $table - SET $column = " . (int) $to_value. " - WHERE $column = '" . $db->sql_escape($from_value) . "'"; - $queries[] = $sql; - } - else - { - $different_user_ids = array_diff($old_user_ids[$from_value], $new_user_ids[$to_value]); - if (!empty($different_user_ids)) - { - $sql = "UPDATE $table - SET $column = " . (int) $to_value. " - WHERE $column = '" . $db->sql_escape($from_value) . "' - AND " . $db->sql_in_set('user_id', $different_user_ids); - $queries[] = $sql; - } - } - } - - if ($any_found) - { - $db->sql_transaction('begin'); - - foreach ($queries as $sql) - { - $db->sql_query($sql); - } - - $sql = "DELETE FROM $table - WHERE " . $db->sql_in_set($column, $from_values); - $db->sql_query($sql); - - $db->sql_transaction('commit'); - } -} - // Functions handling topic/post tracking/marking /** diff --git a/phpBB/includes/functions_tricky_update.php b/phpBB/includes/functions_tricky_update.php new file mode 100644 index 0000000000..a5b9fdacd0 --- /dev/null +++ b/phpBB/includes/functions_tricky_update.php @@ -0,0 +1,103 @@ +sql_in_set($column, $from_values); + $result = $db->sql_query($sql); + + $old_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $old_user_ids[$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $sql = "SELECT $column, user_id + FROM $table + WHERE $column = '" . (int) $to_value . "'"; + $result = $db->sql_query($sql); + + $new_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $new_user_ids[$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $queries = array(); + $any_found = false; + foreach ($from_values as $from_value) + { + if (!isset($old_user_ids[$from_value])) + { + continue; + } + $any_found = true; + if (empty($new_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value. " + WHERE $column = '" . $db->sql_escape($from_value) . "'"; + $queries[] = $sql; + } + else + { + $different_user_ids = array_diff($old_user_ids[$from_value], $new_user_ids[$to_value]); + if (!empty($different_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value. " + WHERE $column = '" . $db->sql_escape($from_value) . "' + AND " . $db->sql_in_set('user_id', $different_user_ids); + $queries[] = $sql; + } + } + } + + if ($any_found) + { + $db->sql_transaction('begin'); + + foreach ($queries as $sql) + { + $db->sql_query($sql); + } + + $sql = "DELETE FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $db->sql_query($sql); + + $db->sql_transaction('commit'); + } +} diff --git a/tests/functions/fixtures/duplicates.xml b/tests/functions_tricky_update/fixtures/duplicates.xml similarity index 100% rename from tests/functions/fixtures/duplicates.xml rename to tests/functions_tricky_update/fixtures/duplicates.xml diff --git a/tests/functions/update_rows_avoiding_duplicates_test.php b/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php similarity index 98% rename from tests/functions/update_rows_avoiding_duplicates_test.php rename to tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php index 0d68e22d4a..6940122393 100644 --- a/tests/functions/update_rows_avoiding_duplicates_test.php +++ b/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php @@ -7,7 +7,7 @@ * */ -require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/functions_tricky_update.php'; class phpbb_update_rows_avoiding_duplicates_test extends phpbb_database_test_case { From abca64b1dfbe11f73675a3e5457fb9f0038f1cb6 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 23:37:14 -0500 Subject: [PATCH 103/497] [ticket/11162] Add includes. PHPBB3-11162 --- phpBB/includes/mcp/mcp_forum.php | 4 ++++ phpBB/includes/mcp/mcp_topic.php | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index e392bef157..3603224735 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -415,6 +415,10 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) $success_msg = 'POSTS_MERGED_SUCCESS'; // Update the topic watch table. + if (!function_exists('phpbb_update_rows_avoiding_duplicates')) + { + include($phpbb_root_path . 'includes/functions_tricky_update.' . $phpEx); + } phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); // Link to the new topic diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index f40a4bc044..1fb3cb9d73 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -620,6 +620,10 @@ function merge_posts($topic_id, $to_topic_id) else { // If the topic no longer exist, we will update the topic watch table. + if (!function_exists('phpbb_update_rows_avoiding_duplicates')) + { + include($phpbb_root_path . 'includes/functions_tricky_update.' . $phpEx); + } phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); } From 58951ef1057bd5f0d1098f9536eb8a84c532833c Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 23:37:57 -0500 Subject: [PATCH 104/497] [ticket/11162] The test is not at all trivial. PHPBB3-11162 --- .../update_rows_avoiding_duplicates_test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php b/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php index 6940122393..4849605e9c 100644 --- a/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php +++ b/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php @@ -53,7 +53,7 @@ class phpbb_update_rows_avoiding_duplicates_test extends phpbb_database_test_cas /** * @dataProvider fixture_data */ - public function test_trivial_update($description, $from, $to, $expected_result_count) + public function test_update($description, $from, $to, $expected_result_count) { $db = $this->new_dbal(); From efe122b03200155479920890defc2a3dc689bdd7 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 23:40:30 -0500 Subject: [PATCH 105/497] [ticket/11162] This test really only works for bookmarks. PHPBB3-11162 --- .../fixtures/bookmarks_duplicates.xml | 47 +++++++++++++++++++ ...icates.xml => topics_watch_duplicates.xml} | 0 .../update_rows_avoiding_duplicates_test.php | 6 +-- 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 tests/functions_tricky_update/fixtures/bookmarks_duplicates.xml rename tests/functions_tricky_update/fixtures/{duplicates.xml => topics_watch_duplicates.xml} (100%) diff --git a/tests/functions_tricky_update/fixtures/bookmarks_duplicates.xml b/tests/functions_tricky_update/fixtures/bookmarks_duplicates.xml new file mode 100644 index 0000000000..d49f76b073 --- /dev/null +++ b/tests/functions_tricky_update/fixtures/bookmarks_duplicates.xml @@ -0,0 +1,47 @@ + + + + user_id + topic_id + + + + 1 + 1 + + + + + 2 + 2 + + + 3 + 3 + + + + + 1 + 4 + + + 1 + 5 + + + + + 1 + 6 + + + 1 + 7 + + + 2 + 6 + +
+
diff --git a/tests/functions_tricky_update/fixtures/duplicates.xml b/tests/functions_tricky_update/fixtures/topics_watch_duplicates.xml similarity index 100% rename from tests/functions_tricky_update/fixtures/duplicates.xml rename to tests/functions_tricky_update/fixtures/topics_watch_duplicates.xml diff --git a/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php b/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php index 4849605e9c..6142997408 100644 --- a/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php +++ b/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php @@ -13,7 +13,7 @@ class phpbb_update_rows_avoiding_duplicates_test extends phpbb_database_test_cas { public function getDataSet() { - return $this->createXMLDataSet(dirname(__FILE__).'/fixtures/duplicates.xml'); + return $this->createXMLDataSet(dirname(__FILE__).'/fixtures/bookmarks_duplicates.xml'); } public static function fixture_data() @@ -57,10 +57,10 @@ class phpbb_update_rows_avoiding_duplicates_test extends phpbb_database_test_cas { $db = $this->new_dbal(); - phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $from, $to); + phpbb_update_rows_avoiding_duplicates($db, BOOKMARKS_TABLE, 'topic_id', $from, $to); $sql = 'SELECT COUNT(*) AS remaining_rows - FROM ' . TOPICS_WATCH_TABLE . ' + FROM ' . BOOKMARKS_TABLE . ' WHERE topic_id = ' . (int) $to; $result = $db->sql_query($sql); $result_count = $db->sql_fetchfield('remaining_rows'); From 6872104aa95a9f2aad565189e25bbf54abc3ca2c Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 5 Dec 2012 00:07:01 -0500 Subject: [PATCH 106/497] [ticket/11162] Account for notify_status. PHPBB3-11162 --- phpBB/includes/functions_tricky_update.php | 111 +++++++++++++++++- .../fixtures/topics_watch_duplicates.xml | 38 ++++-- ...avoiding_duplicates_notify_status_test.php | 100 ++++++++++++++++ 3 files changed, 239 insertions(+), 10 deletions(-) create mode 100644 tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php diff --git a/phpBB/includes/functions_tricky_update.php b/phpBB/includes/functions_tricky_update.php index a5b9fdacd0..cf922d7014 100644 --- a/phpBB/includes/functions_tricky_update.php +++ b/phpBB/includes/functions_tricky_update.php @@ -20,7 +20,7 @@ if (!defined('IN_PHPBB')) * If this results in rows violating uniqueness constraints, the duplicate * rows are eliminated. * -* The only supported tables are bookmarks and topics_watch. +* The only supported table is bookmarks. * * @param dbal $db Database object * @param string $table Table on which to perform the update @@ -67,7 +67,7 @@ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_value if (empty($new_user_ids)) { $sql = "UPDATE $table - SET $column = " . (int) $to_value. " + SET $column = " . (int) $to_value . " WHERE $column = '" . $db->sql_escape($from_value) . "'"; $queries[] = $sql; } @@ -77,7 +77,7 @@ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_value if (!empty($different_user_ids)) { $sql = "UPDATE $table - SET $column = " . (int) $to_value. " + SET $column = " . (int) $to_value . " WHERE $column = '" . $db->sql_escape($from_value) . "' AND " . $db->sql_in_set('user_id', $different_user_ids); $queries[] = $sql; @@ -101,3 +101,108 @@ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_value $db->sql_transaction('commit'); } } + +/** +* Updates rows in given table from a set of values to a new value. +* If this results in rows violating uniqueness constraints, the duplicate +* rows are merged respecting notify_status (0 takes precedence over 1). +* +* The only supported table is topics_watch. +* +* @param dbal $db Database object +* @param string $table Table on which to perform the update +* @param string $column Column whose values to change +* @param array $from_values An array of values that should be changed +* @param int $to_value The new value +* @return null +*/ +function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $column, $from_values, $to_value) +{ + $sql = "SELECT $column, user_id, notify_status + FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $result = $db->sql_query($sql); + + $old_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $old_user_ids[(int) $row['notify_status']][$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $sql = "SELECT $column, user_id + FROM $table + WHERE $column = '" . (int) $to_value . "'"; + $result = $db->sql_query($sql); + + $new_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $new_user_ids[$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $queries = array(); + $any_found = false; + $extra_updates = array( + 0 => 'notify_status = 0', + 1 => '', + ); + foreach ($from_values as $from_value) + { + foreach ($extra_updates as $notify_status => $extra_update) { + if (!isset($old_user_ids[$notify_status][$from_value])) + { + continue; + } + $any_found = true; + if (empty($new_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value . " + WHERE $column = '" . $db->sql_escape($from_value) . "'"; + $queries[] = $sql; + } + else + { + $different_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $new_user_ids[$to_value]); + if (!empty($different_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value . " + WHERE $column = '" . $db->sql_escape($from_value) . "' + AND " . $db->sql_in_set('user_id', $different_user_ids); + $queries[] = $sql; + } + + if ($extra_update) { + $same_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $different_user_ids); + if (!empty($same_user_ids)) + { + $sql = "UPDATE $table + SET $extra_update + WHERE $column = '" . (int) $to_value . "' + AND " . $db->sql_in_set('user_id', $same_user_ids); + $queries[] = $sql; + } + } + } + } + } + + if ($any_found) + { + $db->sql_transaction('begin'); + + foreach ($queries as $sql) + { + $db->sql_query($sql); + } + + $sql = "DELETE FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $db->sql_query($sql); + + $db->sql_transaction('commit'); + } +} diff --git a/tests/functions_tricky_update/fixtures/topics_watch_duplicates.xml b/tests/functions_tricky_update/fixtures/topics_watch_duplicates.xml index bc08016a8f..c387bb737a 100644 --- a/tests/functions_tricky_update/fixtures/topics_watch_duplicates.xml +++ b/tests/functions_tricky_update/fixtures/topics_watch_duplicates.xml @@ -14,17 +14,17 @@ - 2 + 1 2 1 + 2 3 - 3 - 1 + 0 - + 1 4 @@ -36,20 +36,44 @@ 1 - + 1 6 - 1 + 0 1 7 1 + + + + 1 + 8 + 1 + + + 1 + 9 + 0 + + + + + 1 + 10 + 0 + + + 1 + 11 + 1 + 2 - 6 + 10 1
diff --git a/tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php b/tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php new file mode 100644 index 0000000000..aa739c5f04 --- /dev/null +++ b/tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php @@ -0,0 +1,100 @@ +createXMLDataSet(dirname(__FILE__).'/fixtures/topics_watch_duplicates.xml'); + } + + public static function fixture_data() + { + return array( + // description + // from array + // to value + // expected count with to value post update + // expected notify_status values + array( + 'trivial', + array(1), + 1000, + 1, + 1, + ), + array( + 'no conflict', + array(2), + 3, + 2, + 1, + ), + array( + 'conflict, same notify status', + array(4), + 5, + 1, + 1, + ), + array( + 'conflict, notify status 0 into 1', + array(6), + 7, + 1, + 0, + ), + array( + 'conflict, notify status 1 into 0', + array(8), + 9, + 1, + 0, + ), + array( + 'conflict and no conflict', + array(10), + 11, + 2, + 0, + ), + ); + } + + /** + * @dataProvider fixture_data + */ + public function test_update($description, $from, $to, $expected_result_count, $expected_notify_status) + { + $db = $this->new_dbal(); + + phpbb_update_rows_avoiding_duplicates_notify_status($db, TOPICS_WATCH_TABLE, 'topic_id', $from, $to); + + $sql = 'SELECT COUNT(*) AS remaining_rows + FROM ' . TOPICS_WATCH_TABLE . ' + WHERE topic_id = ' . (int) $to; + $result = $db->sql_query($sql); + $result_count = $db->sql_fetchfield('remaining_rows'); + $db->sql_freeresult($result); + + $this->assertEquals($expected_result_count, $result_count); + + // user id of 1 is the user being updated + $sql = 'SELECT notify_status + FROM ' . TOPICS_WATCH_TABLE . ' + WHERE topic_id = ' . (int) $to . ' AND user_id = 1'; + $result = $db->sql_query($sql); + $notify_status = $db->sql_fetchfield('notify_status'); + $db->sql_freeresult($result); + + $this->assertEquals($expected_notify_status, $notify_status); + } +} From 1a411c5658da769e28b03332ed618d5e701dab79 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 5 Dec 2012 00:10:02 -0500 Subject: [PATCH 107/497] [ticket/11162] Use correct functions. PHPBB3-11162 --- phpBB/includes/mcp/mcp_forum.php | 4 ++-- phpBB/includes/mcp/mcp_topic.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index 3603224735..cd938e83a0 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -415,11 +415,11 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) $success_msg = 'POSTS_MERGED_SUCCESS'; // Update the topic watch table. - if (!function_exists('phpbb_update_rows_avoiding_duplicates')) + if (!function_exists('phpbb_update_rows_avoiding_duplicates_notify_status')) { include($phpbb_root_path . 'includes/functions_tricky_update.' . $phpEx); } - phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); + phpbb_update_rows_avoiding_duplicates_notify_status($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); // Link to the new topic $return_link .= (($return_link) ? '

' : '') . sprintf($user->lang['RETURN_NEW_TOPIC'], '', ''); diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index 1fb3cb9d73..29dabdd2a2 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -620,11 +620,11 @@ function merge_posts($topic_id, $to_topic_id) else { // If the topic no longer exist, we will update the topic watch table. - if (!function_exists('phpbb_update_rows_avoiding_duplicates')) + if (!function_exists('phpbb_update_rows_avoiding_duplicates_notify_status')) { include($phpbb_root_path . 'includes/functions_tricky_update.' . $phpEx); } - phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); + phpbb_update_rows_avoiding_duplicates_notify_status($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); } // Link to the new topic From 94ebc5707836d931e24e77f5ce1b3a16d0410fb8 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 5 Dec 2012 10:40:42 -0500 Subject: [PATCH 108/497] [ticket/11162] Newlines to LF. PHPBB3-11162 --- phpBB/includes/functions_tricky_update.php | 416 ++++++++++----------- 1 file changed, 208 insertions(+), 208 deletions(-) diff --git a/phpBB/includes/functions_tricky_update.php b/phpBB/includes/functions_tricky_update.php index cf922d7014..c8fcb9b6f0 100644 --- a/phpBB/includes/functions_tricky_update.php +++ b/phpBB/includes/functions_tricky_update.php @@ -1,208 +1,208 @@ -sql_in_set($column, $from_values); - $result = $db->sql_query($sql); - - $old_user_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $old_user_ids[$row[$column]][] = $row['user_id']; - } - $db->sql_freeresult($result); - - $sql = "SELECT $column, user_id - FROM $table - WHERE $column = '" . (int) $to_value . "'"; - $result = $db->sql_query($sql); - - $new_user_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $new_user_ids[$row[$column]][] = $row['user_id']; - } - $db->sql_freeresult($result); - - $queries = array(); - $any_found = false; - foreach ($from_values as $from_value) - { - if (!isset($old_user_ids[$from_value])) - { - continue; - } - $any_found = true; - if (empty($new_user_ids)) - { - $sql = "UPDATE $table - SET $column = " . (int) $to_value . " - WHERE $column = '" . $db->sql_escape($from_value) . "'"; - $queries[] = $sql; - } - else - { - $different_user_ids = array_diff($old_user_ids[$from_value], $new_user_ids[$to_value]); - if (!empty($different_user_ids)) - { - $sql = "UPDATE $table - SET $column = " . (int) $to_value . " - WHERE $column = '" . $db->sql_escape($from_value) . "' - AND " . $db->sql_in_set('user_id', $different_user_ids); - $queries[] = $sql; - } - } - } - - if ($any_found) - { - $db->sql_transaction('begin'); - - foreach ($queries as $sql) - { - $db->sql_query($sql); - } - - $sql = "DELETE FROM $table - WHERE " . $db->sql_in_set($column, $from_values); - $db->sql_query($sql); - - $db->sql_transaction('commit'); - } -} - -/** -* Updates rows in given table from a set of values to a new value. -* If this results in rows violating uniqueness constraints, the duplicate -* rows are merged respecting notify_status (0 takes precedence over 1). -* -* The only supported table is topics_watch. -* -* @param dbal $db Database object -* @param string $table Table on which to perform the update -* @param string $column Column whose values to change -* @param array $from_values An array of values that should be changed -* @param int $to_value The new value -* @return null -*/ -function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $column, $from_values, $to_value) -{ - $sql = "SELECT $column, user_id, notify_status - FROM $table - WHERE " . $db->sql_in_set($column, $from_values); - $result = $db->sql_query($sql); - - $old_user_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $old_user_ids[(int) $row['notify_status']][$row[$column]][] = $row['user_id']; - } - $db->sql_freeresult($result); - - $sql = "SELECT $column, user_id - FROM $table - WHERE $column = '" . (int) $to_value . "'"; - $result = $db->sql_query($sql); - - $new_user_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $new_user_ids[$row[$column]][] = $row['user_id']; - } - $db->sql_freeresult($result); - - $queries = array(); - $any_found = false; - $extra_updates = array( - 0 => 'notify_status = 0', - 1 => '', - ); - foreach ($from_values as $from_value) - { - foreach ($extra_updates as $notify_status => $extra_update) { - if (!isset($old_user_ids[$notify_status][$from_value])) - { - continue; - } - $any_found = true; - if (empty($new_user_ids)) - { - $sql = "UPDATE $table - SET $column = " . (int) $to_value . " - WHERE $column = '" . $db->sql_escape($from_value) . "'"; - $queries[] = $sql; - } - else - { - $different_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $new_user_ids[$to_value]); - if (!empty($different_user_ids)) - { - $sql = "UPDATE $table - SET $column = " . (int) $to_value . " - WHERE $column = '" . $db->sql_escape($from_value) . "' - AND " . $db->sql_in_set('user_id', $different_user_ids); - $queries[] = $sql; - } - - if ($extra_update) { - $same_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $different_user_ids); - if (!empty($same_user_ids)) - { - $sql = "UPDATE $table - SET $extra_update - WHERE $column = '" . (int) $to_value . "' - AND " . $db->sql_in_set('user_id', $same_user_ids); - $queries[] = $sql; - } - } - } - } - } - - if ($any_found) - { - $db->sql_transaction('begin'); - - foreach ($queries as $sql) - { - $db->sql_query($sql); - } - - $sql = "DELETE FROM $table - WHERE " . $db->sql_in_set($column, $from_values); - $db->sql_query($sql); - - $db->sql_transaction('commit'); - } -} +sql_in_set($column, $from_values); + $result = $db->sql_query($sql); + + $old_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $old_user_ids[$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $sql = "SELECT $column, user_id + FROM $table + WHERE $column = '" . (int) $to_value . "'"; + $result = $db->sql_query($sql); + + $new_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $new_user_ids[$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $queries = array(); + $any_found = false; + foreach ($from_values as $from_value) + { + if (!isset($old_user_ids[$from_value])) + { + continue; + } + $any_found = true; + if (empty($new_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value . " + WHERE $column = '" . $db->sql_escape($from_value) . "'"; + $queries[] = $sql; + } + else + { + $different_user_ids = array_diff($old_user_ids[$from_value], $new_user_ids[$to_value]); + if (!empty($different_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value . " + WHERE $column = '" . $db->sql_escape($from_value) . "' + AND " . $db->sql_in_set('user_id', $different_user_ids); + $queries[] = $sql; + } + } + } + + if ($any_found) + { + $db->sql_transaction('begin'); + + foreach ($queries as $sql) + { + $db->sql_query($sql); + } + + $sql = "DELETE FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $db->sql_query($sql); + + $db->sql_transaction('commit'); + } +} + +/** +* Updates rows in given table from a set of values to a new value. +* If this results in rows violating uniqueness constraints, the duplicate +* rows are merged respecting notify_status (0 takes precedence over 1). +* +* The only supported table is topics_watch. +* +* @param dbal $db Database object +* @param string $table Table on which to perform the update +* @param string $column Column whose values to change +* @param array $from_values An array of values that should be changed +* @param int $to_value The new value +* @return null +*/ +function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $column, $from_values, $to_value) +{ + $sql = "SELECT $column, user_id, notify_status + FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $result = $db->sql_query($sql); + + $old_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $old_user_ids[(int) $row['notify_status']][$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $sql = "SELECT $column, user_id + FROM $table + WHERE $column = '" . (int) $to_value . "'"; + $result = $db->sql_query($sql); + + $new_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $new_user_ids[$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $queries = array(); + $any_found = false; + $extra_updates = array( + 0 => 'notify_status = 0', + 1 => '', + ); + foreach ($from_values as $from_value) + { + foreach ($extra_updates as $notify_status => $extra_update) { + if (!isset($old_user_ids[$notify_status][$from_value])) + { + continue; + } + $any_found = true; + if (empty($new_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value . " + WHERE $column = '" . $db->sql_escape($from_value) . "'"; + $queries[] = $sql; + } + else + { + $different_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $new_user_ids[$to_value]); + if (!empty($different_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value . " + WHERE $column = '" . $db->sql_escape($from_value) . "' + AND " . $db->sql_in_set('user_id', $different_user_ids); + $queries[] = $sql; + } + + if ($extra_update) { + $same_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $different_user_ids); + if (!empty($same_user_ids)) + { + $sql = "UPDATE $table + SET $extra_update + WHERE $column = '" . (int) $to_value . "' + AND " . $db->sql_in_set('user_id', $same_user_ids); + $queries[] = $sql; + } + } + } + } + } + + if ($any_found) + { + $db->sql_transaction('begin'); + + foreach ($queries as $sql) + { + $db->sql_query($sql); + } + + $sql = "DELETE FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $db->sql_query($sql); + + $db->sql_transaction('commit'); + } +} From 16966f52d37e4ebdca4f3846c81dfa85b193501e Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 5 Dec 2012 10:41:08 -0500 Subject: [PATCH 109/497] [ticket/11162] Reformat. PHPBB3-11162 --- phpBB/includes/functions_tricky_update.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/phpBB/includes/functions_tricky_update.php b/phpBB/includes/functions_tricky_update.php index c8fcb9b6f0..10321618b2 100644 --- a/phpBB/includes/functions_tricky_update.php +++ b/phpBB/includes/functions_tricky_update.php @@ -150,7 +150,8 @@ function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $colum ); foreach ($from_values as $from_value) { - foreach ($extra_updates as $notify_status => $extra_update) { + foreach ($extra_updates as $notify_status => $extra_update) + { if (!isset($old_user_ids[$notify_status][$from_value])) { continue; @@ -174,8 +175,9 @@ function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $colum AND " . $db->sql_in_set('user_id', $different_user_ids); $queries[] = $sql; } - - if ($extra_update) { + + if ($extra_update) + { $same_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $different_user_ids); if (!empty($same_user_ids)) { From fe87d441eeb54bf5efb56a0f69f42848d9ef53d5 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 5 Dec 2012 10:44:36 -0500 Subject: [PATCH 110/497] [ticket/11162] Review comments fixed. PHPBB3-11162 --- phpBB/includes/functions_tricky_update.php | 12 ++++++------ ...e_rows_avoiding_duplicates_notify_status_test.php | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/phpBB/includes/functions_tricky_update.php b/phpBB/includes/functions_tricky_update.php index 10321618b2..05cb65e68d 100644 --- a/phpBB/includes/functions_tricky_update.php +++ b/phpBB/includes/functions_tricky_update.php @@ -39,19 +39,19 @@ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_value $old_user_ids = array(); while ($row = $db->sql_fetchrow($result)) { - $old_user_ids[$row[$column]][] = $row['user_id']; + $old_user_ids[$row[$column]][] = (int) $row['user_id']; } $db->sql_freeresult($result); $sql = "SELECT $column, user_id FROM $table - WHERE $column = '" . (int) $to_value . "'"; + WHERE $column = " . (int) $to_value; $result = $db->sql_query($sql); $new_user_ids = array(); while ($row = $db->sql_fetchrow($result)) { - $new_user_ids[$row[$column]][] = $row['user_id']; + $new_user_ids[$row[$column]][] = (int) $row['user_id']; } $db->sql_freeresult($result); @@ -126,19 +126,19 @@ function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $colum $old_user_ids = array(); while ($row = $db->sql_fetchrow($result)) { - $old_user_ids[(int) $row['notify_status']][$row[$column]][] = $row['user_id']; + $old_user_ids[(int) $row['notify_status']][$row[$column]][] = (int) $row['user_id']; } $db->sql_freeresult($result); $sql = "SELECT $column, user_id FROM $table - WHERE $column = '" . (int) $to_value . "'"; + WHERE $column = " . (int) $to_value; $result = $db->sql_query($sql); $new_user_ids = array(); while ($row = $db->sql_fetchrow($result)) { - $new_user_ids[$row[$column]][] = $row['user_id']; + $new_user_ids[$row[$column]][] = (int) $row['user_id']; } $db->sql_freeresult($result); diff --git a/tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php b/tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php index aa739c5f04..9052585552 100644 --- a/tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php +++ b/tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php @@ -90,7 +90,8 @@ class phpbb_update_rows_avoiding_duplicates_notify_status_test extends phpbb_dat // user id of 1 is the user being updated $sql = 'SELECT notify_status FROM ' . TOPICS_WATCH_TABLE . ' - WHERE topic_id = ' . (int) $to . ' AND user_id = 1'; + WHERE topic_id = ' . (int) $to . ' + AND user_id = 1'; $result = $db->sql_query($sql); $notify_status = $db->sql_fetchfield('notify_status'); $db->sql_freeresult($result); From f5de11438c471a76fc5c5f3a4b8c4c29d07ed734 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 5 Dec 2012 10:47:26 -0500 Subject: [PATCH 111/497] [ticket/11162] Use empty($queries). PHPBB3-11162 --- phpBB/includes/functions_tricky_update.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/phpBB/includes/functions_tricky_update.php b/phpBB/includes/functions_tricky_update.php index 05cb65e68d..664c246888 100644 --- a/phpBB/includes/functions_tricky_update.php +++ b/phpBB/includes/functions_tricky_update.php @@ -56,14 +56,12 @@ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_value $db->sql_freeresult($result); $queries = array(); - $any_found = false; foreach ($from_values as $from_value) { if (!isset($old_user_ids[$from_value])) { continue; } - $any_found = true; if (empty($new_user_ids)) { $sql = "UPDATE $table @@ -85,7 +83,7 @@ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_value } } - if ($any_found) + if (!empty($queries)) { $db->sql_transaction('begin'); @@ -143,7 +141,6 @@ function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $colum $db->sql_freeresult($result); $queries = array(); - $any_found = false; $extra_updates = array( 0 => 'notify_status = 0', 1 => '', @@ -156,7 +153,6 @@ function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $colum { continue; } - $any_found = true; if (empty($new_user_ids)) { $sql = "UPDATE $table @@ -192,7 +188,7 @@ function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $colum } } - if ($any_found) + if (!empty($queries)) { $db->sql_transaction('begin'); From 9b018bd460376abce3f4fe9d8c11feef0c547b0d Mon Sep 17 00:00:00 2001 From: Bruno Ais Date: Sun, 2 Dec 2012 21:47:18 +0000 Subject: [PATCH 112/497] [ticket/11171] DB additions for these changes Made the required changes to develop/create_schema_files.php and this is what resulted of that. PHPBB3-11171 --- phpBB/develop/create_schema_files.php | 27 +++++++++++++---------- phpBB/install/schemas/firebird_schema.sql | 5 ++++- phpBB/install/schemas/mssql_schema.sql | 5 ++++- phpBB/install/schemas/mysql_40_schema.sql | 5 ++++- phpBB/install/schemas/mysql_41_schema.sql | 5 ++++- phpBB/install/schemas/oracle_schema.sql | 5 ++++- phpBB/install/schemas/postgres_schema.sql | 5 ++++- phpBB/install/schemas/sqlite_schema.sql | 5 ++++- 8 files changed, 43 insertions(+), 19 deletions(-) diff --git a/phpBB/develop/create_schema_files.php b/phpBB/develop/create_schema_files.php index 3d3e478032..0ae75c2681 100644 --- a/phpBB/develop/create_schema_files.php +++ b/phpBB/develop/create_schema_files.php @@ -1520,18 +1520,21 @@ function get_schema_struct() $schema_data['phpbb_reports'] = array( 'COLUMNS' => array( - 'report_id' => array('UINT', NULL, 'auto_increment'), - 'reason_id' => array('USINT', 0), - 'post_id' => array('UINT', 0), - 'pm_id' => array('UINT', 0), - 'user_id' => array('UINT', 0), - 'user_notify' => array('BOOL', 0), - 'report_closed' => array('BOOL', 0), - 'report_time' => array('TIMESTAMP', 0), - 'report_text' => array('MTEXT_UNI', ''), - 'reported_post_text' => array('MTEXT_UNI', ''), - 'reported_post_uid' => array('VCHAR:8', ''), - 'reported_post_bitfield' => array('VCHAR:255', ''), + 'report_id' => array('UINT', NULL, 'auto_increment'), + 'reason_id' => array('USINT', 0), + 'post_id' => array('UINT', 0), + 'pm_id' => array('UINT', 0), + 'user_id' => array('UINT', 0), + 'user_notify' => array('BOOL', 0), + 'report_closed' => array('BOOL', 0), + 'report_time' => array('TIMESTAMP', 0), + 'report_text' => array('MTEXT_UNI', ''), + 'reported_post_text' => array('MTEXT_UNI', ''), + 'reported_post_uid' => array('VCHAR:8', ''), + 'reported_post_bitfield' => array('VCHAR:255', ''), + 'reported_post_enable_magic_url' => array('BOOL', 1), + 'reported_post_enable_smilies' => array('BOOL', 1), + 'reported_post_enable_bbcode' => array('BOOL', 1) ), 'PRIMARY_KEY' => 'report_id', 'KEYS' => array( diff --git a/phpBB/install/schemas/firebird_schema.sql b/phpBB/install/schemas/firebird_schema.sql index 767ce68b4a..bd97fefb36 100644 --- a/phpBB/install/schemas/firebird_schema.sql +++ b/phpBB/install/schemas/firebird_schema.sql @@ -912,8 +912,11 @@ CREATE TABLE phpbb_reports ( report_time INTEGER DEFAULT 0 NOT NULL, report_text BLOB SUB_TYPE TEXT CHARACTER SET UTF8 DEFAULT '' NOT NULL, reported_post_text BLOB SUB_TYPE TEXT CHARACTER SET UTF8 DEFAULT '' NOT NULL, + reported_post_uid VARCHAR(8) CHARACTER SET NONE DEFAULT '' NOT NULL, reported_post_bitfield VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL, - reported_post_uid VARCHAR(8) CHARACTER SET NONE DEFAULT '' NOT NULL + reported_post_enable_magic_url INTEGER DEFAULT 1 NOT NULL, + reported_post_enable_smilies INTEGER DEFAULT 1 NOT NULL, + reported_post_enable_bbcode INTEGER DEFAULT 1 NOT NULL );; ALTER TABLE phpbb_reports ADD PRIMARY KEY (report_id);; diff --git a/phpBB/install/schemas/mssql_schema.sql b/phpBB/install/schemas/mssql_schema.sql index 84c975942f..bb0890e439 100644 --- a/phpBB/install/schemas/mssql_schema.sql +++ b/phpBB/install/schemas/mssql_schema.sql @@ -1111,8 +1111,11 @@ CREATE TABLE [phpbb_reports] ( [report_time] [int] DEFAULT (0) NOT NULL , [report_text] [text] DEFAULT ('') NOT NULL , [reported_post_text] [text] DEFAULT ('') NOT NULL , + [reported_post_uid] [varchar] (8) DEFAULT ('') NOT NULL , [reported_post_bitfield] [varchar] (255) DEFAULT ('') NOT NULL , - [reported_post_uid] [varchar] (8) DEFAULT ('') NOT NULL + [reported_post_enable_magic_url] [int] DEFAULT (1) NOT NULL , + [reported_post_enable_smilies] [int] DEFAULT (1) NOT NULL , + [reported_post_enable_bbcode] [int] DEFAULT (1) NOT NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO diff --git a/phpBB/install/schemas/mysql_40_schema.sql b/phpBB/install/schemas/mysql_40_schema.sql index 8aab949103..bf3d7fecfa 100644 --- a/phpBB/install/schemas/mysql_40_schema.sql +++ b/phpBB/install/schemas/mysql_40_schema.sql @@ -649,8 +649,11 @@ CREATE TABLE phpbb_reports ( report_time int(11) UNSIGNED DEFAULT '0' NOT NULL, report_text mediumblob NOT NULL, reported_post_text mediumblob NOT NULL, - reported_post_bitfield varbinary(255) DEFAULT '' NOT NULL, reported_post_uid varbinary(8) DEFAULT '' NOT NULL, + reported_post_bitfield varbinary(255) DEFAULT '' NOT NULL, + reported_post_enable_magic_url tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, + reported_post_enable_smilies tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, + reported_post_enable_bbcode tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, PRIMARY KEY (report_id), KEY post_id (post_id), KEY pm_id (pm_id) diff --git a/phpBB/install/schemas/mysql_41_schema.sql b/phpBB/install/schemas/mysql_41_schema.sql index 04aef2844a..372b63d83c 100644 --- a/phpBB/install/schemas/mysql_41_schema.sql +++ b/phpBB/install/schemas/mysql_41_schema.sql @@ -649,8 +649,11 @@ CREATE TABLE phpbb_reports ( report_time int(11) UNSIGNED DEFAULT '0' NOT NULL, report_text mediumtext NOT NULL, reported_post_text mediumtext NOT NULL, - reported_post_bitfield varchar(255) DEFAULT '' NOT NULL, reported_post_uid varchar(8) DEFAULT '' NOT NULL, + reported_post_bitfield varchar(255) DEFAULT '' NOT NULL, + reported_post_enable_magic_url tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, + reported_post_enable_smilies tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, + reported_post_enable_bbcode tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, PRIMARY KEY (report_id), KEY post_id (post_id), KEY pm_id (pm_id) diff --git a/phpBB/install/schemas/oracle_schema.sql b/phpBB/install/schemas/oracle_schema.sql index 91f906bc8b..671347ebe1 100644 --- a/phpBB/install/schemas/oracle_schema.sql +++ b/phpBB/install/schemas/oracle_schema.sql @@ -1216,8 +1216,11 @@ CREATE TABLE phpbb_reports ( report_time number(11) DEFAULT '0' NOT NULL, report_text clob DEFAULT '' , reported_post_text clob DEFAULT '' , - reported_post_bitfield varchar2(255) DEFAULT '' , reported_post_uid varchar2(8) DEFAULT '' , + reported_post_bitfield varchar2(255) DEFAULT '' , + reported_post_enable_magic_url number(1) DEFAULT '1' NOT NULL, + reported_post_enable_smilies number(1) DEFAULT '1' NOT NULL, + reported_post_enable_bbcode number(1) DEFAULT '1' NOT NULL, CONSTRAINT pk_phpbb_reports PRIMARY KEY (report_id) ) / diff --git a/phpBB/install/schemas/postgres_schema.sql b/phpBB/install/schemas/postgres_schema.sql index 619985e0d6..4c13bf0ba9 100644 --- a/phpBB/install/schemas/postgres_schema.sql +++ b/phpBB/install/schemas/postgres_schema.sql @@ -855,8 +855,11 @@ CREATE TABLE phpbb_reports ( report_time INT4 DEFAULT '0' NOT NULL CHECK (report_time >= 0), report_text TEXT DEFAULT '' NOT NULL, reported_post_text TEXT DEFAULT '' NOT NULL, - reported_post_bitfield varchar(255) DEFAULT '' NOT NULL, reported_post_uid varchar(8) DEFAULT '' NOT NULL, + reported_post_bitfield varchar(255) DEFAULT '' NOT NULL, + reported_post_enable_magic_url INT2 DEFAULT '1' NOT NULL CHECK (reported_post_enable_magic_url >= 0), + reported_post_enable_smilies INT2 DEFAULT '1' NOT NULL CHECK (reported_post_enable_smilies >= 0), + reported_post_enable_bbcode INT2 DEFAULT '1' NOT NULL CHECK (reported_post_enable_bbcode >= 0), PRIMARY KEY (report_id) ); diff --git a/phpBB/install/schemas/sqlite_schema.sql b/phpBB/install/schemas/sqlite_schema.sql index 1690a7dcab..46a96a1edd 100644 --- a/phpBB/install/schemas/sqlite_schema.sql +++ b/phpBB/install/schemas/sqlite_schema.sql @@ -630,8 +630,11 @@ CREATE TABLE phpbb_reports ( report_time INTEGER UNSIGNED NOT NULL DEFAULT '0', report_text mediumtext(16777215) NOT NULL DEFAULT '', reported_post_text mediumtext(16777215) NOT NULL DEFAULT '', + reported_post_uid varchar(8) NOT NULL DEFAULT '', reported_post_bitfield varchar(255) NOT NULL DEFAULT '', - reported_post_uid varchar(8) NOT NULL DEFAULT '' + reported_post_enable_magic_url INTEGER UNSIGNED NOT NULL DEFAULT '1', + reported_post_enable_smilies INTEGER UNSIGNED NOT NULL DEFAULT '1', + reported_post_enable_bbcode INTEGER UNSIGNED NOT NULL DEFAULT '1' ); CREATE INDEX phpbb_reports_post_id ON phpbb_reports (post_id); From dc649ad3cd8ea4520ad3694027679d6312c9495f Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 5 Dec 2012 11:34:16 -0500 Subject: [PATCH 113/497] [ticket/11248] Line endings to LF. PHPBB3-11248 --- tests/session/append_sid_test.php | 101 +++++++++++++++--------------- 1 file changed, 50 insertions(+), 51 deletions(-) diff --git a/tests/session/append_sid_test.php b/tests/session/append_sid_test.php index 88f6f0718e..ce7bf71215 100644 --- a/tests/session/append_sid_test.php +++ b/tests/session/append_sid_test.php @@ -1,51 +1,50 @@ - 1, 'f' => 2), true, false, 'viewtopic.php?t=1&f=2', 'parameters in params-argument as array'), - - // Custom sid parameter - array('viewtopic.php', 't=1&f=2', true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid', 'using session_id'), - - // Testing anchors - array('viewtopic.php?t=1&f=2#anchor', false, true, false, 'viewtopic.php?t=1&f=2#anchor', 'anchor in url-argument'), - array('viewtopic.php', 't=1&f=2#anchor', true, false, 'viewtopic.php?t=1&f=2#anchor', 'anchor in params-argument'), - array('viewtopic.php', array('t' => 1, 'f' => 2, '#' => 'anchor'), true, false, 'viewtopic.php?t=1&f=2#anchor', 'anchor in params-argument (array)'), - - // Anchors and custom sid - array('viewtopic.php?t=1&f=2#anchor', false, true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid#anchor', 'anchor in url-argument using session_id'), - array('viewtopic.php', 't=1&f=2#anchor', true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid#anchor', 'anchor in params-argument using session_id'), - array('viewtopic.php', array('t' => 1, 'f' => 2, '#' => 'anchor'), true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid#anchor', 'anchor in params-argument (array) using session_id'), - - // Empty parameters should not append the ? - array('viewtopic.php', false, true, false, 'viewtopic.php', 'no params using bool false'), - array('viewtopic.php', '', true, false, 'viewtopic.php', 'no params using empty string'), - array('viewtopic.php', array(), true, false, 'viewtopic.php', 'no params using empty array'), - ); - } - - /** - * @dataProvider append_sid_data - */ - public function test_append_sid($url, $params, $is_amp, $session_id, $expected, $description) - { - $this->assertEquals($expected, append_sid($url, $params, $is_amp, $session_id)); - } -} - + 1, 'f' => 2), true, false, 'viewtopic.php?t=1&f=2', 'parameters in params-argument as array'), + + // Custom sid parameter + array('viewtopic.php', 't=1&f=2', true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid', 'using session_id'), + + // Testing anchors + array('viewtopic.php?t=1&f=2#anchor', false, true, false, 'viewtopic.php?t=1&f=2#anchor', 'anchor in url-argument'), + array('viewtopic.php', 't=1&f=2#anchor', true, false, 'viewtopic.php?t=1&f=2#anchor', 'anchor in params-argument'), + array('viewtopic.php', array('t' => 1, 'f' => 2, '#' => 'anchor'), true, false, 'viewtopic.php?t=1&f=2#anchor', 'anchor in params-argument (array)'), + + // Anchors and custom sid + array('viewtopic.php?t=1&f=2#anchor', false, true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid#anchor', 'anchor in url-argument using session_id'), + array('viewtopic.php', 't=1&f=2#anchor', true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid#anchor', 'anchor in params-argument using session_id'), + array('viewtopic.php', array('t' => 1, 'f' => 2, '#' => 'anchor'), true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid#anchor', 'anchor in params-argument (array) using session_id'), + + // Empty parameters should not append the ? + array('viewtopic.php', false, true, false, 'viewtopic.php', 'no params using bool false'), + array('viewtopic.php', '', true, false, 'viewtopic.php', 'no params using empty string'), + array('viewtopic.php', array(), true, false, 'viewtopic.php', 'no params using empty array'), + ); + } + + /** + * @dataProvider append_sid_data + */ + public function test_append_sid($url, $params, $is_amp, $session_id, $expected, $description) + { + $this->assertEquals($expected, append_sid($url, $params, $is_amp, $session_id)); + } +} From 4103c99a8676653a868014a6f58a76e8986bd5ed Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 1 Mar 2012 16:15:11 +0100 Subject: [PATCH 114/497] [ticket/10679] Add new permission for changing profile field information The setting is copied from "Can use signature" PHPBB3-10679 --- phpBB/includes/ucp/ucp_profile.php | 5 +++ phpBB/install/database_update.php | 48 +++++++++++++++++++-- phpBB/install/schemas/schema_data.sql | 3 +- phpBB/language/en/acp/permissions_phpbb.php | 1 + phpBB/language/en/ucp.php | 1 + phpBB/ucp.php | 6 +++ 6 files changed, 59 insertions(+), 5 deletions(-) diff --git a/phpBB/includes/ucp/ucp_profile.php b/phpBB/includes/ucp/ucp_profile.php index 89bf20a30f..e7cea06a45 100644 --- a/phpBB/includes/ucp/ucp_profile.php +++ b/phpBB/includes/ucp/ucp_profile.php @@ -251,6 +251,11 @@ class ucp_profile break; case 'profile_info': + // Do not display profile information panel if not authed to do so + if (!$auth->acl_get('u_chgprofileinfo')) + { + trigger_error('NO_AUTH_PROFILEINFO'); + } include($phpbb_root_path . 'includes/functions_profile_fields.' . $phpEx); diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index e966756337..f0a16844e9 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -2731,8 +2731,6 @@ function change_database_data(&$no_updates, $version) $config->set('display_last_subject', '1'); } - $no_updates = false; - if (!isset($config['assets_version'])) { $config->set('assets_version', '1'); @@ -2771,7 +2769,7 @@ function change_database_data(&$no_updates, $version) } // PHPBB3-10601: Make inbox default. Add basename to ucp's pm category - + // Get the category wanted while checking, at the same time, if this has already been applied $sql = 'SELECT module_id, module_basename FROM ' . MODULES_TABLE . " @@ -2788,10 +2786,52 @@ function change_database_data(&$no_updates, $version) SET module_basename = 'ucp_pm' WHERE module_id = " . (int) $row['module_id']; - _sql($sql, $errored, $error_ary); + _sql($sql, $errored, $error_ary); } $db->sql_freeresult($result); + // Add new permission u_chgprofileinfo and duplicate settings from u_sig + include_once($phpbb_root_path . 'includes/acp/auth.' . $phpEx); + $auth_admin = new auth_admin(); + + // Only add the new permission if it does not already exist + if (empty($auth_admin->acl_options['id']['u_chgprofileinfo'])) + { + $auth_admin->acl_add_option(array('global' => array('u_chgprofileinfo'))); + + // Now the tricky part, filling the permission + $old_id = $auth_admin->acl_options['id']['u_sig']; + $new_id = $auth_admin->acl_options['id']['u_chgprofileinfo']; + + $tables = array(ACL_GROUPS_TABLE, ACL_ROLES_DATA_TABLE, ACL_USERS_TABLE); + + foreach ($tables as $table) + { + $sql = 'SELECT * + FROM ' . $table . ' + WHERE auth_option_id = ' . $old_id; + $result = _sql($sql, $errored, $error_ary); + + $sql_ary = array(); + while ($row = $db->sql_fetchrow($result)) + { + $row['auth_option_id'] = $new_id; + $sql_ary[] = $row; + } + $db->sql_freeresult($result); + + if (sizeof($sql_ary)) + { + $db->sql_multi_insert($table, $sql_ary); + } + } + + // Remove any old permission entries + $auth_admin->acl_clear_prefetch(); + } + + $no_updates = false; + break; } } diff --git a/phpBB/install/schemas/schema_data.sql b/phpBB/install/schemas/schema_data.sql index dbb5fd7481..7c1a7d40f5 100644 --- a/phpBB/install/schemas/schema_data.sql +++ b/phpBB/install/schemas/schema_data.sql @@ -387,6 +387,7 @@ INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_chgemail', 1); INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_chggrp', 1); INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_chgname', 1); INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_chgpasswd', 1); +INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_chgprofileinfo', 1); INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_download', 1); INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_hideonline', 1); INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_ignoreflood', 1); @@ -548,7 +549,7 @@ INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 22, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option NOT IN ('f_announce', 'f_attach', 'f_bump', 'f_delete', 'f_flash', 'f_icons', 'f_ignoreflood', 'f_sticky', 'f_user_lock', 'f_votechg'); # New Member (u_) -INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 23, auth_option_id, 0 FROM phpbb_acl_options WHERE auth_option LIKE 'u_%' AND auth_option IN ('u_sendpm', 'u_masspm', 'u_masspm_group'); +INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 23, auth_option_id, 0 FROM phpbb_acl_options WHERE auth_option LIKE 'u_%' AND auth_option IN ('u_sendpm', 'u_masspm', 'u_masspm_group', 'u_chgprofileinfo'); # New Member (f_) INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 24, auth_option_id, 0 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option IN ('f_noapprove'); diff --git a/phpBB/language/en/acp/permissions_phpbb.php b/phpBB/language/en/acp/permissions_phpbb.php index b142cfd9aa..27ef714f8b 100644 --- a/phpBB/language/en/acp/permissions_phpbb.php +++ b/phpBB/language/en/acp/permissions_phpbb.php @@ -102,6 +102,7 @@ $lang = array_merge($lang, array( 'acl_u_chgemail' => array('lang' => 'Can change email address', 'cat' => 'profile'), 'acl_u_chgavatar' => array('lang' => 'Can change avatar', 'cat' => 'profile'), 'acl_u_chggrp' => array('lang' => 'Can change default usergroup', 'cat' => 'profile'), + 'acl_u_chgprofileinfo' => array('lang' => 'Can change profile field information', 'cat' => 'profile'), 'acl_u_attach' => array('lang' => 'Can attach files', 'cat' => 'post'), 'acl_u_download' => array('lang' => 'Can download files', 'cat' => 'post'), diff --git a/phpBB/language/en/ucp.php b/phpBB/language/en/ucp.php index b919699ea0..267ae00710 100644 --- a/phpBB/language/en/ucp.php +++ b/phpBB/language/en/ucp.php @@ -318,6 +318,7 @@ $lang = array_merge($lang, array( 'NO_AUTH_FORWARD_MESSAGE' => 'You are not authorised to forward private messages.', 'NO_AUTH_GROUP_MESSAGE' => 'You are not authorised to send private messages to groups.', 'NO_AUTH_PASSWORD_REMINDER' => 'You are not authorised to request a new password.', + 'NO_AUTH_PROFILEINFO' => 'You are not authorised to change your profile information.', 'NO_AUTH_READ_HOLD_MESSAGE' => 'You are not authorised to read private messages that are on hold.', 'NO_AUTH_READ_MESSAGE' => 'You are not authorised to read private messages.', 'NO_AUTH_READ_REMOVED_MESSAGE' => 'You are not able to read this message because it was removed by the author.', diff --git a/phpBB/ucp.php b/phpBB/ucp.php index a7e75f76c4..7f4cd94f6f 100644 --- a/phpBB/ucp.php +++ b/phpBB/ucp.php @@ -334,6 +334,12 @@ if (!$config['allow_topic_notify'] && !$config['allow_forum_notify']) $vars = array('module', 'id', 'mode'); extract($phpbb_dispatcher->trigger_event('core.ucp_display_module_before', compact($vars))); +// Do not display profile information panel if not authed to do so +if (!$auth->acl_get('u_chgprofileinfo')) +{ + $module->set_display('profile', 'profile_info', false); +} + // Select the active module $module->set_active($id, $mode); From 2f490293e4b8d08d6c1008ef5ea324ae259d9993 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 6 Dec 2012 16:33:12 +0100 Subject: [PATCH 115/497] [ticket/10679] Use module_auth to limit access to the module PHPBB3-10679 --- phpBB/includes/ucp/info/ucp_profile.php | 2 +- phpBB/install/database_update.php | 8 ++++++++ phpBB/ucp.php | 6 ------ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/phpBB/includes/ucp/info/ucp_profile.php b/phpBB/includes/ucp/info/ucp_profile.php index 201216e9fd..3581a7f533 100644 --- a/phpBB/includes/ucp/info/ucp_profile.php +++ b/phpBB/includes/ucp/info/ucp_profile.php @@ -19,7 +19,7 @@ class ucp_profile_info 'title' => 'UCP_PROFILE', 'version' => '1.0.0', 'modes' => array( - 'profile_info' => array('title' => 'UCP_PROFILE_PROFILE_INFO', 'auth' => '', 'cat' => array('UCP_PROFILE')), + 'profile_info' => array('title' => 'UCP_PROFILE_PROFILE_INFO', 'auth' => 'acl_u_chgprofileinfo', 'cat' => array('UCP_PROFILE')), 'signature' => array('title' => 'UCP_PROFILE_SIGNATURE', 'auth' => 'acl_u_sig', 'cat' => array('UCP_PROFILE')), 'avatar' => array('title' => 'UCP_PROFILE_AVATAR', 'auth' => 'cfg_allow_avatar && (cfg_allow_avatar_local || cfg_allow_avatar_remote || cfg_allow_avatar_upload || cfg_allow_avatar_remote_upload)', 'cat' => array('UCP_PROFILE')), 'reg_details' => array('title' => 'UCP_PROFILE_REG_DETAILS', 'auth' => '', 'cat' => array('UCP_PROFILE')), diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index f0a16844e9..95fd1ca2c2 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -2830,6 +2830,14 @@ function change_database_data(&$no_updates, $version) $auth_admin->acl_clear_prefetch(); } + // Update the auth setting for the module + $sql = 'UPDATE ' . MODULES_TABLE . " + SET module_auth = 'acl_u_chgprofileinfo' + WHERE module_class = 'ucp' + AND module_basename = 'profile' + AND module_mode = 'profile_info'"; + _sql($sql, $errored, $error_ary); + $no_updates = false; break; diff --git a/phpBB/ucp.php b/phpBB/ucp.php index 7f4cd94f6f..a7e75f76c4 100644 --- a/phpBB/ucp.php +++ b/phpBB/ucp.php @@ -334,12 +334,6 @@ if (!$config['allow_topic_notify'] && !$config['allow_forum_notify']) $vars = array('module', 'id', 'mode'); extract($phpbb_dispatcher->trigger_event('core.ucp_display_module_before', compact($vars))); -// Do not display profile information panel if not authed to do so -if (!$auth->acl_get('u_chgprofileinfo')) -{ - $module->set_display('profile', 'profile_info', false); -} - // Select the active module $module->set_active($id, $mode); From 70050020699d9eab9b97bda342e0e928d1591de8 Mon Sep 17 00:00:00 2001 From: Fyorl Date: Sun, 8 Jul 2012 20:22:19 +0100 Subject: [PATCH 116/497] [ticket/10972] Added methods for creating and deleting basic users Modified the login method to allow logging in of an arbitrary user. Also added tests for the new functionality. PHPBB3-10972 --- tests/functional/new_user_test.php | 45 +++++++++++++++++++ .../phpbb_functional_test_case.php | 45 ++++++++++++++++++- 2 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 tests/functional/new_user_test.php diff --git a/tests/functional/new_user_test.php b/tests/functional/new_user_test.php new file mode 100644 index 0000000000..db2f31f450 --- /dev/null +++ b/tests/functional/new_user_test.php @@ -0,0 +1,45 @@ +create_user('user'); + $this->login(); + $crawler = $this->request('GET', 'memberlist.php?sid=' . $this->sid); + $this->assertContains('user', $crawler->filter('#memberlist tr')->eq(1)->text()); + } + + /** + * @depends test_create_user + */ + public function test_delete_user() + { + $this->delete_user('user'); + $this->login(); + $crawler = $this->request('GET', 'memberlist.php?sid=' . $this->sid); + $this->assertEquals(2, $crawler->filter('#memberlist tr')->count()); + } + + /** + * @depends test_delete_user + */ + public function test_login_other() + { + $this->create_user('user'); + $this->login('user'); + $crawler = $this->request('GET', 'index.php'); + $this->assertContains('user', $crawler->filter('.icon-logout')->text()); + $this->delete_user('user'); + } +} diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 7c03f874e9..dfbfe2565e 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -194,7 +194,48 @@ class phpbb_functional_test_case extends phpbb_test_case $db_conn_mgr->recreate_db(); } - protected function login() + /** + * Creates a new user with limited permissions + * + * @param string $username Also doubles up as the user's password + */ + protected function create_user($username) + { + // Required by unique_id + global $config; + + if (!is_array($config)) + { + $config = array(); + } + + $config['rand_seed'] = ''; + $config['rand_seed_last_update'] = time() + 600; + + $db = $this->get_db(); + $query = " + INSERT INTO " . self::$config['table_prefix'] . "users + (user_type, group_id, username, username_clean, user_regdate, user_password, user_email, user_lang, user_style, user_rank, user_colour, user_posts, user_permissions, user_ip, user_birthday, user_lastpage, user_last_confirm_key, user_post_sortby_type, user_post_sortby_dir, user_topic_sortby_type, user_topic_sortby_dir, user_avatar, user_sig, user_sig_bbcode_uid, user_from, user_icq, user_aim, user_yim, user_msnm, user_jabber, user_website, user_occ, user_interests, user_actkey, user_newpasswd) + VALUES + (0, 2, 'user', 'user', 0, '" . phpbb_hash($username) . "', 'nobody@example.com', 'en', 1, 0, '', 1, '', '', '', '', '', 't', 'a', 't', 'd', '', '', '', '', '', '', '', '', '', '', '', '', '', '') + "; + + $db->sql_query($query); + } + + /** + * Deletes a user + * + * @param string $username The username of the user to delete + */ + protected function delete_user($username) + { + $db = $this->get_db(); + $query = "DELETE FROM " . self::$config['table_prefix'] . "users WHERE username = '" . $db->sql_escape($username) . "'"; + $db->sql_query($query); + } + + protected function login($username = 'admin') { $this->add_lang('ucp'); @@ -202,7 +243,7 @@ class phpbb_functional_test_case extends phpbb_test_case $this->assertContains($this->lang('LOGIN_EXPLAIN_UCP'), $crawler->filter('html')->text()); $form = $crawler->selectButton($this->lang('LOGIN'))->form(); - $login = $this->client->submit($form, array('username' => 'admin', 'password' => 'admin')); + $login = $this->client->submit($form, array('username' => $username, 'password' => $username)); $cookies = $this->cookieJar->all(); From cafc7feca12730fce59091bd7a18fb5c3f7ecdc0 Mon Sep 17 00:00:00 2001 From: Fyorl Date: Mon, 9 Jul 2012 00:24:28 +0100 Subject: [PATCH 117/497] [ticket/10972] Moved tests into appropriate places and added comments PHPBB3-10972 --- tests/functional/auth_test.php | 9 ++++ tests/functional/new_user_test.php | 45 ------------------- .../phpbb_functional_test_case.php | 4 ++ 3 files changed, 13 insertions(+), 45 deletions(-) delete mode 100644 tests/functional/new_user_test.php diff --git a/tests/functional/auth_test.php b/tests/functional/auth_test.php index e955dcb4df..e67118d8f9 100644 --- a/tests/functional/auth_test.php +++ b/tests/functional/auth_test.php @@ -21,6 +21,15 @@ class phpbb_functional_auth_test extends phpbb_functional_test_case $this->assertContains($this->lang('LOGOUT_USER', 'admin'), $crawler->filter('.navbar')->text()); } + public function test_login_other() + { + $this->create_user('user'); + $this->login('user'); + $crawler = $this->request('GET', 'index.php'); + $this->assertContains('user', $crawler->filter('.icon-logout')->text()); + $this->delete_user('user'); + } + /** * @depends test_login */ diff --git a/tests/functional/new_user_test.php b/tests/functional/new_user_test.php deleted file mode 100644 index db2f31f450..0000000000 --- a/tests/functional/new_user_test.php +++ /dev/null @@ -1,45 +0,0 @@ -create_user('user'); - $this->login(); - $crawler = $this->request('GET', 'memberlist.php?sid=' . $this->sid); - $this->assertContains('user', $crawler->filter('#memberlist tr')->eq(1)->text()); - } - - /** - * @depends test_create_user - */ - public function test_delete_user() - { - $this->delete_user('user'); - $this->login(); - $crawler = $this->request('GET', 'memberlist.php?sid=' . $this->sid); - $this->assertEquals(2, $crawler->filter('#memberlist tr')->count()); - } - - /** - * @depends test_delete_user - */ - public function test_login_other() - { - $this->create_user('user'); - $this->login('user'); - $crawler = $this->request('GET', 'index.php'); - $this->assertContains('user', $crawler->filter('.icon-logout')->text()); - $this->delete_user('user'); - } -} diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index dfbfe2565e..a72c0940ab 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -197,6 +197,10 @@ class phpbb_functional_test_case extends phpbb_test_case /** * Creates a new user with limited permissions * + * Note that creating two users with the same name results in undefined + * login behaviour. Always call delete_user after running a test that + * requires create_user. + * * @param string $username Also doubles up as the user's password */ protected function create_user($username) From d33accb687ab4266559c12a356e121f3634d780b Mon Sep 17 00:00:00 2001 From: Fyorl Date: Fri, 10 Aug 2012 12:31:53 +0100 Subject: [PATCH 118/497] [ticket/10972] Added explicit checks for creating duplicate users. PHPBB3-10972 --- .../phpbb_functional_test_case.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index a72c0940ab..9bc2c96753 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -30,6 +30,11 @@ class phpbb_functional_test_case extends phpbb_test_case */ protected $lang = array(); + /** + * @var array + */ + protected $created_users = array(); + static protected $config = array(); static protected $already_installed = false; @@ -197,14 +202,18 @@ class phpbb_functional_test_case extends phpbb_test_case /** * Creates a new user with limited permissions * - * Note that creating two users with the same name results in undefined - * login behaviour. Always call delete_user after running a test that + * Always call delete_user after running a test that * requires create_user. * * @param string $username Also doubles up as the user's password */ protected function create_user($username) { + if (isset($this->created_users[$username])) + { + return; + } + // Required by unique_id global $config; @@ -225,6 +234,7 @@ class phpbb_functional_test_case extends phpbb_test_case "; $db->sql_query($query); + $this->created_users[$username] = 1; } /** @@ -234,6 +244,11 @@ class phpbb_functional_test_case extends phpbb_test_case */ protected function delete_user($username) { + if (isset($this->created_users[$username])) + { + unset($this->created_users[$username]); + } + $db = $this->get_db(); $query = "DELETE FROM " . self::$config['table_prefix'] . "users WHERE username = '" . $db->sql_escape($username) . "'"; $db->sql_query($query); From ebdd96592a100139c48204ef133e706c0ac465d1 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 6 Dec 2012 22:45:12 -0500 Subject: [PATCH 119/497] [ticket/10972] Backport get_db from develop. PHPBB3-10972 --- .../phpbb_functional_test_case.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 9bc2c96753..3b6232d091 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -16,7 +16,9 @@ class phpbb_functional_test_case extends phpbb_test_case { protected $client; protected $root_url; + protected $cache = null; + protected $db = null; /** * Session ID for current test's session (each test makes its own) @@ -70,6 +72,23 @@ class phpbb_functional_test_case extends phpbb_test_case { } + protected function get_db() + { + global $phpbb_root_path, $phpEx; + // so we don't reopen an open connection + if (!($this->db instanceof dbal)) + { + if (!class_exists('dbal_' . self::$config['dbms'])) + { + include($phpbb_root_path . 'includes/db/' . self::$config['dbms'] . ".$phpEx"); + } + $sql_db = 'dbal_' . self::$config['dbms']; + $this->db = new $sql_db(); + $this->db->sql_connect(self::$config['dbhost'], self::$config['dbuser'], self::$config['dbpasswd'], self::$config['dbname'], self::$config['dbport']); + } + return $this->db; + } + protected function get_cache_driver() { if (!$this->cache) From 771bb957ab4dee865ce1678eb675c37874d04e98 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 6 Dec 2012 23:41:02 -0500 Subject: [PATCH 120/497] [ticket/10972] Add mock null cache. The mock cache has instrumentation methods and therefore is non-trivial to implement. For those times when we don't care that the cache caches, null cache is a simpler implementation. PHPBB3-10972 --- tests/mock/null_cache.php | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tests/mock/null_cache.php diff --git a/tests/mock/null_cache.php b/tests/mock/null_cache.php new file mode 100644 index 0000000000..aca20ca77b --- /dev/null +++ b/tests/mock/null_cache.php @@ -0,0 +1,42 @@ + Date: Thu, 6 Dec 2012 23:42:13 -0500 Subject: [PATCH 121/497] [ticket/10972] Add destroy method to mock cache. I actually needed the version that destroys tables, therefore I ended up writing a mock null cache. This code is currently unused but will probably be handy at some point. PHPBB3-10972 --- tests/mock/cache.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/mock/cache.php b/tests/mock/cache.php index 650545c3d6..aa0db5ab20 100644 --- a/tests/mock/cache.php +++ b/tests/mock/cache.php @@ -34,6 +34,16 @@ class phpbb_mock_cache $this->data[$var_name] = $var; } + public function destroy($var_name, $table = '') + { + if ($table) + { + throw new Exception('Destroying tables is not implemented yet'); + } + + unset($this->data[$var_name]); + } + /** * Obtain active bots */ @@ -41,7 +51,7 @@ class phpbb_mock_cache { return $this->data['_bots']; } - + /** * Obtain list of word censors. We don't need to parse them here, * that is tested elsewhere. From fb5c4440e598f2a775a52299a06e903d3cee5398 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 6 Dec 2012 23:43:22 -0500 Subject: [PATCH 122/497] [ticket/10972] Tweak user addition. Always add users, do not keep track of which users have been added. The tests should know whether users they want exist or not. Use more unique user names in tests for robustness. Added some more assertions here and there. PHPBB3-10972 --- tests/functional/auth_test.php | 12 ++-- .../phpbb_functional_test_case.php | 59 +++++++++++-------- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/tests/functional/auth_test.php b/tests/functional/auth_test.php index e67118d8f9..3e218ebd77 100644 --- a/tests/functional/auth_test.php +++ b/tests/functional/auth_test.php @@ -18,16 +18,18 @@ class phpbb_functional_auth_test extends phpbb_functional_test_case // check for logout link $crawler = $this->request('GET', 'index.php'); + $this->assert_response_success(); $this->assertContains($this->lang('LOGOUT_USER', 'admin'), $crawler->filter('.navbar')->text()); } public function test_login_other() { - $this->create_user('user'); - $this->login('user'); + $this->create_user('anothertestuser'); + $this->login('anothertestuser'); $crawler = $this->request('GET', 'index.php'); - $this->assertContains('user', $crawler->filter('.icon-logout')->text()); - $this->delete_user('user'); + $this->assert_response_success(); + $this->assertContains('anothertestuser', $crawler->filter('.icon-logout')->text()); + $this->delete_user('anothertestuser'); } /** @@ -40,10 +42,12 @@ class phpbb_functional_auth_test extends phpbb_functional_test_case // logout $crawler = $this->request('GET', 'ucp.php?sid=' . $this->sid . '&mode=logout'); + $this->assert_response_success(); $this->assertContains($this->lang('LOGOUT_REDIRECT'), $crawler->filter('#message')->text()); // look for a register link, which should be visible only when logged out $crawler = $this->request('GET', 'index.php'); + $this->assert_response_success(); $this->assertContains($this->lang('REGISTER'), $crawler->filter('.navbar')->text()); } } diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 3b6232d091..b17b2dcd5f 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -32,11 +32,6 @@ class phpbb_functional_test_case extends phpbb_test_case */ protected $lang = array(); - /** - * @var array - */ - protected $created_users = array(); - static protected $config = array(); static protected $already_installed = false; @@ -225,14 +220,10 @@ class phpbb_functional_test_case extends phpbb_test_case * requires create_user. * * @param string $username Also doubles up as the user's password + * @return int ID of created user */ protected function create_user($username) { - if (isset($this->created_users[$username])) - { - return; - } - // Required by unique_id global $config; @@ -243,17 +234,36 @@ class phpbb_functional_test_case extends phpbb_test_case $config['rand_seed'] = ''; $config['rand_seed_last_update'] = time() + 600; - - $db = $this->get_db(); - $query = " - INSERT INTO " . self::$config['table_prefix'] . "users - (user_type, group_id, username, username_clean, user_regdate, user_password, user_email, user_lang, user_style, user_rank, user_colour, user_posts, user_permissions, user_ip, user_birthday, user_lastpage, user_last_confirm_key, user_post_sortby_type, user_post_sortby_dir, user_topic_sortby_type, user_topic_sortby_dir, user_avatar, user_sig, user_sig_bbcode_uid, user_from, user_icq, user_aim, user_yim, user_msnm, user_jabber, user_website, user_occ, user_interests, user_actkey, user_newpasswd) - VALUES - (0, 2, 'user', 'user', 0, '" . phpbb_hash($username) . "', 'nobody@example.com', 'en', 1, 0, '', 1, '', '', '', '', '', 't', 'a', 't', 'd', '', '', '', '', '', '', '', '', '', '', '', '', '', '') - "; - $db->sql_query($query); - $this->created_users[$username] = 1; + // Required by user_add + global $db, $cache; + $db = $this->get_db(); + if (!function_exists('phpbb_mock_null_cache')) + { + require_once(__DIR__ . '/../mock/null_cache.php'); + } + $cache = new phpbb_mock_null_cache; + + if (!function_exists('utf_clean_string')) + { + require_once(__DIR__ . '/../../phpBB/includes/utf/utf_tools.php'); + } + if (!function_exists('user_add')) + { + require_once(__DIR__ . '/../../phpBB/includes/functions_user.php'); + } + + $user_row = array( + 'username' => $username, + 'group_id' => 2, + 'user_email' => 'nobody@example.com', + 'user_type' => 0, + 'user_lang' => 'en', + 'user_timezone' => 0, + 'user_dateformat' => '', + 'user_password' => phpbb_hash($username), + ); + return user_add($user_row); } /** @@ -263,11 +273,6 @@ class phpbb_functional_test_case extends phpbb_test_case */ protected function delete_user($username) { - if (isset($this->created_users[$username])) - { - unset($this->created_users[$username]); - } - $db = $this->get_db(); $query = "DELETE FROM " . self::$config['table_prefix'] . "users WHERE username = '" . $db->sql_escape($username) . "'"; $db->sql_query($query); @@ -281,7 +286,9 @@ class phpbb_functional_test_case extends phpbb_test_case $this->assertContains($this->lang('LOGIN_EXPLAIN_UCP'), $crawler->filter('html')->text()); $form = $crawler->selectButton($this->lang('LOGIN'))->form(); - $login = $this->client->submit($form, array('username' => $username, 'password' => $username)); + $crawler = $this->client->submit($form, array('username' => $username, 'password' => $username)); + $this->assert_response_success(); + $this->assertContains($this->lang('LOGIN_REDIRECT'), $crawler->filter('html')->text()); $cookies = $this->cookieJar->all(); From ff993ba9d30f5de49e5231647c5bb76d95c357f8 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 6 Dec 2012 23:47:19 -0500 Subject: [PATCH 123/497] [ticket/10972] Drop user deletion. Users should not be deleted in tests that test user creation. Tests should use unique user names to avoid collisions. User deletion should use user_remove anyway. PHPBB3-10972 --- tests/functional/auth_test.php | 1 - .../test_framework/phpbb_functional_test_case.php | 15 --------------- 2 files changed, 16 deletions(-) diff --git a/tests/functional/auth_test.php b/tests/functional/auth_test.php index 3e218ebd77..662b1bd38b 100644 --- a/tests/functional/auth_test.php +++ b/tests/functional/auth_test.php @@ -29,7 +29,6 @@ class phpbb_functional_auth_test extends phpbb_functional_test_case $crawler = $this->request('GET', 'index.php'); $this->assert_response_success(); $this->assertContains('anothertestuser', $crawler->filter('.icon-logout')->text()); - $this->delete_user('anothertestuser'); } /** diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index b17b2dcd5f..71e88fbcf6 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -216,9 +216,6 @@ class phpbb_functional_test_case extends phpbb_test_case /** * Creates a new user with limited permissions * - * Always call delete_user after running a test that - * requires create_user. - * * @param string $username Also doubles up as the user's password * @return int ID of created user */ @@ -266,18 +263,6 @@ class phpbb_functional_test_case extends phpbb_test_case return user_add($user_row); } - /** - * Deletes a user - * - * @param string $username The username of the user to delete - */ - protected function delete_user($username) - { - $db = $this->get_db(); - $query = "DELETE FROM " . self::$config['table_prefix'] . "users WHERE username = '" . $db->sql_escape($username) . "'"; - $db->sql_query($query); - } - protected function login($username = 'admin') { $this->add_lang('ucp'); From 25780c17a4e9c1e96e8f1648bd9bd16ff06afb7f Mon Sep 17 00:00:00 2001 From: Bruno Ais Date: Sun, 2 Dec 2012 22:59:11 +0000 Subject: [PATCH 124/497] [ticket/11171] DB changes for the update These are the changes to database_update.php required for this ticket. PHPBB3-11171 --- phpBB/install/database_update.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index e966756337..060d749b92 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -2792,6 +2792,23 @@ function change_database_data(&$no_updates, $version) } $db->sql_freeresult($result); + // PHPBB3-11171: Copy bbcode fields, etc. for reported posts. Add 5 columns to the reports table + + // Add the columns used by these changes + $changes['add_columns'] = array( + REPORTS_TABLE => array( + 'reported_post_enable_bbcode' => array('BOOL', 1), + 'reported_post_enable_smilies' => array('BOOL', 1), + 'reported_post_enable_magic_url' => array('BOOL', 1) + ) + ); + $statements = $db_tools->perform_schema_changes($changes); + + foreach ($statements as $sql) + { + _sql($sql, $errored, $error_ary); + } + break; } } From 83a71a2e777dcc9d1c717b6bf438b9aaf41dffba Mon Sep 17 00:00:00 2001 From: Bruno Ais Date: Sun, 2 Dec 2012 23:01:29 +0000 Subject: [PATCH 125/497] [ticket/11171] Use the options stored to decide how to show it Added what's needed so that the post in the report is parsed the same way as it was being parsed when the post was reported PHPBB3-11171 --- phpBB/includes/mcp/mcp_reports.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/phpBB/includes/mcp/mcp_reports.php b/phpBB/includes/mcp/mcp_reports.php index 3426d62cdb..ca730f7728 100644 --- a/phpBB/includes/mcp/mcp_reports.php +++ b/phpBB/includes/mcp/mcp_reports.php @@ -71,7 +71,7 @@ class mcp_reports // closed reports are accessed by report id $report_id = request_var('r', 0); - $sql = 'SELECT r.post_id, r.user_id, r.report_id, r.report_closed, report_time, r.report_text, r.reported_post_text, r.reported_post_uid, r.reported_post_bitfield, rr.reason_title, rr.reason_description, u.username, u.username_clean, u.user_colour + $sql = 'SELECT r.post_id, r.user_id, r.report_id, r.report_closed, report_time, r.report_text, r.reported_post_text, r.reported_post_uid, r.reported_post_bitfield, r.reported_post_enable_magic_url, r.reported_post_enable_smilies, r.reported_post_enable_bbcode, rr.reason_title, rr.reason_description, u.username, u.username_clean, u.user_colour FROM ' . REPORTS_TABLE . ' r, ' . REPORTS_REASONS_TABLE . ' rr, ' . USERS_TABLE . ' u WHERE ' . (($report_id) ? 'r.report_id = ' . $report_id : "r.post_id = $post_id") . ' AND rr.reason_id = r.reason_id @@ -94,6 +94,10 @@ class mcp_reports $post_id = $report['post_id']; $report_id = $report['report_id']; + + $parse_post_flags = $report['reported_post_enable_bbcode'] ? OPTION_FLAG_BBCODE : 0; + $parse_post_flags += $report['reported_post_enable_smilies'] ? OPTION_FLAG_SMILIES : 0; + $parse_post_flags += $report['reported_post_enable_magic_url'] ? OPTION_FLAG_LINKS : 0; $post_info = get_post_data(array($post_id), 'm_report', true); @@ -227,7 +231,7 @@ class mcp_reports 'REPORTER_NAME' => get_username_string('username', $report['user_id'], $report['username'], $report['user_colour']), 'U_VIEW_REPORTER_PROFILE' => get_username_string('profile', $report['user_id'], $report['username'], $report['user_colour']), - 'POST_PREVIEW' => generate_text_for_display($report['reported_post_text'], $report['reported_post_uid'], $report['reported_post_bitfield'], OPTION_FLAG_BBCODE | OPTION_FLAG_SMILIES, false), + 'POST_PREVIEW' => generate_text_for_display($report['reported_post_text'], $report['reported_post_uid'], $report['reported_post_bitfield'], $parse_post_flags, false), 'POST_SUBJECT' => ($post_info['post_subject']) ? $post_info['post_subject'] : $user->lang['NO_SUBJECT'], 'POST_DATE' => $user->format_date($post_info['post_time']), 'POST_IP' => $post_info['poster_ip'], From 91246c20fa8b9218fe0ddc8b52236d4b878346dd Mon Sep 17 00:00:00 2001 From: Bruno Ais Date: Sun, 2 Dec 2012 23:07:40 +0000 Subject: [PATCH 126/497] [ticket/11171] Adapted the code in report.php Added the variable aliases needed (to look and feel the same as it was before) Added the variables into the table insert. PHPBB3-11171 --- phpBB/report.php | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/phpBB/report.php b/phpBB/report.php index d792b8df6a..be38bad2f3 100644 --- a/phpBB/report.php +++ b/phpBB/report.php @@ -71,11 +71,14 @@ if ($post_id) trigger_error('POST_NOT_EXIST'); } - $forum_id = (int) $report_data['forum_id']; - $topic_id = (int) $report_data['topic_id']; - $reported_post_text = $report_data['post_text']; - $reported_post_bitfield = $report_data['bbcode_bitfield']; - $reported_post_uid = $report_data['bbcode_uid']; + $forum_id = (int) $report_data['forum_id']; + $topic_id = (int) $report_data['topic_id']; + $reported_post_text = $report_data['post_text']; + $reported_post_bitfield = $report_data['bbcode_bitfield']; + $reported_post_uid = $report_data['bbcode_uid']; + $reported_post_enable_bbcode = $report_data['enable_bbcode']; + $reported_post_enable_smilies = $report_data['enable_smilies']; + $reported_post_enable_magic_url = $report_data['enable_magic_url']; $sql = 'SELECT * FROM ' . FORUMS_TABLE . ' @@ -134,9 +137,11 @@ else trigger_error($message); } - $reported_post_text = $report_data['message_text']; - $reported_post_bitfield = $report_data['bbcode_bitfield']; - $reported_post_uid = $report_data['bbcode_uid']; + $reported_post_text = $report_data['message_text']; + $reported_post_bitfield = $report_data['bbcode_bitfield']; + $reported_post_enable_bbcode = $report_data['reported_post_enable_bbcode']; + $reported_post_enable_smilies = $report_data['reported_post_enable_smilies']; + $reported_post_enable_magic_url = $report_data['reported_post_enable_magic_url']; } // Submit report? @@ -155,17 +160,20 @@ if ($submit && $reason_id) } $sql_ary = array( - 'reason_id' => (int) $reason_id, - 'post_id' => $post_id, - 'pm_id' => $pm_id, - 'user_id' => (int) $user->data['user_id'], - 'user_notify' => (int) $user_notify, - 'report_closed' => 0, - 'report_time' => (int) time(), - 'report_text' => (string) $report_text, - 'reported_post_text' => $reported_post_text, - 'reported_post_uid' => $reported_post_uid, - 'reported_post_bitfield'=> $reported_post_bitfield, + 'reason_id' => (int) $reason_id, + 'post_id' => $post_id, + 'pm_id' => $pm_id, + 'user_id' => (int) $user->data['user_id'], + 'user_notify' => (int) $user_notify, + 'report_closed' => 0, + 'report_time' => (int) time(), + 'report_text' => (string) $report_text, + 'reported_post_text' => $reported_post_text, + 'reported_post_uid' => $reported_post_uid, + 'reported_post_bitfield' => $reported_post_bitfield, + 'reported_post_enable_bbcode' => $reported_post_enable_bbcode, + 'reported_post_enable_smilies' => $reported_post_enable_smilies, + 'reported_post_enable_magic_url' => $reported_post_enable_magic_url, ); $sql = 'INSERT INTO ' . REPORTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); From 73971ef0fa2a53b056847a524bb84f8b2d3e5a4b Mon Sep 17 00:00:00 2001 From: Bruno Ais Date: Sun, 2 Dec 2012 23:19:59 +0000 Subject: [PATCH 127/497] [ticket/11171] Cleanup of leftovers I didn't notice that there were actually leftovers from the other PR. Anyway, this will remove all the leftovers I noticed from the other PR. PHPBB3-11171 --- phpBB/includes/mcp/mcp_reports.php | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/phpBB/includes/mcp/mcp_reports.php b/phpBB/includes/mcp/mcp_reports.php index ca730f7728..8da303f6e3 100644 --- a/phpBB/includes/mcp/mcp_reports.php +++ b/phpBB/includes/mcp/mcp_reports.php @@ -140,18 +140,7 @@ class mcp_reports $post_unread = (isset($topic_tracking_info[$post_info['topic_id']]) && $post_info['post_time'] > $topic_tracking_info[$post_info['topic_id']]) ? true : false; - // Process message, leave it uncensored - $message = $post_info['post_text']; - if ($post_info['bbcode_bitfield']) - { - include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx); - $bbcode = new bbcode($post_info['bbcode_bitfield']); - $bbcode->bbcode_second_pass($message, $post_info['bbcode_uid'], $post_info['bbcode_bitfield']); - } - - $message = bbcode_nl2br($message); - $message = smiley_text($message); $report['report_text'] = make_clickable(bbcode_nl2br($report['report_text'])); if ($post_info['post_attachment'] && $auth->acl_get('u_download') && $auth->acl_get('f_download', $post_info['forum_id'])) @@ -172,7 +161,7 @@ class mcp_reports if (sizeof($attachments)) { $update_count = array(); - parse_attachments($post_info['forum_id'], $message, $attachments, $update_count); + parse_attachments($post_info['forum_id'], $report['reported_post_text'], $attachments, $update_count); } // Display not already displayed Attachments for this post, we already parsed them. ;) From c23d2457e9be616bfa83aebc5e743130b6c69624 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Fri, 7 Dec 2012 12:50:21 +0100 Subject: [PATCH 128/497] [ticket/10679] Update module basename, we added the xcp_ prefix in 3.1 PHPBB3-10679 --- phpBB/install/database_update.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 95fd1ca2c2..30592b995d 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -2834,7 +2834,7 @@ function change_database_data(&$no_updates, $version) $sql = 'UPDATE ' . MODULES_TABLE . " SET module_auth = 'acl_u_chgprofileinfo' WHERE module_class = 'ucp' - AND module_basename = 'profile' + AND module_basename = 'ucp_profile' AND module_mode = 'profile_info'"; _sql($sql, $errored, $error_ary); From 9eecaa21e3fe23c0c1afc7f8d057754fca68e9a6 Mon Sep 17 00:00:00 2001 From: Bruno Ais Date: Thu, 6 Dec 2012 11:22:56 +0000 Subject: [PATCH 129/497] [ticket/11171] Moved the DB schema changes to its place Moved the db changes schema to the place where all the other schema changes are. PHPBB3-11171 --- phpBB/install/database_update.php | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 060d749b92..91365d4a72 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -1123,9 +1123,12 @@ function database_update_info() 'style_parent_tree' => array('TEXT', ''), ), REPORTS_TABLE => array( - 'reported_post_text' => array('MTEXT_UNI', ''), - 'reported_post_uid' => array('VCHAR:8', ''), - 'reported_post_bitfield' => array('VCHAR:255', ''), + 'reported_post_text' => array('MTEXT_UNI', ''), + 'reported_post_uid' => array('VCHAR:8', ''), + 'reported_post_bitfield' => array('VCHAR:255', ''), + 'reported_post_enable_bbcode' => array('BOOL', 1), + 'reported_post_enable_smilies' => array('BOOL', 1), + 'reported_post_enable_magic_url' => array('BOOL', 1), ), ), 'change_columns' => array( @@ -2791,23 +2794,7 @@ function change_database_data(&$no_updates, $version) _sql($sql, $errored, $error_ary); } $db->sql_freeresult($result); - - // PHPBB3-11171: Copy bbcode fields, etc. for reported posts. Add 5 columns to the reports table - // Add the columns used by these changes - $changes['add_columns'] = array( - REPORTS_TABLE => array( - 'reported_post_enable_bbcode' => array('BOOL', 1), - 'reported_post_enable_smilies' => array('BOOL', 1), - 'reported_post_enable_magic_url' => array('BOOL', 1) - ) - ); - $statements = $db_tools->perform_schema_changes($changes); - - foreach ($statements as $sql) - { - _sql($sql, $errored, $error_ary); - } break; } From 5b368dd53a2da6ab481bc608176f442dc067c4a7 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 7 Dec 2012 15:32:06 -0500 Subject: [PATCH 130/497] [ticket/11255] Fix dbal write sequence test to run standalone. PHPBB3-11255 --- tests/dbal/write_sequence_test.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/dbal/write_sequence_test.php b/tests/dbal/write_sequence_test.php index 8975cfbfb1..f382a971a5 100644 --- a/tests/dbal/write_sequence_test.php +++ b/tests/dbal/write_sequence_test.php @@ -33,6 +33,10 @@ class phpbb_dbal_write_sequence_test extends phpbb_database_test_case { $db = $this->new_dbal(); + // dbal uses cache + global $cache; + $cache = new phpbb_mock_cache(); + $sql = 'INSERT INTO phpbb_users ' . $db->sql_build_array('INSERT', array( 'username' => $username, 'username_clean' => $username, From 5af3d14af3c35e99c0eba75c43a411ead6191c79 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 7 Dec 2012 15:32:26 -0500 Subject: [PATCH 131/497] [ticket/11255] Change search tests to use mock cache. PHPBB3-11255 --- tests/search/mysql_test.php | 2 +- tests/search/native_test.php | 2 +- tests/search/postgres_test.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/search/mysql_test.php b/tests/search/mysql_test.php index 3ba3915714..3ad15bd806 100644 --- a/tests/search/mysql_test.php +++ b/tests/search/mysql_test.php @@ -26,7 +26,7 @@ class phpbb_search_mysql_test extends phpbb_search_common_test_case parent::setUp(); // dbal uses cache - $cache = new phpbb_cache_service(new phpbb_cache_driver_null); + $cache = new phpbb_mock_cache(); // set config values $config['fulltext_mysql_min_word_len'] = 4; diff --git a/tests/search/native_test.php b/tests/search/native_test.php index eeee3a44f3..4a2c210013 100644 --- a/tests/search/native_test.php +++ b/tests/search/native_test.php @@ -26,7 +26,7 @@ class phpbb_search_native_test extends phpbb_search_test_case parent::setUp(); // dbal uses cache - $cache = new phpbb_cache_service(new phpbb_cache_driver_null); + $cache = new phpbb_mock_cache(); $this->db = $this->new_dbal(); $error = null; diff --git a/tests/search/postgres_test.php b/tests/search/postgres_test.php index 9c77e0c09e..923af6f854 100644 --- a/tests/search/postgres_test.php +++ b/tests/search/postgres_test.php @@ -26,7 +26,7 @@ class phpbb_search_postgres_test extends phpbb_search_common_test_case parent::setUp(); // dbal uses cache - $cache = new phpbb_cache_service(new phpbb_cache_driver_null); + $cache = new phpbb_mock_cache(); // set config values $config['fulltext_postgres_min_word_len'] = 4; From cf956e8f53cadbbe647651b9fd87f9feba23f7e2 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Fri, 7 Dec 2012 23:14:07 +0100 Subject: [PATCH 132/497] [ticket/11256] Remove unused service with non-existent class PHPBB3-11256 --- phpBB/config/services.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/phpBB/config/services.yml b/phpBB/config/services.yml index 37e6c0b5df..fb1df6f508 100644 --- a/phpBB/config/services.yml +++ b/phpBB/config/services.yml @@ -59,12 +59,6 @@ services: - @service_container - @ext.finder - controller.route_collection: - class: phpbb_controller_route_collection - arguments: - - @ext.finder - - @controller.provider - controller.provider: class: phpbb_controller_provider From 2973539760beebc1bb60dc91382c2b628d4276c6 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Fri, 7 Dec 2012 23:18:38 +0100 Subject: [PATCH 133/497] [ticket/11256] Remove unused controller.provider service PHPBB3-11256 --- phpBB/config/services.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/phpBB/config/services.yml b/phpBB/config/services.yml index fb1df6f508..242fe7f1d2 100644 --- a/phpBB/config/services.yml +++ b/phpBB/config/services.yml @@ -59,9 +59,6 @@ services: - @service_container - @ext.finder - controller.provider: - class: phpbb_controller_provider - cron.task_collection: class: phpbb_di_service_collection arguments: From 03d2c6413c25b1faf7f37ff20625ce986b19eb88 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 7 Dec 2012 21:57:33 -0500 Subject: [PATCH 134/497] [ticket/11248] Convert line endings to LF - develop edition. PHPBB3-11248 --- phpBB/docs/sphinx.sample.conf | 90 +- phpBB/includes/sphinxapi.php | 3424 ++++++++++++++--------------- tests/session/append_sid_test.php | 108 +- 3 files changed, 1826 insertions(+), 1796 deletions(-) diff --git a/phpBB/docs/sphinx.sample.conf b/phpBB/docs/sphinx.sample.conf index aa0e8d905d..fcaba6dcf3 100644 --- a/phpBB/docs/sphinx.sample.conf +++ b/phpBB/docs/sphinx.sample.conf @@ -10,21 +10,36 @@ source source_phpbb_{SPHINX_ID}_main sql_query_pre = UPDATE phpbb_sphinx SET max_doc_id = MAX(post_id) WHERE counter_id = 1 sql_query_range = SELECT MIN(post_id), MAX(post_id) FROM phpbb_posts sql_range_step = 5000 - sql_query = SELECT \ - p.post_id AS id, \ - p.forum_id, \ - p.topic_id, \ - p.poster_id, \ - CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post, \ - p.post_time, \ - p.post_subject, \ - p.post_subject as title, \ - p.post_text as data, \ - t.topic_last_post_time, \ - 0 as deleted \ - FROM phpbb_posts p, phpbb_topics t \ - WHERE \ - p.topic_id = t.topic_id \ + sql_query = SELECT +\ + p.post_id AS id, +\ + p.forum_id, +\ + p.topic_id, +\ + p.poster_id, +\ + CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post, +\ + p.post_time, +\ + p.post_subject, +\ + p.post_subject as title, +\ + p.post_text as data, +\ + t.topic_last_post_time, +\ + 0 as deleted +\ + FROM phpbb_posts p, phpbb_topics t +\ + WHERE +\ + p.topic_id = t.topic_id +\ AND p.post_id >= $start AND p.post_id <= $end sql_query_post = sql_query_post_index = UPDATE phpbb_sphinx SET max_doc_id = $maxid WHERE counter_id = 1 @@ -42,21 +57,36 @@ source source_phpbb_{SPHINX_ID}_delta : source_phpbb_{SPHINX_ID}_main { sql_query_range = sql_range_step = - sql_query = SELECT \ - p.post_id AS id, \ - p.forum_id, \ - p.topic_id, \ - p.poster_id, \ - CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post, \ - p.post_time, \ - p.post_subject, \ - p.post_subject as title, \ - p.post_text as data, \ - t.topic_last_post_time, \ - 0 as deleted \ - FROM phpbb_posts p, phpbb_topics t \ - WHERE \ - p.topic_id = t.topic_id \ + sql_query = SELECT +\ + p.post_id AS id, +\ + p.forum_id, +\ + p.topic_id, +\ + p.poster_id, +\ + CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post, +\ + p.post_time, +\ + p.post_subject, +\ + p.post_subject as title, +\ + p.post_text as data, +\ + t.topic_last_post_time, +\ + 0 as deleted +\ + FROM phpbb_posts p, phpbb_topics t +\ + WHERE +\ + p.topic_id = t.topic_id +\ AND p.post_id >= ( SELECT max_doc_id FROM phpbb_sphinx WHERE counter_id=1 ) sql_query_pre = } diff --git a/phpBB/includes/sphinxapi.php b/phpBB/includes/sphinxapi.php index bd83b1d2e0..6c3b66710c 100644 --- a/phpBB/includes/sphinxapi.php +++ b/phpBB/includes/sphinxapi.php @@ -1,1712 +1,1712 @@ -=8 ) - { - $v = (int)$v; - return pack ( "NN", $v>>32, $v&0xFFFFFFFF ); - } - - // x32, int - if ( is_int($v) ) - return pack ( "NN", $v < 0 ? -1 : 0, $v ); - - // x32, bcmath - if ( function_exists("bcmul") ) - { - if ( bccomp ( $v, 0 ) == -1 ) - $v = bcadd ( "18446744073709551616", $v ); - $h = bcdiv ( $v, "4294967296", 0 ); - $l = bcmod ( $v, "4294967296" ); - return pack ( "NN", (float)$h, (float)$l ); // conversion to float is intentional; int would lose 31st bit - } - - // x32, no-bcmath - $p = max(0, strlen($v) - 13); - $lo = abs((float)substr($v, $p)); - $hi = abs((float)substr($v, 0, $p)); - - $m = $lo + $hi*1316134912.0; // (10 ^ 13) % (1 << 32) = 1316134912 - $q = floor($m/4294967296.0); - $l = $m - ($q*4294967296.0); - $h = $hi*2328.0 + $q; // (10 ^ 13) / (1 << 32) = 2328 - - if ( $v<0 ) - { - if ( $l==0 ) - $h = 4294967296.0 - $h; - else - { - $h = 4294967295.0 - $h; - $l = 4294967296.0 - $l; - } - } - return pack ( "NN", $h, $l ); -} - -/// pack 64-bit unsigned -function sphPackU64 ( $v ) -{ - assert ( is_numeric($v) ); - - // x64 - if ( PHP_INT_SIZE>=8 ) - { - assert ( $v>=0 ); - - // x64, int - if ( is_int($v) ) - return pack ( "NN", $v>>32, $v&0xFFFFFFFF ); - - // x64, bcmath - if ( function_exists("bcmul") ) - { - $h = bcdiv ( $v, 4294967296, 0 ); - $l = bcmod ( $v, 4294967296 ); - return pack ( "NN", $h, $l ); - } - - // x64, no-bcmath - $p = max ( 0, strlen($v) - 13 ); - $lo = (int)substr ( $v, $p ); - $hi = (int)substr ( $v, 0, $p ); - - $m = $lo + $hi*1316134912; - $l = $m % 4294967296; - $h = $hi*2328 + (int)($m/4294967296); - - return pack ( "NN", $h, $l ); - } - - // x32, int - if ( is_int($v) ) - return pack ( "NN", 0, $v ); - - // x32, bcmath - if ( function_exists("bcmul") ) - { - $h = bcdiv ( $v, "4294967296", 0 ); - $l = bcmod ( $v, "4294967296" ); - return pack ( "NN", (float)$h, (float)$l ); // conversion to float is intentional; int would lose 31st bit - } - - // x32, no-bcmath - $p = max(0, strlen($v) - 13); - $lo = (float)substr($v, $p); - $hi = (float)substr($v, 0, $p); - - $m = $lo + $hi*1316134912.0; - $q = floor($m / 4294967296.0); - $l = $m - ($q * 4294967296.0); - $h = $hi*2328.0 + $q; - - return pack ( "NN", $h, $l ); -} - -// unpack 64-bit unsigned -function sphUnpackU64 ( $v ) -{ - list ( $hi, $lo ) = array_values ( unpack ( "N*N*", $v ) ); - - if ( PHP_INT_SIZE>=8 ) - { - if ( $hi<0 ) $hi += (1<<32); // because php 5.2.2 to 5.2.5 is totally fucked up again - if ( $lo<0 ) $lo += (1<<32); - - // x64, int - if ( $hi<=2147483647 ) - return ($hi<<32) + $lo; - - // x64, bcmath - if ( function_exists("bcmul") ) - return bcadd ( $lo, bcmul ( $hi, "4294967296" ) ); - - // x64, no-bcmath - $C = 100000; - $h = ((int)($hi / $C) << 32) + (int)($lo / $C); - $l = (($hi % $C) << 32) + ($lo % $C); - if ( $l>$C ) - { - $h += (int)($l / $C); - $l = $l % $C; - } - - if ( $h==0 ) - return $l; - return sprintf ( "%d%05d", $h, $l ); - } - - // x32, int - if ( $hi==0 ) - { - if ( $lo>0 ) - return $lo; - return sprintf ( "%u", $lo ); - } - - $hi = sprintf ( "%u", $hi ); - $lo = sprintf ( "%u", $lo ); - - // x32, bcmath - if ( function_exists("bcmul") ) - return bcadd ( $lo, bcmul ( $hi, "4294967296" ) ); - - // x32, no-bcmath - $hi = (float)$hi; - $lo = (float)$lo; - - $q = floor($hi/10000000.0); - $r = $hi - $q*10000000.0; - $m = $lo + $r*4967296.0; - $mq = floor($m/10000000.0); - $l = $m - $mq*10000000.0; - $h = $q*4294967296.0 + $r*429.0 + $mq; - - $h = sprintf ( "%.0f", $h ); - $l = sprintf ( "%07.0f", $l ); - if ( $h=="0" ) - return sprintf( "%.0f", (float)$l ); - return $h . $l; -} - -// unpack 64-bit signed -function sphUnpackI64 ( $v ) -{ - list ( $hi, $lo ) = array_values ( unpack ( "N*N*", $v ) ); - - // x64 - if ( PHP_INT_SIZE>=8 ) - { - if ( $hi<0 ) $hi += (1<<32); // because php 5.2.2 to 5.2.5 is totally fucked up again - if ( $lo<0 ) $lo += (1<<32); - - return ($hi<<32) + $lo; - } - - // x32, int - if ( $hi==0 ) - { - if ( $lo>0 ) - return $lo; - return sprintf ( "%u", $lo ); - } - // x32, int - elseif ( $hi==-1 ) - { - if ( $lo<0 ) - return $lo; - return sprintf ( "%.0f", $lo - 4294967296.0 ); - } - - $neg = ""; - $c = 0; - if ( $hi<0 ) - { - $hi = ~$hi; - $lo = ~$lo; - $c = 1; - $neg = "-"; - } - - $hi = sprintf ( "%u", $hi ); - $lo = sprintf ( "%u", $lo ); - - // x32, bcmath - if ( function_exists("bcmul") ) - return $neg . bcadd ( bcadd ( $lo, bcmul ( $hi, "4294967296" ) ), $c ); - - // x32, no-bcmath - $hi = (float)$hi; - $lo = (float)$lo; - - $q = floor($hi/10000000.0); - $r = $hi - $q*10000000.0; - $m = $lo + $r*4967296.0; - $mq = floor($m/10000000.0); - $l = $m - $mq*10000000.0 + $c; - $h = $q*4294967296.0 + $r*429.0 + $mq; - if ( $l==10000000 ) - { - $l = 0; - $h += 1; - } - - $h = sprintf ( "%.0f", $h ); - $l = sprintf ( "%07.0f", $l ); - if ( $h=="0" ) - return $neg . sprintf( "%.0f", (float)$l ); - return $neg . $h . $l; -} - - -function sphFixUint ( $value ) -{ - if ( PHP_INT_SIZE>=8 ) - { - // x64 route, workaround broken unpack() in 5.2.2+ - if ( $value<0 ) $value += (1<<32); - return $value; - } - else - { - // x32 route, workaround php signed/unsigned braindamage - return sprintf ( "%u", $value ); - } -} - - -/// sphinx searchd client class -class SphinxClient -{ - var $_host; ///< searchd host (default is "localhost") - var $_port; ///< searchd port (default is 9312) - var $_offset; ///< how many records to seek from result-set start (default is 0) - var $_limit; ///< how many records to return from result-set starting at offset (default is 20) - var $_mode; ///< query matching mode (default is SPH_MATCH_ALL) - var $_weights; ///< per-field weights (default is 1 for all fields) - var $_sort; ///< match sorting mode (default is SPH_SORT_RELEVANCE) - var $_sortby; ///< attribute to sort by (defualt is "") - var $_min_id; ///< min ID to match (default is 0, which means no limit) - var $_max_id; ///< max ID to match (default is 0, which means no limit) - var $_filters; ///< search filters - var $_groupby; ///< group-by attribute name - var $_groupfunc; ///< group-by function (to pre-process group-by attribute value with) - var $_groupsort; ///< group-by sorting clause (to sort groups in result set with) - var $_groupdistinct;///< group-by count-distinct attribute - var $_maxmatches; ///< max matches to retrieve - var $_cutoff; ///< cutoff to stop searching at (default is 0) - var $_retrycount; ///< distributed retries count - var $_retrydelay; ///< distributed retries delay - var $_anchor; ///< geographical anchor point - var $_indexweights; ///< per-index weights - var $_ranker; ///< ranking mode (default is SPH_RANK_PROXIMITY_BM25) - var $_rankexpr; ///< ranking mode expression (for SPH_RANK_EXPR) - var $_maxquerytime; ///< max query time, milliseconds (default is 0, do not limit) - var $_fieldweights; ///< per-field-name weights - var $_overrides; ///< per-query attribute values overrides - var $_select; ///< select-list (attributes or expressions, with optional aliases) - - var $_error; ///< last error message - var $_warning; ///< last warning message - var $_connerror; ///< connection error vs remote error flag - - var $_reqs; ///< requests array for multi-query - var $_mbenc; ///< stored mbstring encoding - var $_arrayresult; ///< whether $result["matches"] should be a hash or an array - var $_timeout; ///< connect timeout - - ///////////////////////////////////////////////////////////////////////////// - // common stuff - ///////////////////////////////////////////////////////////////////////////// - - /// create a new client object and fill defaults - function SphinxClient () - { - // per-client-object settings - $this->_host = "localhost"; - $this->_port = 9312; - $this->_path = false; - $this->_socket = false; - - // per-query settings - $this->_offset = 0; - $this->_limit = 20; - $this->_mode = SPH_MATCH_ALL; - $this->_weights = array (); - $this->_sort = SPH_SORT_RELEVANCE; - $this->_sortby = ""; - $this->_min_id = 0; - $this->_max_id = 0; - $this->_filters = array (); - $this->_groupby = ""; - $this->_groupfunc = SPH_GROUPBY_DAY; - $this->_groupsort = "@group desc"; - $this->_groupdistinct= ""; - $this->_maxmatches = 1000; - $this->_cutoff = 0; - $this->_retrycount = 0; - $this->_retrydelay = 0; - $this->_anchor = array (); - $this->_indexweights= array (); - $this->_ranker = SPH_RANK_PROXIMITY_BM25; - $this->_rankexpr = ""; - $this->_maxquerytime= 0; - $this->_fieldweights= array(); - $this->_overrides = array(); - $this->_select = "*"; - - $this->_error = ""; // per-reply fields (for single-query case) - $this->_warning = ""; - $this->_connerror = false; - - $this->_reqs = array (); // requests storage (for multi-query case) - $this->_mbenc = ""; - $this->_arrayresult = false; - $this->_timeout = 0; - } - - function __destruct() - { - if ( $this->_socket !== false ) - fclose ( $this->_socket ); - } - - /// get last error message (string) - function GetLastError () - { - return $this->_error; - } - - /// get last warning message (string) - function GetLastWarning () - { - return $this->_warning; - } - - /// get last error flag (to tell network connection errors from searchd errors or broken responses) - function IsConnectError() - { - return $this->_connerror; - } - - /// set searchd host name (string) and port (integer) - function SetServer ( $host, $port = 0 ) - { - assert ( is_string($host) ); - if ( $host[0] == '/') - { - $this->_path = 'unix://' . $host; - return; - } - if ( substr ( $host, 0, 7 )=="unix://" ) - { - $this->_path = $host; - return; - } - - assert ( is_int($port) ); - $this->_host = $host; - $this->_port = $port; - $this->_path = ''; - - } - - /// set server connection timeout (0 to remove) - function SetConnectTimeout ( $timeout ) - { - assert ( is_numeric($timeout) ); - $this->_timeout = $timeout; - } - - - function _Send ( $handle, $data, $length ) - { - if ( feof($handle) || fwrite ( $handle, $data, $length ) !== $length ) - { - $this->_error = 'connection unexpectedly closed (timed out?)'; - $this->_connerror = true; - return false; - } - return true; - } - - ///////////////////////////////////////////////////////////////////////////// - - /// enter mbstring workaround mode - function _MBPush () - { - $this->_mbenc = ""; - if ( ini_get ( "mbstring.func_overload" ) & 2 ) - { - $this->_mbenc = mb_internal_encoding(); - mb_internal_encoding ( "latin1" ); - } - } - - /// leave mbstring workaround mode - function _MBPop () - { - if ( $this->_mbenc ) - mb_internal_encoding ( $this->_mbenc ); - } - - /// connect to searchd server - function _Connect () - { - if ( $this->_socket!==false ) - { - // we are in persistent connection mode, so we have a socket - // however, need to check whether it's still alive - if ( !@feof ( $this->_socket ) ) - return $this->_socket; - - // force reopen - $this->_socket = false; - } - - $errno = 0; - $errstr = ""; - $this->_connerror = false; - - if ( $this->_path ) - { - $host = $this->_path; - $port = 0; - } - else - { - $host = $this->_host; - $port = $this->_port; - } - - if ( $this->_timeout<=0 ) - $fp = @fsockopen ( $host, $port, $errno, $errstr ); - else - $fp = @fsockopen ( $host, $port, $errno, $errstr, $this->_timeout ); - - if ( !$fp ) - { - if ( $this->_path ) - $location = $this->_path; - else - $location = "{$this->_host}:{$this->_port}"; - - $errstr = trim ( $errstr ); - $this->_error = "connection to $location failed (errno=$errno, msg=$errstr)"; - $this->_connerror = true; - return false; - } - - // send my version - // this is a subtle part. we must do it before (!) reading back from searchd. - // because otherwise under some conditions (reported on FreeBSD for instance) - // TCP stack could throttle write-write-read pattern because of Nagle. - if ( !$this->_Send ( $fp, pack ( "N", 1 ), 4 ) ) - { - fclose ( $fp ); - $this->_error = "failed to send client protocol version"; - return false; - } - - // check version - list(,$v) = unpack ( "N*", fread ( $fp, 4 ) ); - $v = (int)$v; - if ( $v<1 ) - { - fclose ( $fp ); - $this->_error = "expected searchd protocol version 1+, got version '$v'"; - return false; - } - - return $fp; - } - - /// get and check response packet from searchd server - function _GetResponse ( $fp, $client_ver ) - { - $response = ""; - $len = 0; - - $header = fread ( $fp, 8 ); - if ( strlen($header)==8 ) - { - list ( $status, $ver, $len ) = array_values ( unpack ( "n2a/Nb", $header ) ); - $left = $len; - while ( $left>0 && !feof($fp) ) - { - $chunk = fread ( $fp, min ( 8192, $left ) ); - if ( $chunk ) - { - $response .= $chunk; - $left -= strlen($chunk); - } - } - } - if ( $this->_socket === false ) - fclose ( $fp ); - - // check response - $read = strlen ( $response ); - if ( !$response || $read!=$len ) - { - $this->_error = $len - ? "failed to read searchd response (status=$status, ver=$ver, len=$len, read=$read)" - : "received zero-sized searchd response"; - return false; - } - - // check status - if ( $status==SEARCHD_WARNING ) - { - list(,$wlen) = unpack ( "N*", substr ( $response, 0, 4 ) ); - $this->_warning = substr ( $response, 4, $wlen ); - return substr ( $response, 4+$wlen ); - } - if ( $status==SEARCHD_ERROR ) - { - $this->_error = "searchd error: " . substr ( $response, 4 ); - return false; - } - if ( $status==SEARCHD_RETRY ) - { - $this->_error = "temporary searchd error: " . substr ( $response, 4 ); - return false; - } - if ( $status!=SEARCHD_OK ) - { - $this->_error = "unknown status code '$status'"; - return false; - } - - // check version - if ( $ver<$client_ver ) - { - $this->_warning = sprintf ( "searchd command v.%d.%d older than client's v.%d.%d, some options might not work", - $ver>>8, $ver&0xff, $client_ver>>8, $client_ver&0xff ); - } - - return $response; - } - - ///////////////////////////////////////////////////////////////////////////// - // searching - ///////////////////////////////////////////////////////////////////////////// - - /// set offset and count into result set, - /// and optionally set max-matches and cutoff limits - function SetLimits ( $offset, $limit, $max=0, $cutoff=0 ) - { - assert ( is_int($offset) ); - assert ( is_int($limit) ); - assert ( $offset>=0 ); - assert ( $limit>0 ); - assert ( $max>=0 ); - $this->_offset = $offset; - $this->_limit = $limit; - if ( $max>0 ) - $this->_maxmatches = $max; - if ( $cutoff>0 ) - $this->_cutoff = $cutoff; - } - - /// set maximum query time, in milliseconds, per-index - /// integer, 0 means "do not limit" - function SetMaxQueryTime ( $max ) - { - assert ( is_int($max) ); - assert ( $max>=0 ); - $this->_maxquerytime = $max; - } - - /// set matching mode - function SetMatchMode ( $mode ) - { - assert ( $mode==SPH_MATCH_ALL - || $mode==SPH_MATCH_ANY - || $mode==SPH_MATCH_PHRASE - || $mode==SPH_MATCH_BOOLEAN - || $mode==SPH_MATCH_EXTENDED - || $mode==SPH_MATCH_FULLSCAN - || $mode==SPH_MATCH_EXTENDED2 ); - $this->_mode = $mode; - } - - /// set ranking mode - function SetRankingMode ( $ranker, $rankexpr="" ) - { - assert ( $ranker>=0 && $ranker_ranker = $ranker; - $this->_rankexpr = $rankexpr; - } - - /// set matches sorting mode - function SetSortMode ( $mode, $sortby="" ) - { - assert ( - $mode==SPH_SORT_RELEVANCE || - $mode==SPH_SORT_ATTR_DESC || - $mode==SPH_SORT_ATTR_ASC || - $mode==SPH_SORT_TIME_SEGMENTS || - $mode==SPH_SORT_EXTENDED || - $mode==SPH_SORT_EXPR ); - assert ( is_string($sortby) ); - assert ( $mode==SPH_SORT_RELEVANCE || strlen($sortby)>0 ); - - $this->_sort = $mode; - $this->_sortby = $sortby; - } - - /// bind per-field weights by order - /// DEPRECATED; use SetFieldWeights() instead - function SetWeights ( $weights ) - { - assert ( is_array($weights) ); - foreach ( $weights as $weight ) - assert ( is_int($weight) ); - - $this->_weights = $weights; - } - - /// bind per-field weights by name - function SetFieldWeights ( $weights ) - { - assert ( is_array($weights) ); - foreach ( $weights as $name=>$weight ) - { - assert ( is_string($name) ); - assert ( is_int($weight) ); - } - $this->_fieldweights = $weights; - } - - /// bind per-index weights by name - function SetIndexWeights ( $weights ) - { - assert ( is_array($weights) ); - foreach ( $weights as $index=>$weight ) - { - assert ( is_string($index) ); - assert ( is_int($weight) ); - } - $this->_indexweights = $weights; - } - - /// set IDs range to match - /// only match records if document ID is beetwen $min and $max (inclusive) - function SetIDRange ( $min, $max ) - { - assert ( is_numeric($min) ); - assert ( is_numeric($max) ); - assert ( $min<=$max ); - $this->_min_id = $min; - $this->_max_id = $max; - } - - /// set values set filter - /// only match records where $attribute value is in given set - function SetFilter ( $attribute, $values, $exclude=false ) - { - assert ( is_string($attribute) ); - assert ( is_array($values) ); - assert ( count($values) ); - - if ( is_array($values) && count($values) ) - { - foreach ( $values as $value ) - assert ( is_numeric($value) ); - - $this->_filters[] = array ( "type"=>SPH_FILTER_VALUES, "attr"=>$attribute, "exclude"=>$exclude, "values"=>$values ); - } - } - - /// set range filter - /// only match records if $attribute value is beetwen $min and $max (inclusive) - function SetFilterRange ( $attribute, $min, $max, $exclude=false ) - { - assert ( is_string($attribute) ); - assert ( is_numeric($min) ); - assert ( is_numeric($max) ); - assert ( $min<=$max ); - - $this->_filters[] = array ( "type"=>SPH_FILTER_RANGE, "attr"=>$attribute, "exclude"=>$exclude, "min"=>$min, "max"=>$max ); - } - - /// set float range filter - /// only match records if $attribute value is beetwen $min and $max (inclusive) - function SetFilterFloatRange ( $attribute, $min, $max, $exclude=false ) - { - assert ( is_string($attribute) ); - assert ( is_float($min) ); - assert ( is_float($max) ); - assert ( $min<=$max ); - - $this->_filters[] = array ( "type"=>SPH_FILTER_FLOATRANGE, "attr"=>$attribute, "exclude"=>$exclude, "min"=>$min, "max"=>$max ); - } - - /// setup anchor point for geosphere distance calculations - /// required to use @geodist in filters and sorting - /// latitude and longitude must be in radians - function SetGeoAnchor ( $attrlat, $attrlong, $lat, $long ) - { - assert ( is_string($attrlat) ); - assert ( is_string($attrlong) ); - assert ( is_float($lat) ); - assert ( is_float($long) ); - - $this->_anchor = array ( "attrlat"=>$attrlat, "attrlong"=>$attrlong, "lat"=>$lat, "long"=>$long ); - } - - /// set grouping attribute and function - function SetGroupBy ( $attribute, $func, $groupsort="@group desc" ) - { - assert ( is_string($attribute) ); - assert ( is_string($groupsort) ); - assert ( $func==SPH_GROUPBY_DAY - || $func==SPH_GROUPBY_WEEK - || $func==SPH_GROUPBY_MONTH - || $func==SPH_GROUPBY_YEAR - || $func==SPH_GROUPBY_ATTR - || $func==SPH_GROUPBY_ATTRPAIR ); - - $this->_groupby = $attribute; - $this->_groupfunc = $func; - $this->_groupsort = $groupsort; - } - - /// set count-distinct attribute for group-by queries - function SetGroupDistinct ( $attribute ) - { - assert ( is_string($attribute) ); - $this->_groupdistinct = $attribute; - } - - /// set distributed retries count and delay - function SetRetries ( $count, $delay=0 ) - { - assert ( is_int($count) && $count>=0 ); - assert ( is_int($delay) && $delay>=0 ); - $this->_retrycount = $count; - $this->_retrydelay = $delay; - } - - /// set result set format (hash or array; hash by default) - /// PHP specific; needed for group-by-MVA result sets that may contain duplicate IDs - function SetArrayResult ( $arrayresult ) - { - assert ( is_bool($arrayresult) ); - $this->_arrayresult = $arrayresult; - } - - /// set attribute values override - /// there can be only one override per attribute - /// $values must be a hash that maps document IDs to attribute values - function SetOverride ( $attrname, $attrtype, $values ) - { - assert ( is_string ( $attrname ) ); - assert ( in_array ( $attrtype, array ( SPH_ATTR_INTEGER, SPH_ATTR_TIMESTAMP, SPH_ATTR_BOOL, SPH_ATTR_FLOAT, SPH_ATTR_BIGINT ) ) ); - assert ( is_array ( $values ) ); - - $this->_overrides[$attrname] = array ( "attr"=>$attrname, "type"=>$attrtype, "values"=>$values ); - } - - /// set select-list (attributes or expressions), SQL-like syntax - function SetSelect ( $select ) - { - assert ( is_string ( $select ) ); - $this->_select = $select; - } - - ////////////////////////////////////////////////////////////////////////////// - - /// clear all filters (for multi-queries) - function ResetFilters () - { - $this->_filters = array(); - $this->_anchor = array(); - } - - /// clear groupby settings (for multi-queries) - function ResetGroupBy () - { - $this->_groupby = ""; - $this->_groupfunc = SPH_GROUPBY_DAY; - $this->_groupsort = "@group desc"; - $this->_groupdistinct= ""; - } - - /// clear all attribute value overrides (for multi-queries) - function ResetOverrides () - { - $this->_overrides = array (); - } - - ////////////////////////////////////////////////////////////////////////////// - - /// connect to searchd server, run given search query through given indexes, - /// and return the search results - function Query ( $query, $index="*", $comment="" ) - { - assert ( empty($this->_reqs) ); - - $this->AddQuery ( $query, $index, $comment ); - $results = $this->RunQueries (); - $this->_reqs = array (); // just in case it failed too early - - if ( !is_array($results) ) - return false; // probably network error; error message should be already filled - - $this->_error = $results[0]["error"]; - $this->_warning = $results[0]["warning"]; - if ( $results[0]["status"]==SEARCHD_ERROR ) - return false; - else - return $results[0]; - } - - /// helper to pack floats in network byte order - function _PackFloat ( $f ) - { - $t1 = pack ( "f", $f ); // machine order - list(,$t2) = unpack ( "L*", $t1 ); // int in machine order - return pack ( "N", $t2 ); - } - - /// add query to multi-query batch - /// returns index into results array from RunQueries() call - function AddQuery ( $query, $index="*", $comment="" ) - { - // mbstring workaround - $this->_MBPush (); - - // build request - $req = pack ( "NNNN", $this->_offset, $this->_limit, $this->_mode, $this->_ranker ); - if ( $this->_ranker==SPH_RANK_EXPR ) - $req .= pack ( "N", strlen($this->_rankexpr) ) . $this->_rankexpr; - $req .= pack ( "N", $this->_sort ); // (deprecated) sort mode - $req .= pack ( "N", strlen($this->_sortby) ) . $this->_sortby; - $req .= pack ( "N", strlen($query) ) . $query; // query itself - $req .= pack ( "N", count($this->_weights) ); // weights - foreach ( $this->_weights as $weight ) - $req .= pack ( "N", (int)$weight ); - $req .= pack ( "N", strlen($index) ) . $index; // indexes - $req .= pack ( "N", 1 ); // id64 range marker - $req .= sphPackU64 ( $this->_min_id ) . sphPackU64 ( $this->_max_id ); // id64 range - - // filters - $req .= pack ( "N", count($this->_filters) ); - foreach ( $this->_filters as $filter ) - { - $req .= pack ( "N", strlen($filter["attr"]) ) . $filter["attr"]; - $req .= pack ( "N", $filter["type"] ); - switch ( $filter["type"] ) - { - case SPH_FILTER_VALUES: - $req .= pack ( "N", count($filter["values"]) ); - foreach ( $filter["values"] as $value ) - $req .= sphPackI64 ( $value ); - break; - - case SPH_FILTER_RANGE: - $req .= sphPackI64 ( $filter["min"] ) . sphPackI64 ( $filter["max"] ); - break; - - case SPH_FILTER_FLOATRANGE: - $req .= $this->_PackFloat ( $filter["min"] ) . $this->_PackFloat ( $filter["max"] ); - break; - - default: - assert ( 0 && "internal error: unhandled filter type" ); - } - $req .= pack ( "N", $filter["exclude"] ); - } - - // group-by clause, max-matches count, group-sort clause, cutoff count - $req .= pack ( "NN", $this->_groupfunc, strlen($this->_groupby) ) . $this->_groupby; - $req .= pack ( "N", $this->_maxmatches ); - $req .= pack ( "N", strlen($this->_groupsort) ) . $this->_groupsort; - $req .= pack ( "NNN", $this->_cutoff, $this->_retrycount, $this->_retrydelay ); - $req .= pack ( "N", strlen($this->_groupdistinct) ) . $this->_groupdistinct; - - // anchor point - if ( empty($this->_anchor) ) - { - $req .= pack ( "N", 0 ); - } else - { - $a =& $this->_anchor; - $req .= pack ( "N", 1 ); - $req .= pack ( "N", strlen($a["attrlat"]) ) . $a["attrlat"]; - $req .= pack ( "N", strlen($a["attrlong"]) ) . $a["attrlong"]; - $req .= $this->_PackFloat ( $a["lat"] ) . $this->_PackFloat ( $a["long"] ); - } - - // per-index weights - $req .= pack ( "N", count($this->_indexweights) ); - foreach ( $this->_indexweights as $idx=>$weight ) - $req .= pack ( "N", strlen($idx) ) . $idx . pack ( "N", $weight ); - - // max query time - $req .= pack ( "N", $this->_maxquerytime ); - - // per-field weights - $req .= pack ( "N", count($this->_fieldweights) ); - foreach ( $this->_fieldweights as $field=>$weight ) - $req .= pack ( "N", strlen($field) ) . $field . pack ( "N", $weight ); - - // comment - $req .= pack ( "N", strlen($comment) ) . $comment; - - // attribute overrides - $req .= pack ( "N", count($this->_overrides) ); - foreach ( $this->_overrides as $key => $entry ) - { - $req .= pack ( "N", strlen($entry["attr"]) ) . $entry["attr"]; - $req .= pack ( "NN", $entry["type"], count($entry["values"]) ); - foreach ( $entry["values"] as $id=>$val ) - { - assert ( is_numeric($id) ); - assert ( is_numeric($val) ); - - $req .= sphPackU64 ( $id ); - switch ( $entry["type"] ) - { - case SPH_ATTR_FLOAT: $req .= $this->_PackFloat ( $val ); break; - case SPH_ATTR_BIGINT: $req .= sphPackI64 ( $val ); break; - default: $req .= pack ( "N", $val ); break; - } - } - } - - // select-list - $req .= pack ( "N", strlen($this->_select) ) . $this->_select; - - // mbstring workaround - $this->_MBPop (); - - // store request to requests array - $this->_reqs[] = $req; - return count($this->_reqs)-1; - } - - /// connect to searchd, run queries batch, and return an array of result sets - function RunQueries () - { - if ( empty($this->_reqs) ) - { - $this->_error = "no queries defined, issue AddQuery() first"; - return false; - } - - // mbstring workaround - $this->_MBPush (); - - if (!( $fp = $this->_Connect() )) - { - $this->_MBPop (); - return false; - } - - // send query, get response - $nreqs = count($this->_reqs); - $req = join ( "", $this->_reqs ); - $len = 8+strlen($req); - $req = pack ( "nnNNN", SEARCHD_COMMAND_SEARCH, VER_COMMAND_SEARCH, $len, 0, $nreqs ) . $req; // add header - - if ( !( $this->_Send ( $fp, $req, $len+8 ) ) || - !( $response = $this->_GetResponse ( $fp, VER_COMMAND_SEARCH ) ) ) - { - $this->_MBPop (); - return false; - } - - // query sent ok; we can reset reqs now - $this->_reqs = array (); - - // parse and return response - return $this->_ParseSearchResponse ( $response, $nreqs ); - } - - /// parse and return search query (or queries) response - function _ParseSearchResponse ( $response, $nreqs ) - { - $p = 0; // current position - $max = strlen($response); // max position for checks, to protect against broken responses - - $results = array (); - for ( $ires=0; $ires<$nreqs && $p<$max; $ires++ ) - { - $results[] = array(); - $result =& $results[$ires]; - - $result["error"] = ""; - $result["warning"] = ""; - - // extract status - list(,$status) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; - $result["status"] = $status; - if ( $status!=SEARCHD_OK ) - { - list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; - $message = substr ( $response, $p, $len ); $p += $len; - - if ( $status==SEARCHD_WARNING ) - { - $result["warning"] = $message; - } else - { - $result["error"] = $message; - continue; - } - } - - // read schema - $fields = array (); - $attrs = array (); - - list(,$nfields) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; - while ( $nfields-->0 && $p<$max ) - { - list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; - $fields[] = substr ( $response, $p, $len ); $p += $len; - } - $result["fields"] = $fields; - - list(,$nattrs) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; - while ( $nattrs-->0 && $p<$max ) - { - list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; - $attr = substr ( $response, $p, $len ); $p += $len; - list(,$type) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; - $attrs[$attr] = $type; - } - $result["attrs"] = $attrs; - - // read match count - list(,$count) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; - list(,$id64) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; - - // read matches - $idx = -1; - while ( $count-->0 && $p<$max ) - { - // index into result array - $idx++; - - // parse document id and weight - if ( $id64 ) - { - $doc = sphUnpackU64 ( substr ( $response, $p, 8 ) ); $p += 8; - list(,$weight) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; - } - else - { - list ( $doc, $weight ) = array_values ( unpack ( "N*N*", - substr ( $response, $p, 8 ) ) ); - $p += 8; - $doc = sphFixUint($doc); - } - $weight = sprintf ( "%u", $weight ); - - // create match entry - if ( $this->_arrayresult ) - $result["matches"][$idx] = array ( "id"=>$doc, "weight"=>$weight ); - else - $result["matches"][$doc]["weight"] = $weight; - - // parse and create attributes - $attrvals = array (); - foreach ( $attrs as $attr=>$type ) - { - // handle 64bit ints - if ( $type==SPH_ATTR_BIGINT ) - { - $attrvals[$attr] = sphUnpackI64 ( substr ( $response, $p, 8 ) ); $p += 8; - continue; - } - - // handle floats - if ( $type==SPH_ATTR_FLOAT ) - { - list(,$uval) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; - list(,$fval) = unpack ( "f*", pack ( "L", $uval ) ); - $attrvals[$attr] = $fval; - continue; - } - - // handle everything else as unsigned ints - list(,$val) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; - if ( $type==SPH_ATTR_MULTI ) - { - $attrvals[$attr] = array (); - $nvalues = $val; - while ( $nvalues-->0 && $p<$max ) - { - list(,$val) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; - $attrvals[$attr][] = sphFixUint($val); - } - } else if ( $type==SPH_ATTR_MULTI64 ) - { - $attrvals[$attr] = array (); - $nvalues = $val; - while ( $nvalues>0 && $p<$max ) - { - $attrvals[$attr][] = sphUnpackU64 ( substr ( $response, $p, 8 ) ); $p += 8; - $nvalues -= 2; - } - } else if ( $type==SPH_ATTR_STRING ) - { - $attrvals[$attr] = substr ( $response, $p, $val ); - $p += $val; - } else - { - $attrvals[$attr] = sphFixUint($val); - } - } - - if ( $this->_arrayresult ) - $result["matches"][$idx]["attrs"] = $attrvals; - else - $result["matches"][$doc]["attrs"] = $attrvals; - } - - list ( $total, $total_found, $msecs, $words ) = - array_values ( unpack ( "N*N*N*N*", substr ( $response, $p, 16 ) ) ); - $result["total"] = sprintf ( "%u", $total ); - $result["total_found"] = sprintf ( "%u", $total_found ); - $result["time"] = sprintf ( "%.3f", $msecs/1000 ); - $p += 16; - - while ( $words-->0 && $p<$max ) - { - list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; - $word = substr ( $response, $p, $len ); $p += $len; - list ( $docs, $hits ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8; - $result["words"][$word] = array ( - "docs"=>sprintf ( "%u", $docs ), - "hits"=>sprintf ( "%u", $hits ) ); - } - } - - $this->_MBPop (); - return $results; - } - - ///////////////////////////////////////////////////////////////////////////// - // excerpts generation - ///////////////////////////////////////////////////////////////////////////// - - /// connect to searchd server, and generate exceprts (snippets) - /// of given documents for given query. returns false on failure, - /// an array of snippets on success - function BuildExcerpts ( $docs, $index, $words, $opts=array() ) - { - assert ( is_array($docs) ); - assert ( is_string($index) ); - assert ( is_string($words) ); - assert ( is_array($opts) ); - - $this->_MBPush (); - - if (!( $fp = $this->_Connect() )) - { - $this->_MBPop(); - return false; - } - - ///////////////// - // fixup options - ///////////////// - - if ( !isset($opts["before_match"]) ) $opts["before_match"] = ""; - if ( !isset($opts["after_match"]) ) $opts["after_match"] = ""; - if ( !isset($opts["chunk_separator"]) ) $opts["chunk_separator"] = " ... "; - if ( !isset($opts["limit"]) ) $opts["limit"] = 256; - if ( !isset($opts["limit_passages"]) ) $opts["limit_passages"] = 0; - if ( !isset($opts["limit_words"]) ) $opts["limit_words"] = 0; - if ( !isset($opts["around"]) ) $opts["around"] = 5; - if ( !isset($opts["exact_phrase"]) ) $opts["exact_phrase"] = false; - if ( !isset($opts["single_passage"]) ) $opts["single_passage"] = false; - if ( !isset($opts["use_boundaries"]) ) $opts["use_boundaries"] = false; - if ( !isset($opts["weight_order"]) ) $opts["weight_order"] = false; - if ( !isset($opts["query_mode"]) ) $opts["query_mode"] = false; - if ( !isset($opts["force_all_words"]) ) $opts["force_all_words"] = false; - if ( !isset($opts["start_passage_id"]) ) $opts["start_passage_id"] = 1; - if ( !isset($opts["load_files"]) ) $opts["load_files"] = false; - if ( !isset($opts["html_strip_mode"]) ) $opts["html_strip_mode"] = "index"; - if ( !isset($opts["allow_empty"]) ) $opts["allow_empty"] = false; - if ( !isset($opts["passage_boundary"]) ) $opts["passage_boundary"] = "none"; - if ( !isset($opts["emit_zones"]) ) $opts["emit_zones"] = false; - if ( !isset($opts["load_files_scattered"]) ) $opts["load_files_scattered"] = false; - - - ///////////////// - // build request - ///////////////// - - // v.1.2 req - $flags = 1; // remove spaces - if ( $opts["exact_phrase"] ) $flags |= 2; - if ( $opts["single_passage"] ) $flags |= 4; - if ( $opts["use_boundaries"] ) $flags |= 8; - if ( $opts["weight_order"] ) $flags |= 16; - if ( $opts["query_mode"] ) $flags |= 32; - if ( $opts["force_all_words"] ) $flags |= 64; - if ( $opts["load_files"] ) $flags |= 128; - if ( $opts["allow_empty"] ) $flags |= 256; - if ( $opts["emit_zones"] ) $flags |= 512; - if ( $opts["load_files_scattered"] ) $flags |= 1024; - $req = pack ( "NN", 0, $flags ); // mode=0, flags=$flags - $req .= pack ( "N", strlen($index) ) . $index; // req index - $req .= pack ( "N", strlen($words) ) . $words; // req words - - // options - $req .= pack ( "N", strlen($opts["before_match"]) ) . $opts["before_match"]; - $req .= pack ( "N", strlen($opts["after_match"]) ) . $opts["after_match"]; - $req .= pack ( "N", strlen($opts["chunk_separator"]) ) . $opts["chunk_separator"]; - $req .= pack ( "NN", (int)$opts["limit"], (int)$opts["around"] ); - $req .= pack ( "NNN", (int)$opts["limit_passages"], (int)$opts["limit_words"], (int)$opts["start_passage_id"] ); // v.1.2 - $req .= pack ( "N", strlen($opts["html_strip_mode"]) ) . $opts["html_strip_mode"]; - $req .= pack ( "N", strlen($opts["passage_boundary"]) ) . $opts["passage_boundary"]; - - // documents - $req .= pack ( "N", count($docs) ); - foreach ( $docs as $doc ) - { - assert ( is_string($doc) ); - $req .= pack ( "N", strlen($doc) ) . $doc; - } - - //////////////////////////// - // send query, get response - //////////////////////////// - - $len = strlen($req); - $req = pack ( "nnN", SEARCHD_COMMAND_EXCERPT, VER_COMMAND_EXCERPT, $len ) . $req; // add header - if ( !( $this->_Send ( $fp, $req, $len+8 ) ) || - !( $response = $this->_GetResponse ( $fp, VER_COMMAND_EXCERPT ) ) ) - { - $this->_MBPop (); - return false; - } - - ////////////////// - // parse response - ////////////////// - - $pos = 0; - $res = array (); - $rlen = strlen($response); - for ( $i=0; $i $rlen ) - { - $this->_error = "incomplete reply"; - $this->_MBPop (); - return false; - } - $res[] = $len ? substr ( $response, $pos, $len ) : ""; - $pos += $len; - } - - $this->_MBPop (); - return $res; - } - - - ///////////////////////////////////////////////////////////////////////////// - // keyword generation - ///////////////////////////////////////////////////////////////////////////// - - /// connect to searchd server, and generate keyword list for a given query - /// returns false on failure, - /// an array of words on success - function BuildKeywords ( $query, $index, $hits ) - { - assert ( is_string($query) ); - assert ( is_string($index) ); - assert ( is_bool($hits) ); - - $this->_MBPush (); - - if (!( $fp = $this->_Connect() )) - { - $this->_MBPop(); - return false; - } - - ///////////////// - // build request - ///////////////// - - // v.1.0 req - $req = pack ( "N", strlen($query) ) . $query; // req query - $req .= pack ( "N", strlen($index) ) . $index; // req index - $req .= pack ( "N", (int)$hits ); - - //////////////////////////// - // send query, get response - //////////////////////////// - - $len = strlen($req); - $req = pack ( "nnN", SEARCHD_COMMAND_KEYWORDS, VER_COMMAND_KEYWORDS, $len ) . $req; // add header - if ( !( $this->_Send ( $fp, $req, $len+8 ) ) || - !( $response = $this->_GetResponse ( $fp, VER_COMMAND_KEYWORDS ) ) ) - { - $this->_MBPop (); - return false; - } - - ////////////////// - // parse response - ////////////////// - - $pos = 0; - $res = array (); - $rlen = strlen($response); - list(,$nwords) = unpack ( "N*", substr ( $response, $pos, 4 ) ); - $pos += 4; - for ( $i=0; $i<$nwords; $i++ ) - { - list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) ); $pos += 4; - $tokenized = $len ? substr ( $response, $pos, $len ) : ""; - $pos += $len; - - list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) ); $pos += 4; - $normalized = $len ? substr ( $response, $pos, $len ) : ""; - $pos += $len; - - $res[] = array ( "tokenized"=>$tokenized, "normalized"=>$normalized ); - - if ( $hits ) - { - list($ndocs,$nhits) = array_values ( unpack ( "N*N*", substr ( $response, $pos, 8 ) ) ); - $pos += 8; - $res [$i]["docs"] = $ndocs; - $res [$i]["hits"] = $nhits; - } - - if ( $pos > $rlen ) - { - $this->_error = "incomplete reply"; - $this->_MBPop (); - return false; - } - } - - $this->_MBPop (); - return $res; - } - - function EscapeString ( $string ) - { - $from = array ( '\\', '(',')','|','-','!','@','~','"','&', '/', '^', '$', '=' ); - $to = array ( '\\\\', '\(','\)','\|','\-','\!','\@','\~','\"', '\&', '\/', '\^', '\$', '\=' ); - - return str_replace ( $from, $to, $string ); - } - - ///////////////////////////////////////////////////////////////////////////// - // attribute updates - ///////////////////////////////////////////////////////////////////////////// - - /// batch update given attributes in given rows in given indexes - /// returns amount of updated documents (0 or more) on success, or -1 on failure - function UpdateAttributes ( $index, $attrs, $values, $mva=false ) - { - // verify everything - assert ( is_string($index) ); - assert ( is_bool($mva) ); - - assert ( is_array($attrs) ); - foreach ( $attrs as $attr ) - assert ( is_string($attr) ); - - assert ( is_array($values) ); - foreach ( $values as $id=>$entry ) - { - assert ( is_numeric($id) ); - assert ( is_array($entry) ); - assert ( count($entry)==count($attrs) ); - foreach ( $entry as $v ) - { - if ( $mva ) - { - assert ( is_array($v) ); - foreach ( $v as $vv ) - assert ( is_int($vv) ); - } else - assert ( is_int($v) ); - } - } - - // build request - $this->_MBPush (); - $req = pack ( "N", strlen($index) ) . $index; - - $req .= pack ( "N", count($attrs) ); - foreach ( $attrs as $attr ) - { - $req .= pack ( "N", strlen($attr) ) . $attr; - $req .= pack ( "N", $mva ? 1 : 0 ); - } - - $req .= pack ( "N", count($values) ); - foreach ( $values as $id=>$entry ) - { - $req .= sphPackU64 ( $id ); - foreach ( $entry as $v ) - { - $req .= pack ( "N", $mva ? count($v) : $v ); - if ( $mva ) - foreach ( $v as $vv ) - $req .= pack ( "N", $vv ); - } - } - - // connect, send query, get response - if (!( $fp = $this->_Connect() )) - { - $this->_MBPop (); - return -1; - } - - $len = strlen($req); - $req = pack ( "nnN", SEARCHD_COMMAND_UPDATE, VER_COMMAND_UPDATE, $len ) . $req; // add header - if ( !$this->_Send ( $fp, $req, $len+8 ) ) - { - $this->_MBPop (); - return -1; - } - - if (!( $response = $this->_GetResponse ( $fp, VER_COMMAND_UPDATE ) )) - { - $this->_MBPop (); - return -1; - } - - // parse response - list(,$updated) = unpack ( "N*", substr ( $response, 0, 4 ) ); - $this->_MBPop (); - return $updated; - } - - ///////////////////////////////////////////////////////////////////////////// - // persistent connections - ///////////////////////////////////////////////////////////////////////////// - - function Open() - { - if ( $this->_socket !== false ) - { - $this->_error = 'already connected'; - return false; - } - if ( !$fp = $this->_Connect() ) - return false; - - // command, command version = 0, body length = 4, body = 1 - $req = pack ( "nnNN", SEARCHD_COMMAND_PERSIST, 0, 4, 1 ); - if ( !$this->_Send ( $fp, $req, 12 ) ) - return false; - - $this->_socket = $fp; - return true; - } - - function Close() - { - if ( $this->_socket === false ) - { - $this->_error = 'not connected'; - return false; - } - - fclose ( $this->_socket ); - $this->_socket = false; - - return true; - } - - ////////////////////////////////////////////////////////////////////////// - // status - ////////////////////////////////////////////////////////////////////////// - - function Status () - { - $this->_MBPush (); - if (!( $fp = $this->_Connect() )) - { - $this->_MBPop(); - return false; - } - - $req = pack ( "nnNN", SEARCHD_COMMAND_STATUS, VER_COMMAND_STATUS, 4, 1 ); // len=4, body=1 - if ( !( $this->_Send ( $fp, $req, 12 ) ) || - !( $response = $this->_GetResponse ( $fp, VER_COMMAND_STATUS ) ) ) - { - $this->_MBPop (); - return false; - } - - $res = substr ( $response, 4 ); // just ignore length, error handling, etc - $p = 0; - list ( $rows, $cols ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8; - - $res = array(); - for ( $i=0; $i<$rows; $i++ ) - for ( $j=0; $j<$cols; $j++ ) - { - list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; - $res[$i][] = substr ( $response, $p, $len ); $p += $len; - } - - $this->_MBPop (); - return $res; - } - - ////////////////////////////////////////////////////////////////////////// - // flush - ////////////////////////////////////////////////////////////////////////// - - function FlushAttributes () - { - $this->_MBPush (); - if (!( $fp = $this->_Connect() )) - { - $this->_MBPop(); - return -1; - } - - $req = pack ( "nnN", SEARCHD_COMMAND_FLUSHATTRS, VER_COMMAND_FLUSHATTRS, 0 ); // len=0 - if ( !( $this->_Send ( $fp, $req, 8 ) ) || - !( $response = $this->_GetResponse ( $fp, VER_COMMAND_FLUSHATTRS ) ) ) - { - $this->_MBPop (); - return -1; - } - - $tag = -1; - if ( strlen($response)==4 ) - list(,$tag) = unpack ( "N*", $response ); - else - $this->_error = "unexpected response length"; - - $this->_MBPop (); - return $tag; - } -} - -// -// $Id: sphinxapi.php 3087 2012-01-30 23:07:35Z shodan $ -// +=8 ) + { + $v = (int)$v; + return pack ( "NN", $v>>32, $v&0xFFFFFFFF ); + } + + // x32, int + if ( is_int($v) ) + return pack ( "NN", $v < 0 ? -1 : 0, $v ); + + // x32, bcmath + if ( function_exists("bcmul") ) + { + if ( bccomp ( $v, 0 ) == -1 ) + $v = bcadd ( "18446744073709551616", $v ); + $h = bcdiv ( $v, "4294967296", 0 ); + $l = bcmod ( $v, "4294967296" ); + return pack ( "NN", (float)$h, (float)$l ); // conversion to float is intentional; int would lose 31st bit + } + + // x32, no-bcmath + $p = max(0, strlen($v) - 13); + $lo = abs((float)substr($v, $p)); + $hi = abs((float)substr($v, 0, $p)); + + $m = $lo + $hi*1316134912.0; // (10 ^ 13) % (1 << 32) = 1316134912 + $q = floor($m/4294967296.0); + $l = $m - ($q*4294967296.0); + $h = $hi*2328.0 + $q; // (10 ^ 13) / (1 << 32) = 2328 + + if ( $v<0 ) + { + if ( $l==0 ) + $h = 4294967296.0 - $h; + else + { + $h = 4294967295.0 - $h; + $l = 4294967296.0 - $l; + } + } + return pack ( "NN", $h, $l ); +} + +/// pack 64-bit unsigned +function sphPackU64 ( $v ) +{ + assert ( is_numeric($v) ); + + // x64 + if ( PHP_INT_SIZE>=8 ) + { + assert ( $v>=0 ); + + // x64, int + if ( is_int($v) ) + return pack ( "NN", $v>>32, $v&0xFFFFFFFF ); + + // x64, bcmath + if ( function_exists("bcmul") ) + { + $h = bcdiv ( $v, 4294967296, 0 ); + $l = bcmod ( $v, 4294967296 ); + return pack ( "NN", $h, $l ); + } + + // x64, no-bcmath + $p = max ( 0, strlen($v) - 13 ); + $lo = (int)substr ( $v, $p ); + $hi = (int)substr ( $v, 0, $p ); + + $m = $lo + $hi*1316134912; + $l = $m % 4294967296; + $h = $hi*2328 + (int)($m/4294967296); + + return pack ( "NN", $h, $l ); + } + + // x32, int + if ( is_int($v) ) + return pack ( "NN", 0, $v ); + + // x32, bcmath + if ( function_exists("bcmul") ) + { + $h = bcdiv ( $v, "4294967296", 0 ); + $l = bcmod ( $v, "4294967296" ); + return pack ( "NN", (float)$h, (float)$l ); // conversion to float is intentional; int would lose 31st bit + } + + // x32, no-bcmath + $p = max(0, strlen($v) - 13); + $lo = (float)substr($v, $p); + $hi = (float)substr($v, 0, $p); + + $m = $lo + $hi*1316134912.0; + $q = floor($m / 4294967296.0); + $l = $m - ($q * 4294967296.0); + $h = $hi*2328.0 + $q; + + return pack ( "NN", $h, $l ); +} + +// unpack 64-bit unsigned +function sphUnpackU64 ( $v ) +{ + list ( $hi, $lo ) = array_values ( unpack ( "N*N*", $v ) ); + + if ( PHP_INT_SIZE>=8 ) + { + if ( $hi<0 ) $hi += (1<<32); // because php 5.2.2 to 5.2.5 is totally fucked up again + if ( $lo<0 ) $lo += (1<<32); + + // x64, int + if ( $hi<=2147483647 ) + return ($hi<<32) + $lo; + + // x64, bcmath + if ( function_exists("bcmul") ) + return bcadd ( $lo, bcmul ( $hi, "4294967296" ) ); + + // x64, no-bcmath + $C = 100000; + $h = ((int)($hi / $C) << 32) + (int)($lo / $C); + $l = (($hi % $C) << 32) + ($lo % $C); + if ( $l>$C ) + { + $h += (int)($l / $C); + $l = $l % $C; + } + + if ( $h==0 ) + return $l; + return sprintf ( "%d%05d", $h, $l ); + } + + // x32, int + if ( $hi==0 ) + { + if ( $lo>0 ) + return $lo; + return sprintf ( "%u", $lo ); + } + + $hi = sprintf ( "%u", $hi ); + $lo = sprintf ( "%u", $lo ); + + // x32, bcmath + if ( function_exists("bcmul") ) + return bcadd ( $lo, bcmul ( $hi, "4294967296" ) ); + + // x32, no-bcmath + $hi = (float)$hi; + $lo = (float)$lo; + + $q = floor($hi/10000000.0); + $r = $hi - $q*10000000.0; + $m = $lo + $r*4967296.0; + $mq = floor($m/10000000.0); + $l = $m - $mq*10000000.0; + $h = $q*4294967296.0 + $r*429.0 + $mq; + + $h = sprintf ( "%.0f", $h ); + $l = sprintf ( "%07.0f", $l ); + if ( $h=="0" ) + return sprintf( "%.0f", (float)$l ); + return $h . $l; +} + +// unpack 64-bit signed +function sphUnpackI64 ( $v ) +{ + list ( $hi, $lo ) = array_values ( unpack ( "N*N*", $v ) ); + + // x64 + if ( PHP_INT_SIZE>=8 ) + { + if ( $hi<0 ) $hi += (1<<32); // because php 5.2.2 to 5.2.5 is totally fucked up again + if ( $lo<0 ) $lo += (1<<32); + + return ($hi<<32) + $lo; + } + + // x32, int + if ( $hi==0 ) + { + if ( $lo>0 ) + return $lo; + return sprintf ( "%u", $lo ); + } + // x32, int + elseif ( $hi==-1 ) + { + if ( $lo<0 ) + return $lo; + return sprintf ( "%.0f", $lo - 4294967296.0 ); + } + + $neg = ""; + $c = 0; + if ( $hi<0 ) + { + $hi = ~$hi; + $lo = ~$lo; + $c = 1; + $neg = "-"; + } + + $hi = sprintf ( "%u", $hi ); + $lo = sprintf ( "%u", $lo ); + + // x32, bcmath + if ( function_exists("bcmul") ) + return $neg . bcadd ( bcadd ( $lo, bcmul ( $hi, "4294967296" ) ), $c ); + + // x32, no-bcmath + $hi = (float)$hi; + $lo = (float)$lo; + + $q = floor($hi/10000000.0); + $r = $hi - $q*10000000.0; + $m = $lo + $r*4967296.0; + $mq = floor($m/10000000.0); + $l = $m - $mq*10000000.0 + $c; + $h = $q*4294967296.0 + $r*429.0 + $mq; + if ( $l==10000000 ) + { + $l = 0; + $h += 1; + } + + $h = sprintf ( "%.0f", $h ); + $l = sprintf ( "%07.0f", $l ); + if ( $h=="0" ) + return $neg . sprintf( "%.0f", (float)$l ); + return $neg . $h . $l; +} + + +function sphFixUint ( $value ) +{ + if ( PHP_INT_SIZE>=8 ) + { + // x64 route, workaround broken unpack() in 5.2.2+ + if ( $value<0 ) $value += (1<<32); + return $value; + } + else + { + // x32 route, workaround php signed/unsigned braindamage + return sprintf ( "%u", $value ); + } +} + + +/// sphinx searchd client class +class SphinxClient +{ + var $_host; ///< searchd host (default is "localhost") + var $_port; ///< searchd port (default is 9312) + var $_offset; ///< how many records to seek from result-set start (default is 0) + var $_limit; ///< how many records to return from result-set starting at offset (default is 20) + var $_mode; ///< query matching mode (default is SPH_MATCH_ALL) + var $_weights; ///< per-field weights (default is 1 for all fields) + var $_sort; ///< match sorting mode (default is SPH_SORT_RELEVANCE) + var $_sortby; ///< attribute to sort by (defualt is "") + var $_min_id; ///< min ID to match (default is 0, which means no limit) + var $_max_id; ///< max ID to match (default is 0, which means no limit) + var $_filters; ///< search filters + var $_groupby; ///< group-by attribute name + var $_groupfunc; ///< group-by function (to pre-process group-by attribute value with) + var $_groupsort; ///< group-by sorting clause (to sort groups in result set with) + var $_groupdistinct;///< group-by count-distinct attribute + var $_maxmatches; ///< max matches to retrieve + var $_cutoff; ///< cutoff to stop searching at (default is 0) + var $_retrycount; ///< distributed retries count + var $_retrydelay; ///< distributed retries delay + var $_anchor; ///< geographical anchor point + var $_indexweights; ///< per-index weights + var $_ranker; ///< ranking mode (default is SPH_RANK_PROXIMITY_BM25) + var $_rankexpr; ///< ranking mode expression (for SPH_RANK_EXPR) + var $_maxquerytime; ///< max query time, milliseconds (default is 0, do not limit) + var $_fieldweights; ///< per-field-name weights + var $_overrides; ///< per-query attribute values overrides + var $_select; ///< select-list (attributes or expressions, with optional aliases) + + var $_error; ///< last error message + var $_warning; ///< last warning message + var $_connerror; ///< connection error vs remote error flag + + var $_reqs; ///< requests array for multi-query + var $_mbenc; ///< stored mbstring encoding + var $_arrayresult; ///< whether $result["matches"] should be a hash or an array + var $_timeout; ///< connect timeout + + ///////////////////////////////////////////////////////////////////////////// + // common stuff + ///////////////////////////////////////////////////////////////////////////// + + /// create a new client object and fill defaults + function SphinxClient () + { + // per-client-object settings + $this->_host = "localhost"; + $this->_port = 9312; + $this->_path = false; + $this->_socket = false; + + // per-query settings + $this->_offset = 0; + $this->_limit = 20; + $this->_mode = SPH_MATCH_ALL; + $this->_weights = array (); + $this->_sort = SPH_SORT_RELEVANCE; + $this->_sortby = ""; + $this->_min_id = 0; + $this->_max_id = 0; + $this->_filters = array (); + $this->_groupby = ""; + $this->_groupfunc = SPH_GROUPBY_DAY; + $this->_groupsort = "@group desc"; + $this->_groupdistinct= ""; + $this->_maxmatches = 1000; + $this->_cutoff = 0; + $this->_retrycount = 0; + $this->_retrydelay = 0; + $this->_anchor = array (); + $this->_indexweights= array (); + $this->_ranker = SPH_RANK_PROXIMITY_BM25; + $this->_rankexpr = ""; + $this->_maxquerytime= 0; + $this->_fieldweights= array(); + $this->_overrides = array(); + $this->_select = "*"; + + $this->_error = ""; // per-reply fields (for single-query case) + $this->_warning = ""; + $this->_connerror = false; + + $this->_reqs = array (); // requests storage (for multi-query case) + $this->_mbenc = ""; + $this->_arrayresult = false; + $this->_timeout = 0; + } + + function __destruct() + { + if ( $this->_socket !== false ) + fclose ( $this->_socket ); + } + + /// get last error message (string) + function GetLastError () + { + return $this->_error; + } + + /// get last warning message (string) + function GetLastWarning () + { + return $this->_warning; + } + + /// get last error flag (to tell network connection errors from searchd errors or broken responses) + function IsConnectError() + { + return $this->_connerror; + } + + /// set searchd host name (string) and port (integer) + function SetServer ( $host, $port = 0 ) + { + assert ( is_string($host) ); + if ( $host[0] == '/') + { + $this->_path = 'unix://' . $host; + return; + } + if ( substr ( $host, 0, 7 )=="unix://" ) + { + $this->_path = $host; + return; + } + + assert ( is_int($port) ); + $this->_host = $host; + $this->_port = $port; + $this->_path = ''; + + } + + /// set server connection timeout (0 to remove) + function SetConnectTimeout ( $timeout ) + { + assert ( is_numeric($timeout) ); + $this->_timeout = $timeout; + } + + + function _Send ( $handle, $data, $length ) + { + if ( feof($handle) || fwrite ( $handle, $data, $length ) !== $length ) + { + $this->_error = 'connection unexpectedly closed (timed out?)'; + $this->_connerror = true; + return false; + } + return true; + } + + ///////////////////////////////////////////////////////////////////////////// + + /// enter mbstring workaround mode + function _MBPush () + { + $this->_mbenc = ""; + if ( ini_get ( "mbstring.func_overload" ) & 2 ) + { + $this->_mbenc = mb_internal_encoding(); + mb_internal_encoding ( "latin1" ); + } + } + + /// leave mbstring workaround mode + function _MBPop () + { + if ( $this->_mbenc ) + mb_internal_encoding ( $this->_mbenc ); + } + + /// connect to searchd server + function _Connect () + { + if ( $this->_socket!==false ) + { + // we are in persistent connection mode, so we have a socket + // however, need to check whether it's still alive + if ( !@feof ( $this->_socket ) ) + return $this->_socket; + + // force reopen + $this->_socket = false; + } + + $errno = 0; + $errstr = ""; + $this->_connerror = false; + + if ( $this->_path ) + { + $host = $this->_path; + $port = 0; + } + else + { + $host = $this->_host; + $port = $this->_port; + } + + if ( $this->_timeout<=0 ) + $fp = @fsockopen ( $host, $port, $errno, $errstr ); + else + $fp = @fsockopen ( $host, $port, $errno, $errstr, $this->_timeout ); + + if ( !$fp ) + { + if ( $this->_path ) + $location = $this->_path; + else + $location = "{$this->_host}:{$this->_port}"; + + $errstr = trim ( $errstr ); + $this->_error = "connection to $location failed (errno=$errno, msg=$errstr)"; + $this->_connerror = true; + return false; + } + + // send my version + // this is a subtle part. we must do it before (!) reading back from searchd. + // because otherwise under some conditions (reported on FreeBSD for instance) + // TCP stack could throttle write-write-read pattern because of Nagle. + if ( !$this->_Send ( $fp, pack ( "N", 1 ), 4 ) ) + { + fclose ( $fp ); + $this->_error = "failed to send client protocol version"; + return false; + } + + // check version + list(,$v) = unpack ( "N*", fread ( $fp, 4 ) ); + $v = (int)$v; + if ( $v<1 ) + { + fclose ( $fp ); + $this->_error = "expected searchd protocol version 1+, got version '$v'"; + return false; + } + + return $fp; + } + + /// get and check response packet from searchd server + function _GetResponse ( $fp, $client_ver ) + { + $response = ""; + $len = 0; + + $header = fread ( $fp, 8 ); + if ( strlen($header)==8 ) + { + list ( $status, $ver, $len ) = array_values ( unpack ( "n2a/Nb", $header ) ); + $left = $len; + while ( $left>0 && !feof($fp) ) + { + $chunk = fread ( $fp, min ( 8192, $left ) ); + if ( $chunk ) + { + $response .= $chunk; + $left -= strlen($chunk); + } + } + } + if ( $this->_socket === false ) + fclose ( $fp ); + + // check response + $read = strlen ( $response ); + if ( !$response || $read!=$len ) + { + $this->_error = $len + ? "failed to read searchd response (status=$status, ver=$ver, len=$len, read=$read)" + : "received zero-sized searchd response"; + return false; + } + + // check status + if ( $status==SEARCHD_WARNING ) + { + list(,$wlen) = unpack ( "N*", substr ( $response, 0, 4 ) ); + $this->_warning = substr ( $response, 4, $wlen ); + return substr ( $response, 4+$wlen ); + } + if ( $status==SEARCHD_ERROR ) + { + $this->_error = "searchd error: " . substr ( $response, 4 ); + return false; + } + if ( $status==SEARCHD_RETRY ) + { + $this->_error = "temporary searchd error: " . substr ( $response, 4 ); + return false; + } + if ( $status!=SEARCHD_OK ) + { + $this->_error = "unknown status code '$status'"; + return false; + } + + // check version + if ( $ver<$client_ver ) + { + $this->_warning = sprintf ( "searchd command v.%d.%d older than client's v.%d.%d, some options might not work", + $ver>>8, $ver&0xff, $client_ver>>8, $client_ver&0xff ); + } + + return $response; + } + + ///////////////////////////////////////////////////////////////////////////// + // searching + ///////////////////////////////////////////////////////////////////////////// + + /// set offset and count into result set, + /// and optionally set max-matches and cutoff limits + function SetLimits ( $offset, $limit, $max=0, $cutoff=0 ) + { + assert ( is_int($offset) ); + assert ( is_int($limit) ); + assert ( $offset>=0 ); + assert ( $limit>0 ); + assert ( $max>=0 ); + $this->_offset = $offset; + $this->_limit = $limit; + if ( $max>0 ) + $this->_maxmatches = $max; + if ( $cutoff>0 ) + $this->_cutoff = $cutoff; + } + + /// set maximum query time, in milliseconds, per-index + /// integer, 0 means "do not limit" + function SetMaxQueryTime ( $max ) + { + assert ( is_int($max) ); + assert ( $max>=0 ); + $this->_maxquerytime = $max; + } + + /// set matching mode + function SetMatchMode ( $mode ) + { + assert ( $mode==SPH_MATCH_ALL + || $mode==SPH_MATCH_ANY + || $mode==SPH_MATCH_PHRASE + || $mode==SPH_MATCH_BOOLEAN + || $mode==SPH_MATCH_EXTENDED + || $mode==SPH_MATCH_FULLSCAN + || $mode==SPH_MATCH_EXTENDED2 ); + $this->_mode = $mode; + } + + /// set ranking mode + function SetRankingMode ( $ranker, $rankexpr="" ) + { + assert ( $ranker>=0 && $ranker_ranker = $ranker; + $this->_rankexpr = $rankexpr; + } + + /// set matches sorting mode + function SetSortMode ( $mode, $sortby="" ) + { + assert ( + $mode==SPH_SORT_RELEVANCE || + $mode==SPH_SORT_ATTR_DESC || + $mode==SPH_SORT_ATTR_ASC || + $mode==SPH_SORT_TIME_SEGMENTS || + $mode==SPH_SORT_EXTENDED || + $mode==SPH_SORT_EXPR ); + assert ( is_string($sortby) ); + assert ( $mode==SPH_SORT_RELEVANCE || strlen($sortby)>0 ); + + $this->_sort = $mode; + $this->_sortby = $sortby; + } + + /// bind per-field weights by order + /// DEPRECATED; use SetFieldWeights() instead + function SetWeights ( $weights ) + { + assert ( is_array($weights) ); + foreach ( $weights as $weight ) + assert ( is_int($weight) ); + + $this->_weights = $weights; + } + + /// bind per-field weights by name + function SetFieldWeights ( $weights ) + { + assert ( is_array($weights) ); + foreach ( $weights as $name=>$weight ) + { + assert ( is_string($name) ); + assert ( is_int($weight) ); + } + $this->_fieldweights = $weights; + } + + /// bind per-index weights by name + function SetIndexWeights ( $weights ) + { + assert ( is_array($weights) ); + foreach ( $weights as $index=>$weight ) + { + assert ( is_string($index) ); + assert ( is_int($weight) ); + } + $this->_indexweights = $weights; + } + + /// set IDs range to match + /// only match records if document ID is beetwen $min and $max (inclusive) + function SetIDRange ( $min, $max ) + { + assert ( is_numeric($min) ); + assert ( is_numeric($max) ); + assert ( $min<=$max ); + $this->_min_id = $min; + $this->_max_id = $max; + } + + /// set values set filter + /// only match records where $attribute value is in given set + function SetFilter ( $attribute, $values, $exclude=false ) + { + assert ( is_string($attribute) ); + assert ( is_array($values) ); + assert ( count($values) ); + + if ( is_array($values) && count($values) ) + { + foreach ( $values as $value ) + assert ( is_numeric($value) ); + + $this->_filters[] = array ( "type"=>SPH_FILTER_VALUES, "attr"=>$attribute, "exclude"=>$exclude, "values"=>$values ); + } + } + + /// set range filter + /// only match records if $attribute value is beetwen $min and $max (inclusive) + function SetFilterRange ( $attribute, $min, $max, $exclude=false ) + { + assert ( is_string($attribute) ); + assert ( is_numeric($min) ); + assert ( is_numeric($max) ); + assert ( $min<=$max ); + + $this->_filters[] = array ( "type"=>SPH_FILTER_RANGE, "attr"=>$attribute, "exclude"=>$exclude, "min"=>$min, "max"=>$max ); + } + + /// set float range filter + /// only match records if $attribute value is beetwen $min and $max (inclusive) + function SetFilterFloatRange ( $attribute, $min, $max, $exclude=false ) + { + assert ( is_string($attribute) ); + assert ( is_float($min) ); + assert ( is_float($max) ); + assert ( $min<=$max ); + + $this->_filters[] = array ( "type"=>SPH_FILTER_FLOATRANGE, "attr"=>$attribute, "exclude"=>$exclude, "min"=>$min, "max"=>$max ); + } + + /// setup anchor point for geosphere distance calculations + /// required to use @geodist in filters and sorting + /// latitude and longitude must be in radians + function SetGeoAnchor ( $attrlat, $attrlong, $lat, $long ) + { + assert ( is_string($attrlat) ); + assert ( is_string($attrlong) ); + assert ( is_float($lat) ); + assert ( is_float($long) ); + + $this->_anchor = array ( "attrlat"=>$attrlat, "attrlong"=>$attrlong, "lat"=>$lat, "long"=>$long ); + } + + /// set grouping attribute and function + function SetGroupBy ( $attribute, $func, $groupsort="@group desc" ) + { + assert ( is_string($attribute) ); + assert ( is_string($groupsort) ); + assert ( $func==SPH_GROUPBY_DAY + || $func==SPH_GROUPBY_WEEK + || $func==SPH_GROUPBY_MONTH + || $func==SPH_GROUPBY_YEAR + || $func==SPH_GROUPBY_ATTR + || $func==SPH_GROUPBY_ATTRPAIR ); + + $this->_groupby = $attribute; + $this->_groupfunc = $func; + $this->_groupsort = $groupsort; + } + + /// set count-distinct attribute for group-by queries + function SetGroupDistinct ( $attribute ) + { + assert ( is_string($attribute) ); + $this->_groupdistinct = $attribute; + } + + /// set distributed retries count and delay + function SetRetries ( $count, $delay=0 ) + { + assert ( is_int($count) && $count>=0 ); + assert ( is_int($delay) && $delay>=0 ); + $this->_retrycount = $count; + $this->_retrydelay = $delay; + } + + /// set result set format (hash or array; hash by default) + /// PHP specific; needed for group-by-MVA result sets that may contain duplicate IDs + function SetArrayResult ( $arrayresult ) + { + assert ( is_bool($arrayresult) ); + $this->_arrayresult = $arrayresult; + } + + /// set attribute values override + /// there can be only one override per attribute + /// $values must be a hash that maps document IDs to attribute values + function SetOverride ( $attrname, $attrtype, $values ) + { + assert ( is_string ( $attrname ) ); + assert ( in_array ( $attrtype, array ( SPH_ATTR_INTEGER, SPH_ATTR_TIMESTAMP, SPH_ATTR_BOOL, SPH_ATTR_FLOAT, SPH_ATTR_BIGINT ) ) ); + assert ( is_array ( $values ) ); + + $this->_overrides[$attrname] = array ( "attr"=>$attrname, "type"=>$attrtype, "values"=>$values ); + } + + /// set select-list (attributes or expressions), SQL-like syntax + function SetSelect ( $select ) + { + assert ( is_string ( $select ) ); + $this->_select = $select; + } + + ////////////////////////////////////////////////////////////////////////////// + + /// clear all filters (for multi-queries) + function ResetFilters () + { + $this->_filters = array(); + $this->_anchor = array(); + } + + /// clear groupby settings (for multi-queries) + function ResetGroupBy () + { + $this->_groupby = ""; + $this->_groupfunc = SPH_GROUPBY_DAY; + $this->_groupsort = "@group desc"; + $this->_groupdistinct= ""; + } + + /// clear all attribute value overrides (for multi-queries) + function ResetOverrides () + { + $this->_overrides = array (); + } + + ////////////////////////////////////////////////////////////////////////////// + + /// connect to searchd server, run given search query through given indexes, + /// and return the search results + function Query ( $query, $index="*", $comment="" ) + { + assert ( empty($this->_reqs) ); + + $this->AddQuery ( $query, $index, $comment ); + $results = $this->RunQueries (); + $this->_reqs = array (); // just in case it failed too early + + if ( !is_array($results) ) + return false; // probably network error; error message should be already filled + + $this->_error = $results[0]["error"]; + $this->_warning = $results[0]["warning"]; + if ( $results[0]["status"]==SEARCHD_ERROR ) + return false; + else + return $results[0]; + } + + /// helper to pack floats in network byte order + function _PackFloat ( $f ) + { + $t1 = pack ( "f", $f ); // machine order + list(,$t2) = unpack ( "L*", $t1 ); // int in machine order + return pack ( "N", $t2 ); + } + + /// add query to multi-query batch + /// returns index into results array from RunQueries() call + function AddQuery ( $query, $index="*", $comment="" ) + { + // mbstring workaround + $this->_MBPush (); + + // build request + $req = pack ( "NNNN", $this->_offset, $this->_limit, $this->_mode, $this->_ranker ); + if ( $this->_ranker==SPH_RANK_EXPR ) + $req .= pack ( "N", strlen($this->_rankexpr) ) . $this->_rankexpr; + $req .= pack ( "N", $this->_sort ); // (deprecated) sort mode + $req .= pack ( "N", strlen($this->_sortby) ) . $this->_sortby; + $req .= pack ( "N", strlen($query) ) . $query; // query itself + $req .= pack ( "N", count($this->_weights) ); // weights + foreach ( $this->_weights as $weight ) + $req .= pack ( "N", (int)$weight ); + $req .= pack ( "N", strlen($index) ) . $index; // indexes + $req .= pack ( "N", 1 ); // id64 range marker + $req .= sphPackU64 ( $this->_min_id ) . sphPackU64 ( $this->_max_id ); // id64 range + + // filters + $req .= pack ( "N", count($this->_filters) ); + foreach ( $this->_filters as $filter ) + { + $req .= pack ( "N", strlen($filter["attr"]) ) . $filter["attr"]; + $req .= pack ( "N", $filter["type"] ); + switch ( $filter["type"] ) + { + case SPH_FILTER_VALUES: + $req .= pack ( "N", count($filter["values"]) ); + foreach ( $filter["values"] as $value ) + $req .= sphPackI64 ( $value ); + break; + + case SPH_FILTER_RANGE: + $req .= sphPackI64 ( $filter["min"] ) . sphPackI64 ( $filter["max"] ); + break; + + case SPH_FILTER_FLOATRANGE: + $req .= $this->_PackFloat ( $filter["min"] ) . $this->_PackFloat ( $filter["max"] ); + break; + + default: + assert ( 0 && "internal error: unhandled filter type" ); + } + $req .= pack ( "N", $filter["exclude"] ); + } + + // group-by clause, max-matches count, group-sort clause, cutoff count + $req .= pack ( "NN", $this->_groupfunc, strlen($this->_groupby) ) . $this->_groupby; + $req .= pack ( "N", $this->_maxmatches ); + $req .= pack ( "N", strlen($this->_groupsort) ) . $this->_groupsort; + $req .= pack ( "NNN", $this->_cutoff, $this->_retrycount, $this->_retrydelay ); + $req .= pack ( "N", strlen($this->_groupdistinct) ) . $this->_groupdistinct; + + // anchor point + if ( empty($this->_anchor) ) + { + $req .= pack ( "N", 0 ); + } else + { + $a =& $this->_anchor; + $req .= pack ( "N", 1 ); + $req .= pack ( "N", strlen($a["attrlat"]) ) . $a["attrlat"]; + $req .= pack ( "N", strlen($a["attrlong"]) ) . $a["attrlong"]; + $req .= $this->_PackFloat ( $a["lat"] ) . $this->_PackFloat ( $a["long"] ); + } + + // per-index weights + $req .= pack ( "N", count($this->_indexweights) ); + foreach ( $this->_indexweights as $idx=>$weight ) + $req .= pack ( "N", strlen($idx) ) . $idx . pack ( "N", $weight ); + + // max query time + $req .= pack ( "N", $this->_maxquerytime ); + + // per-field weights + $req .= pack ( "N", count($this->_fieldweights) ); + foreach ( $this->_fieldweights as $field=>$weight ) + $req .= pack ( "N", strlen($field) ) . $field . pack ( "N", $weight ); + + // comment + $req .= pack ( "N", strlen($comment) ) . $comment; + + // attribute overrides + $req .= pack ( "N", count($this->_overrides) ); + foreach ( $this->_overrides as $key => $entry ) + { + $req .= pack ( "N", strlen($entry["attr"]) ) . $entry["attr"]; + $req .= pack ( "NN", $entry["type"], count($entry["values"]) ); + foreach ( $entry["values"] as $id=>$val ) + { + assert ( is_numeric($id) ); + assert ( is_numeric($val) ); + + $req .= sphPackU64 ( $id ); + switch ( $entry["type"] ) + { + case SPH_ATTR_FLOAT: $req .= $this->_PackFloat ( $val ); break; + case SPH_ATTR_BIGINT: $req .= sphPackI64 ( $val ); break; + default: $req .= pack ( "N", $val ); break; + } + } + } + + // select-list + $req .= pack ( "N", strlen($this->_select) ) . $this->_select; + + // mbstring workaround + $this->_MBPop (); + + // store request to requests array + $this->_reqs[] = $req; + return count($this->_reqs)-1; + } + + /// connect to searchd, run queries batch, and return an array of result sets + function RunQueries () + { + if ( empty($this->_reqs) ) + { + $this->_error = "no queries defined, issue AddQuery() first"; + return false; + } + + // mbstring workaround + $this->_MBPush (); + + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop (); + return false; + } + + // send query, get response + $nreqs = count($this->_reqs); + $req = join ( "", $this->_reqs ); + $len = 8+strlen($req); + $req = pack ( "nnNNN", SEARCHD_COMMAND_SEARCH, VER_COMMAND_SEARCH, $len, 0, $nreqs ) . $req; // add header + + if ( !( $this->_Send ( $fp, $req, $len+8 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_SEARCH ) ) ) + { + $this->_MBPop (); + return false; + } + + // query sent ok; we can reset reqs now + $this->_reqs = array (); + + // parse and return response + return $this->_ParseSearchResponse ( $response, $nreqs ); + } + + /// parse and return search query (or queries) response + function _ParseSearchResponse ( $response, $nreqs ) + { + $p = 0; // current position + $max = strlen($response); // max position for checks, to protect against broken responses + + $results = array (); + for ( $ires=0; $ires<$nreqs && $p<$max; $ires++ ) + { + $results[] = array(); + $result =& $results[$ires]; + + $result["error"] = ""; + $result["warning"] = ""; + + // extract status + list(,$status) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $result["status"] = $status; + if ( $status!=SEARCHD_OK ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $message = substr ( $response, $p, $len ); $p += $len; + + if ( $status==SEARCHD_WARNING ) + { + $result["warning"] = $message; + } else + { + $result["error"] = $message; + continue; + } + } + + // read schema + $fields = array (); + $attrs = array (); + + list(,$nfields) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + while ( $nfields-->0 && $p<$max ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $fields[] = substr ( $response, $p, $len ); $p += $len; + } + $result["fields"] = $fields; + + list(,$nattrs) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + while ( $nattrs-->0 && $p<$max ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $attr = substr ( $response, $p, $len ); $p += $len; + list(,$type) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $attrs[$attr] = $type; + } + $result["attrs"] = $attrs; + + // read match count + list(,$count) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + list(,$id64) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + + // read matches + $idx = -1; + while ( $count-->0 && $p<$max ) + { + // index into result array + $idx++; + + // parse document id and weight + if ( $id64 ) + { + $doc = sphUnpackU64 ( substr ( $response, $p, 8 ) ); $p += 8; + list(,$weight) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + } + else + { + list ( $doc, $weight ) = array_values ( unpack ( "N*N*", + substr ( $response, $p, 8 ) ) ); + $p += 8; + $doc = sphFixUint($doc); + } + $weight = sprintf ( "%u", $weight ); + + // create match entry + if ( $this->_arrayresult ) + $result["matches"][$idx] = array ( "id"=>$doc, "weight"=>$weight ); + else + $result["matches"][$doc]["weight"] = $weight; + + // parse and create attributes + $attrvals = array (); + foreach ( $attrs as $attr=>$type ) + { + // handle 64bit ints + if ( $type==SPH_ATTR_BIGINT ) + { + $attrvals[$attr] = sphUnpackI64 ( substr ( $response, $p, 8 ) ); $p += 8; + continue; + } + + // handle floats + if ( $type==SPH_ATTR_FLOAT ) + { + list(,$uval) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + list(,$fval) = unpack ( "f*", pack ( "L", $uval ) ); + $attrvals[$attr] = $fval; + continue; + } + + // handle everything else as unsigned ints + list(,$val) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + if ( $type==SPH_ATTR_MULTI ) + { + $attrvals[$attr] = array (); + $nvalues = $val; + while ( $nvalues-->0 && $p<$max ) + { + list(,$val) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $attrvals[$attr][] = sphFixUint($val); + } + } else if ( $type==SPH_ATTR_MULTI64 ) + { + $attrvals[$attr] = array (); + $nvalues = $val; + while ( $nvalues>0 && $p<$max ) + { + $attrvals[$attr][] = sphUnpackU64 ( substr ( $response, $p, 8 ) ); $p += 8; + $nvalues -= 2; + } + } else if ( $type==SPH_ATTR_STRING ) + { + $attrvals[$attr] = substr ( $response, $p, $val ); + $p += $val; + } else + { + $attrvals[$attr] = sphFixUint($val); + } + } + + if ( $this->_arrayresult ) + $result["matches"][$idx]["attrs"] = $attrvals; + else + $result["matches"][$doc]["attrs"] = $attrvals; + } + + list ( $total, $total_found, $msecs, $words ) = + array_values ( unpack ( "N*N*N*N*", substr ( $response, $p, 16 ) ) ); + $result["total"] = sprintf ( "%u", $total ); + $result["total_found"] = sprintf ( "%u", $total_found ); + $result["time"] = sprintf ( "%.3f", $msecs/1000 ); + $p += 16; + + while ( $words-->0 && $p<$max ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $word = substr ( $response, $p, $len ); $p += $len; + list ( $docs, $hits ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8; + $result["words"][$word] = array ( + "docs"=>sprintf ( "%u", $docs ), + "hits"=>sprintf ( "%u", $hits ) ); + } + } + + $this->_MBPop (); + return $results; + } + + ///////////////////////////////////////////////////////////////////////////// + // excerpts generation + ///////////////////////////////////////////////////////////////////////////// + + /// connect to searchd server, and generate exceprts (snippets) + /// of given documents for given query. returns false on failure, + /// an array of snippets on success + function BuildExcerpts ( $docs, $index, $words, $opts=array() ) + { + assert ( is_array($docs) ); + assert ( is_string($index) ); + assert ( is_string($words) ); + assert ( is_array($opts) ); + + $this->_MBPush (); + + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop(); + return false; + } + + ///////////////// + // fixup options + ///////////////// + + if ( !isset($opts["before_match"]) ) $opts["before_match"] = ""; + if ( !isset($opts["after_match"]) ) $opts["after_match"] = ""; + if ( !isset($opts["chunk_separator"]) ) $opts["chunk_separator"] = " ... "; + if ( !isset($opts["limit"]) ) $opts["limit"] = 256; + if ( !isset($opts["limit_passages"]) ) $opts["limit_passages"] = 0; + if ( !isset($opts["limit_words"]) ) $opts["limit_words"] = 0; + if ( !isset($opts["around"]) ) $opts["around"] = 5; + if ( !isset($opts["exact_phrase"]) ) $opts["exact_phrase"] = false; + if ( !isset($opts["single_passage"]) ) $opts["single_passage"] = false; + if ( !isset($opts["use_boundaries"]) ) $opts["use_boundaries"] = false; + if ( !isset($opts["weight_order"]) ) $opts["weight_order"] = false; + if ( !isset($opts["query_mode"]) ) $opts["query_mode"] = false; + if ( !isset($opts["force_all_words"]) ) $opts["force_all_words"] = false; + if ( !isset($opts["start_passage_id"]) ) $opts["start_passage_id"] = 1; + if ( !isset($opts["load_files"]) ) $opts["load_files"] = false; + if ( !isset($opts["html_strip_mode"]) ) $opts["html_strip_mode"] = "index"; + if ( !isset($opts["allow_empty"]) ) $opts["allow_empty"] = false; + if ( !isset($opts["passage_boundary"]) ) $opts["passage_boundary"] = "none"; + if ( !isset($opts["emit_zones"]) ) $opts["emit_zones"] = false; + if ( !isset($opts["load_files_scattered"]) ) $opts["load_files_scattered"] = false; + + + ///////////////// + // build request + ///////////////// + + // v.1.2 req + $flags = 1; // remove spaces + if ( $opts["exact_phrase"] ) $flags |= 2; + if ( $opts["single_passage"] ) $flags |= 4; + if ( $opts["use_boundaries"] ) $flags |= 8; + if ( $opts["weight_order"] ) $flags |= 16; + if ( $opts["query_mode"] ) $flags |= 32; + if ( $opts["force_all_words"] ) $flags |= 64; + if ( $opts["load_files"] ) $flags |= 128; + if ( $opts["allow_empty"] ) $flags |= 256; + if ( $opts["emit_zones"] ) $flags |= 512; + if ( $opts["load_files_scattered"] ) $flags |= 1024; + $req = pack ( "NN", 0, $flags ); // mode=0, flags=$flags + $req .= pack ( "N", strlen($index) ) . $index; // req index + $req .= pack ( "N", strlen($words) ) . $words; // req words + + // options + $req .= pack ( "N", strlen($opts["before_match"]) ) . $opts["before_match"]; + $req .= pack ( "N", strlen($opts["after_match"]) ) . $opts["after_match"]; + $req .= pack ( "N", strlen($opts["chunk_separator"]) ) . $opts["chunk_separator"]; + $req .= pack ( "NN", (int)$opts["limit"], (int)$opts["around"] ); + $req .= pack ( "NNN", (int)$opts["limit_passages"], (int)$opts["limit_words"], (int)$opts["start_passage_id"] ); // v.1.2 + $req .= pack ( "N", strlen($opts["html_strip_mode"]) ) . $opts["html_strip_mode"]; + $req .= pack ( "N", strlen($opts["passage_boundary"]) ) . $opts["passage_boundary"]; + + // documents + $req .= pack ( "N", count($docs) ); + foreach ( $docs as $doc ) + { + assert ( is_string($doc) ); + $req .= pack ( "N", strlen($doc) ) . $doc; + } + + //////////////////////////// + // send query, get response + //////////////////////////// + + $len = strlen($req); + $req = pack ( "nnN", SEARCHD_COMMAND_EXCERPT, VER_COMMAND_EXCERPT, $len ) . $req; // add header + if ( !( $this->_Send ( $fp, $req, $len+8 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_EXCERPT ) ) ) + { + $this->_MBPop (); + return false; + } + + ////////////////// + // parse response + ////////////////// + + $pos = 0; + $res = array (); + $rlen = strlen($response); + for ( $i=0; $i $rlen ) + { + $this->_error = "incomplete reply"; + $this->_MBPop (); + return false; + } + $res[] = $len ? substr ( $response, $pos, $len ) : ""; + $pos += $len; + } + + $this->_MBPop (); + return $res; + } + + + ///////////////////////////////////////////////////////////////////////////// + // keyword generation + ///////////////////////////////////////////////////////////////////////////// + + /// connect to searchd server, and generate keyword list for a given query + /// returns false on failure, + /// an array of words on success + function BuildKeywords ( $query, $index, $hits ) + { + assert ( is_string($query) ); + assert ( is_string($index) ); + assert ( is_bool($hits) ); + + $this->_MBPush (); + + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop(); + return false; + } + + ///////////////// + // build request + ///////////////// + + // v.1.0 req + $req = pack ( "N", strlen($query) ) . $query; // req query + $req .= pack ( "N", strlen($index) ) . $index; // req index + $req .= pack ( "N", (int)$hits ); + + //////////////////////////// + // send query, get response + //////////////////////////// + + $len = strlen($req); + $req = pack ( "nnN", SEARCHD_COMMAND_KEYWORDS, VER_COMMAND_KEYWORDS, $len ) . $req; // add header + if ( !( $this->_Send ( $fp, $req, $len+8 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_KEYWORDS ) ) ) + { + $this->_MBPop (); + return false; + } + + ////////////////// + // parse response + ////////////////// + + $pos = 0; + $res = array (); + $rlen = strlen($response); + list(,$nwords) = unpack ( "N*", substr ( $response, $pos, 4 ) ); + $pos += 4; + for ( $i=0; $i<$nwords; $i++ ) + { + list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) ); $pos += 4; + $tokenized = $len ? substr ( $response, $pos, $len ) : ""; + $pos += $len; + + list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) ); $pos += 4; + $normalized = $len ? substr ( $response, $pos, $len ) : ""; + $pos += $len; + + $res[] = array ( "tokenized"=>$tokenized, "normalized"=>$normalized ); + + if ( $hits ) + { + list($ndocs,$nhits) = array_values ( unpack ( "N*N*", substr ( $response, $pos, 8 ) ) ); + $pos += 8; + $res [$i]["docs"] = $ndocs; + $res [$i]["hits"] = $nhits; + } + + if ( $pos > $rlen ) + { + $this->_error = "incomplete reply"; + $this->_MBPop (); + return false; + } + } + + $this->_MBPop (); + return $res; + } + + function EscapeString ( $string ) + { + $from = array ( '\\', '(',')','|','-','!','@','~','"','&', '/', '^', '$', '=' ); + $to = array ( '\\\\', '\(','\)','\|','\-','\!','\@','\~','\"', '\&', '\/', '\^', '\$', '\=' ); + + return str_replace ( $from, $to, $string ); + } + + ///////////////////////////////////////////////////////////////////////////// + // attribute updates + ///////////////////////////////////////////////////////////////////////////// + + /// batch update given attributes in given rows in given indexes + /// returns amount of updated documents (0 or more) on success, or -1 on failure + function UpdateAttributes ( $index, $attrs, $values, $mva=false ) + { + // verify everything + assert ( is_string($index) ); + assert ( is_bool($mva) ); + + assert ( is_array($attrs) ); + foreach ( $attrs as $attr ) + assert ( is_string($attr) ); + + assert ( is_array($values) ); + foreach ( $values as $id=>$entry ) + { + assert ( is_numeric($id) ); + assert ( is_array($entry) ); + assert ( count($entry)==count($attrs) ); + foreach ( $entry as $v ) + { + if ( $mva ) + { + assert ( is_array($v) ); + foreach ( $v as $vv ) + assert ( is_int($vv) ); + } else + assert ( is_int($v) ); + } + } + + // build request + $this->_MBPush (); + $req = pack ( "N", strlen($index) ) . $index; + + $req .= pack ( "N", count($attrs) ); + foreach ( $attrs as $attr ) + { + $req .= pack ( "N", strlen($attr) ) . $attr; + $req .= pack ( "N", $mva ? 1 : 0 ); + } + + $req .= pack ( "N", count($values) ); + foreach ( $values as $id=>$entry ) + { + $req .= sphPackU64 ( $id ); + foreach ( $entry as $v ) + { + $req .= pack ( "N", $mva ? count($v) : $v ); + if ( $mva ) + foreach ( $v as $vv ) + $req .= pack ( "N", $vv ); + } + } + + // connect, send query, get response + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop (); + return -1; + } + + $len = strlen($req); + $req = pack ( "nnN", SEARCHD_COMMAND_UPDATE, VER_COMMAND_UPDATE, $len ) . $req; // add header + if ( !$this->_Send ( $fp, $req, $len+8 ) ) + { + $this->_MBPop (); + return -1; + } + + if (!( $response = $this->_GetResponse ( $fp, VER_COMMAND_UPDATE ) )) + { + $this->_MBPop (); + return -1; + } + + // parse response + list(,$updated) = unpack ( "N*", substr ( $response, 0, 4 ) ); + $this->_MBPop (); + return $updated; + } + + ///////////////////////////////////////////////////////////////////////////// + // persistent connections + ///////////////////////////////////////////////////////////////////////////// + + function Open() + { + if ( $this->_socket !== false ) + { + $this->_error = 'already connected'; + return false; + } + if ( !$fp = $this->_Connect() ) + return false; + + // command, command version = 0, body length = 4, body = 1 + $req = pack ( "nnNN", SEARCHD_COMMAND_PERSIST, 0, 4, 1 ); + if ( !$this->_Send ( $fp, $req, 12 ) ) + return false; + + $this->_socket = $fp; + return true; + } + + function Close() + { + if ( $this->_socket === false ) + { + $this->_error = 'not connected'; + return false; + } + + fclose ( $this->_socket ); + $this->_socket = false; + + return true; + } + + ////////////////////////////////////////////////////////////////////////// + // status + ////////////////////////////////////////////////////////////////////////// + + function Status () + { + $this->_MBPush (); + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop(); + return false; + } + + $req = pack ( "nnNN", SEARCHD_COMMAND_STATUS, VER_COMMAND_STATUS, 4, 1 ); // len=4, body=1 + if ( !( $this->_Send ( $fp, $req, 12 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_STATUS ) ) ) + { + $this->_MBPop (); + return false; + } + + $res = substr ( $response, 4 ); // just ignore length, error handling, etc + $p = 0; + list ( $rows, $cols ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8; + + $res = array(); + for ( $i=0; $i<$rows; $i++ ) + for ( $j=0; $j<$cols; $j++ ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $res[$i][] = substr ( $response, $p, $len ); $p += $len; + } + + $this->_MBPop (); + return $res; + } + + ////////////////////////////////////////////////////////////////////////// + // flush + ////////////////////////////////////////////////////////////////////////// + + function FlushAttributes () + { + $this->_MBPush (); + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop(); + return -1; + } + + $req = pack ( "nnN", SEARCHD_COMMAND_FLUSHATTRS, VER_COMMAND_FLUSHATTRS, 0 ); // len=0 + if ( !( $this->_Send ( $fp, $req, 8 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_FLUSHATTRS ) ) ) + { + $this->_MBPop (); + return -1; + } + + $tag = -1; + if ( strlen($response)==4 ) + list(,$tag) = unpack ( "N*", $response ); + else + $this->_error = "unexpected response length"; + + $this->_MBPop (); + return $tag; + } +} + +// +// $Id: sphinxapi.php 3087 2012-01-30 23:07:35Z shodan $ +// diff --git a/tests/session/append_sid_test.php b/tests/session/append_sid_test.php index 34f6dea8ca..b9e9ac1aa9 100644 --- a/tests/session/append_sid_test.php +++ b/tests/session/append_sid_test.php @@ -1,54 +1,54 @@ - 1, 'f' => 2), true, false, 'viewtopic.php?t=1&f=2', 'parameters in params-argument as array'), - - // Custom sid parameter - array('viewtopic.php', 't=1&f=2', true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid', 'using session_id'), - - // Testing anchors - array('viewtopic.php?t=1&f=2#anchor', false, true, false, 'viewtopic.php?t=1&f=2#anchor', 'anchor in url-argument'), - array('viewtopic.php', 't=1&f=2#anchor', true, false, 'viewtopic.php?t=1&f=2#anchor', 'anchor in params-argument'), - array('viewtopic.php', array('t' => 1, 'f' => 2, '#' => 'anchor'), true, false, 'viewtopic.php?t=1&f=2#anchor', 'anchor in params-argument (array)'), - - // Anchors and custom sid - array('viewtopic.php?t=1&f=2#anchor', false, true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid#anchor', 'anchor in url-argument using session_id'), - array('viewtopic.php', 't=1&f=2#anchor', true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid#anchor', 'anchor in params-argument using session_id'), - array('viewtopic.php', array('t' => 1, 'f' => 2, '#' => 'anchor'), true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid#anchor', 'anchor in params-argument (array) using session_id'), - - // Empty parameters should not append the ? - array('viewtopic.php', false, true, false, 'viewtopic.php', 'no params using bool false'), - array('viewtopic.php', '', true, false, 'viewtopic.php', 'no params using empty string'), - array('viewtopic.php', array(), true, false, 'viewtopic.php', 'no params using empty array'), - ); - } - - /** - * @dataProvider append_sid_data - */ - public function test_append_sid($url, $params, $is_amp, $session_id, $expected, $description) - { - global $phpbb_dispatcher; - - $phpbb_dispatcher = new phpbb_mock_event_dispatcher; - $this->assertEquals($expected, append_sid($url, $params, $is_amp, $session_id)); - } -} - + 1, 'f' => 2), true, false, 'viewtopic.php?t=1&f=2', 'parameters in params-argument as array'), + + // Custom sid parameter + array('viewtopic.php', 't=1&f=2', true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid', 'using session_id'), + + // Testing anchors + array('viewtopic.php?t=1&f=2#anchor', false, true, false, 'viewtopic.php?t=1&f=2#anchor', 'anchor in url-argument'), + array('viewtopic.php', 't=1&f=2#anchor', true, false, 'viewtopic.php?t=1&f=2#anchor', 'anchor in params-argument'), + array('viewtopic.php', array('t' => 1, 'f' => 2, '#' => 'anchor'), true, false, 'viewtopic.php?t=1&f=2#anchor', 'anchor in params-argument (array)'), + + // Anchors and custom sid + array('viewtopic.php?t=1&f=2#anchor', false, true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid#anchor', 'anchor in url-argument using session_id'), + array('viewtopic.php', 't=1&f=2#anchor', true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid#anchor', 'anchor in params-argument using session_id'), + array('viewtopic.php', array('t' => 1, 'f' => 2, '#' => 'anchor'), true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid#anchor', 'anchor in params-argument (array) using session_id'), + + // Empty parameters should not append the ? + array('viewtopic.php', false, true, false, 'viewtopic.php', 'no params using bool false'), + array('viewtopic.php', '', true, false, 'viewtopic.php', 'no params using empty string'), + array('viewtopic.php', array(), true, false, 'viewtopic.php', 'no params using empty array'), + ); + } + + /** + * @dataProvider append_sid_data + */ + public function test_append_sid($url, $params, $is_amp, $session_id, $expected, $description) + { + global $phpbb_dispatcher; + + $phpbb_dispatcher = new phpbb_mock_event_dispatcher; + $this->assertEquals($expected, append_sid($url, $params, $is_amp, $session_id)); + } +} + From 8a28271dd500b3623e1402339252504468e567f6 Mon Sep 17 00:00:00 2001 From: Nathan Guse Date: Fri, 7 Dec 2012 21:23:20 -0600 Subject: [PATCH 135/497] [ticket/11257] Do not require set_name() method to exist To use Service Collection PHPBB3-11257 --- phpBB/config/cron_tasks.yml | 16 ++++++++++++++++ phpBB/includes/di/service_collection.php | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/phpBB/config/cron_tasks.yml b/phpBB/config/cron_tasks.yml index 74f57e449d..d1954b1877 100644 --- a/phpBB/config/cron_tasks.yml +++ b/phpBB/config/cron_tasks.yml @@ -6,6 +6,8 @@ services: - %core.php_ext% - @config - @dbal.conn + calls: + - [set_name, [cron.task.core.prune_all_forums]] tags: - { name: cron.task } @@ -16,6 +18,8 @@ services: - %core.php_ext% - @config - @dbal.conn + calls: + - [set_name, [cron.task.core.prune_forum]] tags: - { name: cron.task } @@ -25,6 +29,8 @@ services: - %core.root_path% - %core.php_ext% - @config + calls: + - [set_name, [cron.task.core.queue]] tags: - { name: cron.task } @@ -33,6 +39,8 @@ services: arguments: - @config - @cache.driver + calls: + - [set_name, [cron.task.core.tidy_cache]] tags: - { name: cron.task } @@ -42,6 +50,8 @@ services: - %core.root_path% - %core.php_ext% - @config + calls: + - [set_name, [cron.task.core.tidy_database]] tags: - { name: cron.task } @@ -54,6 +64,8 @@ services: - @config - @dbal.conn - @user + calls: + - [set_name, [cron.task.core.tidy_search]] tags: - { name: cron.task } @@ -62,6 +74,8 @@ services: arguments: - @config - @user + calls: + - [set_name, [cron.task.core.tidy_sessions]] tags: - { name: cron.task } @@ -71,5 +85,7 @@ services: - %core.root_path% - %core.php_ext% - @config + calls: + - [set_name, [cron.task.core.tidy_warnings]] tags: - { name: cron.task } diff --git a/phpBB/includes/di/service_collection.php b/phpBB/includes/di/service_collection.php index 60323c8dba..880cb46d4d 100644 --- a/phpBB/includes/di/service_collection.php +++ b/phpBB/includes/di/service_collection.php @@ -43,7 +43,7 @@ class phpbb_di_service_collection extends ArrayObject public function add($name) { $task = $this->container->get($name); - $task->set_name($name); + $this->offsetSet($name, $task); } } From 6dee2539419ba2c050830b7677294603a63b559a Mon Sep 17 00:00:00 2001 From: Nathan Guse Date: Sun, 9 Dec 2012 17:01:08 -0600 Subject: [PATCH 136/497] [ticket/11259] Make phpbb_admin_path available everywhere PHPBB3-11259 --- phpBB/adm/index.php | 1 - phpBB/adm/style/install_header.html | 6 +++--- phpBB/adm/style/install_update_diff.html | 2 +- phpBB/adm/swatch.php | 2 -- phpBB/common.php | 4 ++++ phpBB/includes/db/dbal.php | 4 ++-- phpBB/includes/functions.php | 4 ++-- phpBB/includes/functions_install.php | 3 +++ phpBB/includes/ucp/ucp_groups.php | 6 +++--- phpBB/install/database_update.php | 8 ++++++-- phpBB/install/index.php | 16 ++++++++++------ phpBB/install/install_install.php | 4 ++-- phpBB/install/install_update.php | 11 ++++++----- phpBB/language/en/install.php | 2 +- phpBB/memberlist.php | 2 +- phpBB/viewonline.php | 2 +- 16 files changed, 45 insertions(+), 32 deletions(-) diff --git a/phpBB/adm/index.php b/phpBB/adm/index.php index e20bbe4bec..2591fa9d24 100644 --- a/phpBB/adm/index.php +++ b/phpBB/adm/index.php @@ -42,7 +42,6 @@ if (!$auth->acl_get('a_')) // We define the admin variables now, because the user is now able to use the admin related features... define('IN_ADMIN', true); -$phpbb_admin_path = (defined('PHPBB_ADMIN_PATH')) ? PHPBB_ADMIN_PATH : './'; // Some oft used variables $safe_mode = (@ini_get('safe_mode') == '1' || strtolower(@ini_get('safe_mode')) === 'on') ? true : false; diff --git a/phpBB/adm/style/install_header.html b/phpBB/adm/style/install_header.html index 6826654ded..5631b83e17 100644 --- a/phpBB/adm/style/install_header.html +++ b/phpBB/adm/style/install_header.html @@ -5,7 +5,7 @@ {META} {PAGE_TITLE} - + + + + From c83c5c7f473b8b7211560a826b84800831167f0b Mon Sep 17 00:00:00 2001 From: Michael Cullum Date: Tue, 13 Mar 2012 13:22:58 +0000 Subject: [PATCH 221/497] [feature/events] Add overall_header_nav template ledge Adds a ledge next to the FAQ button for extensions to put links on the navigation bar PHPBB3-9550 --- phpBB/styles/prosilver/template/overall_header.html | 1 + 1 file changed, 1 insertion(+) diff --git a/phpBB/styles/prosilver/template/overall_header.html b/phpBB/styles/prosilver/template/overall_header.html index c7aac764a5..aa931293d6 100644 --- a/phpBB/styles/prosilver/template/overall_header.html +++ b/phpBB/styles/prosilver/template/overall_header.html @@ -147,6 +147,7 @@