diff options
106 files changed, 2626 insertions, 448 deletions
diff --git a/.gitignore b/.gitignore index 25a6352f8d..18f598cf67 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,6 @@ /phpBB/images/avatars/upload/* /phpBB/store/* /phpBB/vendor -/tests/phpbb_unit_tests.sqlite2 +/tests/phpbb_unit_tests.sqlite* /tests/test_config*.php /tests/tmp/* diff --git a/.travis.yml b/.travis.yml index 88c902cd4d..3d79d156de 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,23 +14,13 @@ services: - redis-server install: - - sh -c "if [ '$DB' = 'mariadb' ]; then travis/setup-mariadb.sh; fi" - - sh -c "if [ '$TRAVIS_PHP_VERSION' != 'hhvm' ]; then travis/setup-php-extensions.sh; fi" - - sh -c "if [ `php -r "echo (int) version_compare(PHP_VERSION, '5.3.19', '>=');"` = "1" ]; then travis/setup-webserver.sh; fi" - - cd phpBB - - php ../composer.phar install --dev --no-interaction --prefer-source - - cd .. + - travis/setup-phpbb.sh $DB $TRAVIS_PHP_VERSION before_script: - - sh -c "if [ '$DB' = 'postgres' ]; then psql -c 'DROP DATABASE IF EXISTS phpbb_tests;' -U postgres; fi" - - sh -c "if [ '$DB' = 'postgres' ]; then psql -c 'create database phpbb_tests;' -U postgres; fi" - - sh -c "if [ '$TRAVIS_PHP_VERSION' = '5.3' -a '$DB' = 'mysql' ]; then mysql -e 'SET GLOBAL storage_engine=MyISAM;'; fi" - - sh -c "if [ '$DB' = 'mysql' -o '$DB' = 'mariadb' ]; then mysql -e 'create database IF NOT EXISTS phpbb_tests;'; fi" + - travis/setup-database.sh $DB $TRAVIS_PHP_VERSION script: - - cd build - - sh -c "if [ '$TRAVIS_PHP_VERSION' = '5.5' -a '$DB' = 'mysql' ]; then ../phpBB/vendor/bin/phing sniff; fi" - - cd .. + - travis/phing-sniff.sh $DB $TRAVIS_PHP_VERSION - phpBB/vendor/bin/phpunit --configuration travis/phpunit-$DB-travis.xml - sh -c "if [ '$TRAVIS_PHP_VERSION' = '5.5' -a '$DB' = 'mysql' -a '$TRAVIS_PULL_REQUEST' != 'false' ]; then git-tools/commit-msg-hook-range.sh origin/$TRAVIS_BRANCH..FETCH_HEAD; fi" @@ -40,5 +30,8 @@ matrix: env: DB=mariadb - php: 5.4 env: DB=postgres + - php: 5.4 + env: DB=sqlite3 allow_failures: - php: hhvm + fast_finish: true diff --git a/phpBB/.htaccess b/phpBB/.htaccess index 6f33916775..1ae74ed825 100644 --- a/phpBB/.htaccess +++ b/phpBB/.htaccess @@ -26,12 +26,50 @@ RewriteRule ^(.*)$ app.php [QSA,L] #Options +FollowSymLinks </IfModule> -<Files "config.php"> -Order Allow,Deny -Deny from All -</Files> - -<Files "common.php"> -Order Allow,Deny -Deny from All -</Files> +# With Apache 2.4 the "Order, Deny" syntax has been deprecated and moved from +# module mod_authz_host to a new module called mod_access_compat (which may be +# disabled) and a new "Require" syntax has been introduced to mod_authz_host. +# We could just conditionally provide both versions, but unfortunately Apache +# does not explicitly tell us its version if the module mod_version is not +# available. In this case, we check for the availability of module +# mod_authz_core (which should be on 2.4 or higher only) as a best guess. +<IfModule mod_version.c> + <IfVersion < 2.4> + <Files "config.php"> + Order Allow,Deny + Deny from All + </Files> + <Files "common.php"> + Order Allow,Deny + Deny from All + </Files> + </IfVersion> + <IfVersion >= 2.4> + <Files "config.php"> + Require all denied + </Files> + <Files "common.php"> + Require all denied + </Files> + </IfVersion> +</IfModule> +<IfModule !mod_version.c> + <IfModule !mod_authz_core.c> + <Files "config.php"> + Order Allow,Deny + Deny from All + </Files> + <Files "common.php"> + Order Allow,Deny + Deny from All + </Files> + </IfModule> + <IfModule mod_authz_core.c> + <Files "config.php"> + Require all denied + </Files> + <Files "common.php"> + Require all denied + </Files> + </IfModule> +</IfModule> diff --git a/phpBB/assets/javascript/core.js b/phpBB/assets/javascript/core.js index 4920a1167f..f461d5a175 100644 --- a/phpBB/assets/javascript/core.js +++ b/phpBB/assets/javascript/core.js @@ -249,7 +249,16 @@ phpbb.ajaxify = function(options) { callback = options.callback, overlay = (typeof options.overlay !== 'undefined') ? options.overlay : true, isForm = elements.is('form'), - eventName = isForm ? 'submit' : 'click'; + isText = elements.is('input[type="text"], textarea'), + eventName; + + if (isForm) { + eventName = 'submit'; + } else if (isText) { + eventName = 'keyup'; + } else { + eventName = 'click'; + } elements.bind(eventName, function(event) { var action, method, data, submit, that = this, $this = $(this); @@ -349,6 +358,7 @@ 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 runFilter = (typeof options.filter === 'function'); + var data = {}; if (isForm) { action = $this.attr('action').replace('&', '&'); @@ -362,33 +372,41 @@ phpbb.ajaxify = function(options) { value: submit.val() }); } + } else if (isText) { + var name = ($this.attr('data-name') !== undefined) ? $this.attr('data-name') : this['name']; + action = $this.attr('data-url').replace('&', '&'); + data[name] = this.value; + method = 'POST'; } else { action = this.href; data = null; method = 'GET'; } + var sendRequest = function() { + if (overlay && (typeof $this.attr('data-overlay') === 'undefined' || $this.attr('data-overlay') === 'true')) { + phpbb.loadingIndicator(); + } + + var request = $.ajax({ + url: action, + type: method, + data: data, + success: returnHandler, + error: errorHandler + }); + request.always(function() { + loadingIndicator.fadeOut(phpbb.alertTime); + }); + }; + // If filter function returns false, cancel the AJAX functionality, // and return true (meaning that the HTTP request will be sent normally). - if (runFilter && !options.filter.call(this, data)) { + if (runFilter && !options.filter.call(this, data, event, sendRequest)) { return; } - if (overlay && (typeof $this.attr('data-overlay') === 'undefined' || $this.attr('data-overlay') === 'true')) { - phpbb.loadingIndicator(); - } - - var request = $.ajax({ - url: action, - type: method, - data: data, - success: returnHandler, - error: errorHandler - }); - request.always(function() { - loadingIndicator.fadeOut(phpbb.alertTime); - }); - + sendRequest(); event.preventDefault(); }); @@ -404,6 +422,278 @@ phpbb.ajaxify = function(options) { return this; }; +phpbb.search = {cache: {data: []}, tpl: [], container: []}; + +/** + * Get cached search data. + * + * @param string id Search ID. + * @return bool|object. Cached data object. Returns false if no data exists. + */ +phpbb.search.cache.get = function(id) { + if (this.data[id]) { + return this.data[id]; + } + return false; +}; + +/** + * Set search cache data value. + * + * @param string id Search ID. + * @param string key Data key. + * @param string value Data value. + * + * @return undefined + */ +phpbb.search.cache.set = function(id, key, value) { + if (!this.data[id]) { + this.data[id] = {results: []}; + } + this.data[id][key] = value; +}; + +/** + * Cache search result. + * + * @param string id Search ID. + * @param string keyword Keyword. + * @param array results Search results. + * + * @return undefined + */ +phpbb.search.cache.setResults = function(id, keyword, value) { + this.data[id]['results'][keyword] = value; +}; + +/** + * Trim spaces from keyword and lower its case. + * + * @param string keyword Search keyword to clean. + * @return string Cleaned string. + */ +phpbb.search.cleanKeyword = function(keyword) { + return $.trim(keyword).toLowerCase(); +}; + +/** + * Get clean version of search keyword. If textarea supports several keywords + * (one per line), it fetches the current keyword based on the caret position. + * + * @param jQuery el Search input|textarea. + * @param string keyword Input|textarea value. + * @param bool multiline Whether textarea supports multiple search keywords. + * + * @return string Clean string. + */ +phpbb.search.getKeyword = function(el, keyword, multiline) { + if (multiline) { + var line = phpbb.search.getKeywordLine(el); + keyword = keyword.split("\n").splice(line, 1); + } + return phpbb.search.cleanKeyword(keyword); +}; + +/** + * Get the textarea line number on which the keyword resides - for textareas + * that support multiple keywords (one per line). + * + * @param jQuery el Search textarea. + * @return int + */ +phpbb.search.getKeywordLine = function (el) { + return el.val().substr(0, el.get(0).selectionStart).split("\n").length - 1; +}; + +/** + * Set the value on the input|textarea. If textarea supports multiple + * keywords, only the active keyword is replaced. + * + * @param jQuery el Search input|textarea. + * @param string value Value to set. + * @param bool multiline Whether textarea supports multiple search keywords. + * + * @return undefined + */ +phpbb.search.setValue = function(el, value, multiline) { + if (multiline) { + var line = phpbb.search.getKeywordLine(el), + lines = el.val().split("\n"); + lines[line] = value; + value = lines.join("\n"); + } + el.val(value); +}; + +/** + * Sets the onclick event to set the value on the input|textarea to the selected search result. + * + * @param jQuery el Search input|textarea. + * @param object value Result object. + * @param object container jQuery object for the search container. + * + * @return undefined + */ +phpbb.search.setValueOnClick = function(el, value, row, container) { + row.click(function() { + phpbb.search.setValue(el, value.result, el.attr('data-multiline')); + container.hide(); + }); +}; + +/** + * Runs before the AJAX search request is sent and determines whether + * there is a need to contact the server. If there are cached results + * already, those are displayed instead. Executes the AJAX request function + * itself due to the need to use a timeout to limit the number of requests. + * + * @param array data Data to be sent to the server. + * @param object event Onkeyup event object. + * @param function sendRequest Function to execute AJAX request. + * + * @return bool Returns false. + */ +phpbb.search.filter = function(data, event, sendRequest) { + var el = $(this), + dataName = (el.attr('data-name') !== undefined) ? el.attr('data-name') : el.attr('name'), + minLength = parseInt(el.attr('data-min-length')), + searchID = el.attr('data-results'), + keyword = phpbb.search.getKeyword(el, data[dataName], el.attr('data-multiline')), + cache = phpbb.search.cache.get(searchID), + proceed = true; + data[dataName] = keyword; + + if (cache['timeout']) { + clearTimeout(cache['timeout']); + } + + var timeout = setTimeout(function() { + // Check min length and existence of cache. + if (minLength > keyword.length) { + proceed = false; + } else if (cache['last_search']) { + // Has the keyword actually changed? + if (cache['last_search'] === keyword) { + proceed = false; + } else { + // Do we already have results for this? + if (cache['results'][keyword]) { + var response = {keyword: keyword, results: cache['results'][keyword]}; + phpbb.search.handleResponse(response, el, true); + proceed = false; + } + + // If the previous search didn't yield results and the string only had characters added to it, + // then we won't bother sending a request. + if (keyword.indexOf(cache['last_search']) === 0 && cache['results'][cache['last_search']].length === 0) { + phpbb.search.cache.set(searchID, 'last_search', keyword); + phpbb.search.cache.setResults(searchID, keyword, []); + proceed = false; + } + } + } + + if (proceed) { + sendRequest.call(this); + } + }, 350); + phpbb.search.cache.set(searchID, 'timeout', timeout); + + return false; +}; + +/** + * Handle search result response. + * + * @param object res Data received from server. + * @param jQuery el Search input|textarea. + * @param bool fromCache Whether the results are from the cache. + * @param function callback Optional callback to run when assigning each search result. + * + * @return undefined + */ +phpbb.search.handleResponse = function(res, el, fromCache, callback) { + if (typeof res !== 'object') { + return; + } + + var searchID = el.attr('data-results'), + container = $(searchID); + + if (this.cache.get(searchID)['callback']) { + callback = this.cache.get(searchID)['callback']; + } else if (typeof callback === 'function') { + this.cache.set(searchID, 'callback', callback); + } + + if (!fromCache) { + this.cache.setResults(searchID, res.keyword, res.results); + } + + this.cache.set(searchID, 'last_search', res.keyword); + this.showResults(res.results, el, container, callback); +}; + +/** + * Show search results. + * + * @param array results Search results. + * @param jQuery el Search input|textarea. + * @param jQuery container Search results container element. + * @param function callback Optional callback to run when assigning each search result. + * + * @return undefined + */ +phpbb.search.showResults = function(results, el, container, callback) { + var resultContainer = $('.search-results', container); + this.clearResults(resultContainer); + + if (!results.length) { + container.hide(); + return; + } + + var searchID = container.attr('id'), + tpl, + row; + + if (!this.tpl[searchID]) { + tpl = $('.search-result-tpl', container); + this.tpl[searchID] = tpl.clone().removeClass('search-result-tpl'); + tpl.remove(); + } + tpl = this.tpl[searchID]; + + $.each(results, function(i, item) { + row = tpl.clone(); + row.find('.search-result').html(item.display); + + if (typeof callback === 'function') { + callback.call(this, el, item, row, container); + } + row.appendTo(resultContainer).show(); + }); + container.show(); +}; + +/** + * Clear search results. + * + * @param jQuery container Search results container. + * @return undefined + */ +phpbb.search.clearResults = function(container) { + container.children(':not(.search-result-tpl)').remove(); +}; + +$('#phpbb').click(function(e) { + var target = $(e.target); + + if (!target.is('.live-search') && !target.parents().is('.live-search')) { + $('.live-search').hide(); + } +}); + /** * Hide the optgroups that are not the selected timezone * @@ -543,6 +833,12 @@ phpbb.addAjaxCallback = function(id, callback) { return this; }; +/** + * This callback handles live member searches. + */ +phpbb.addAjaxCallback('member_search', function(res) { + phpbb.search.handleResponse(res, $(this), false, phpbb.getFunctionByName('phpbb.search.setValueOnClick')); +}); /** * This callback alternates text - it replaces the current text with the text in @@ -918,9 +1214,10 @@ phpbb.toggleDropdown = function() { // Check dimensions when showing dropdown // !visible because variable shows state of dropdown before it was toggled if (!visible) { + var windowWidth = $(window).width(); + options.dropdown.find('.dropdown-contents').each(function() { - var $this = $(this), - windowWidth = $(window).width(); + var $this = $(this); $this.css({ marginLeft: 0, @@ -938,6 +1235,13 @@ phpbb.toggleDropdown = function() { $this.css('margin-left', (windowWidth - offset - width - 2) + 'px'); } }); + var freeSpace = parent.offset().left - 4; + + if (direction == 'left') { + options.dropdown.css('margin-left', '-' + freeSpace + 'px'); + } else { + options.dropdown.css('margin-right', '-' + (windowWidth + freeSpace) + 'px'); + } } // Prevent event propagation @@ -1104,6 +1408,24 @@ phpbb.toggleDisplay = function(id, action, type) { } /** +* Get function from name. +* Based on http://stackoverflow.com/a/359910 +* +* @param string functionName Function to get. +* @return function +*/ +phpbb.getFunctionByName = function (functionName) { + var namespaces = functionName.split('.'), + func = namespaces.pop(), + context = window; + + for (var i = 0; i < namespaces.length; i++) { + context = context[namespaces[i]]; + } + return context[func]; +}; + +/** * Apply code editor to all textarea elements with data-bbcode attribute */ $(document).ready(function() { diff --git a/phpBB/bin/phpbbcli.php b/phpBB/bin/phpbbcli.php index 49f4ca13e7..02d6b88943 100755 --- a/phpBB/bin/phpbbcli.php +++ b/phpBB/bin/phpbbcli.php @@ -22,6 +22,7 @@ require($phpbb_root_path . 'config.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); require($phpbb_root_path . 'includes/functions.' . $phpEx); require($phpbb_root_path . 'includes/functions_container.' . $phpEx); +require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx); require($phpbb_root_path . 'phpbb/class_loader.' . $phpEx); $phpbb_class_loader = new \phpbb\class_loader('phpbb\\', "{$phpbb_root_path}phpbb/", $phpEx); @@ -30,6 +31,8 @@ $phpbb_class_loader_ext = new \phpbb\class_loader('\\', "{$phpbb_root_path}ext/" $phpbb_class_loader_ext->register(); $phpbb_container = phpbb_create_update_container($phpbb_root_path, $phpEx, "$phpbb_root_path/config"); +$phpbb_container->get('request')->enable_super_globals(); +require($phpbb_root_path . 'includes/compatibility_globals.' . $phpEx); $application = new \phpbb\console\application('phpBB Console', PHPBB_VERSION); $application->register_container_commands($phpbb_container); diff --git a/phpBB/common.php b/phpBB/common.php index 12dbe5a62c..4ad669a021 100644 --- a/phpBB/common.php +++ b/phpBB/common.php @@ -96,34 +96,7 @@ $phpbb_container = phpbb_create_default_container($phpbb_root_path, $phpEx); $phpbb_class_loader->set_cache($phpbb_container->get('cache.driver')); $phpbb_class_loader_ext->set_cache($phpbb_container->get('cache.driver')); -// set up caching -$cache = $phpbb_container->get('cache'); - -// Instantiate some basic classes -$phpbb_dispatcher = $phpbb_container->get('dispatcher'); -$request = $phpbb_container->get('request'); -$user = $phpbb_container->get('user'); -$auth = $phpbb_container->get('auth'); -$db = $phpbb_container->get('dbal.conn'); - -// make sure request_var uses this request instance -request_var('', 0, false, false, $request); // "dependency injection" for a function - -// Grab global variables, re-cache if necessary -$config = $phpbb_container->get('config'); -set_config(null, null, null, $config); -set_config_count(null, null, null, $config); - -$phpbb_log = $phpbb_container->get('log'); -$symfony_request = $phpbb_container->get('symfony_request'); -$phpbb_filesystem = $phpbb_container->get('filesystem'); -$phpbb_path_helper = $phpbb_container->get('path_helper'); - -// load extensions -$phpbb_extension_manager = $phpbb_container->get('ext.manager'); -$phpbb_subscriber_loader = $phpbb_container->get('event.subscriber_loader'); - -$template = $phpbb_container->get('template'); +require($phpbb_root_path . 'includes/compatibility_globals.' . $phpEx); // Add own hook handler require($phpbb_root_path . 'includes/hooks/index.' . $phpEx); diff --git a/phpBB/composer.json b/phpBB/composer.json index f005fff805..a55733b3c0 100644 --- a/phpBB/composer.json +++ b/phpBB/composer.json @@ -16,8 +16,8 @@ }, "require-dev": { "fabpot/goutte": "1.0.*", - "phpunit/dbunit": "1.2.*", - "phpunit/phpunit": "3.7.*", + "phpunit/dbunit": "1.3.*", + "phpunit/phpunit": "4.1.*", "phing/phing": "2.4.*", "squizlabs/php_codesniffer": "1.*" } diff --git a/phpBB/composer.lock b/phpBB/composer.lock index ee83dee047..9e0bcf9771 100644 --- a/phpBB/composer.lock +++ b/phpBB/composer.lock @@ -3,7 +3,7 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "9b683acbc766a345d90de958db4e7f48", + "hash": "194c86e9ae52700a8f6c1b10d7b2e4d0", "packages": [ { "name": "lusitanian/oauth", @@ -88,7 +88,7 @@ "Psr\\Log\\": "" } }, - "notification-url": "http://packagist.org/downloads/", + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -213,17 +213,17 @@ }, { "name": "symfony/debug", - "version": "v2.3.4", + "version": "v2.4.4", "target-dir": "Symfony/Component/Debug", "source": { "type": "git", "url": "https://github.com/symfony/Debug.git", - "reference": "729f6d19cfc401c4942e43fcc1059103bd6df130" + "reference": "6a8eb9aba50595014fef52d6b4d99b31dfaa6f02" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Debug/zipball/729f6d19cfc401c4942e43fcc1059103bd6df130", - "reference": "729f6d19cfc401c4942e43fcc1059103bd6df130", + "url": "https://api.github.com/repos/symfony/Debug/zipball/6a8eb9aba50595014fef52d6b4d99b31dfaa6f02", + "reference": "6a8eb9aba50595014fef52d6b4d99b31dfaa6f02", "shasum": "" }, "require": { @@ -234,14 +234,13 @@ "symfony/http-kernel": "~2.1" }, "suggest": { - "symfony/class-loader": "", "symfony/http-foundation": "", "symfony/http-kernel": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3-dev" + "dev-master": "2.4-dev" } }, "autoload": { @@ -267,7 +266,7 @@ ], "description": "Symfony Debug Component", "homepage": "http://symfony.com", - "time": "2013-08-08 14:16:10" + "time": "2014-04-16 10:34:42" }, { "name": "symfony/dependency-injection", @@ -385,17 +384,17 @@ }, { "name": "symfony/filesystem", - "version": "v2.3.4", + "version": "v2.4.4", "target-dir": "Symfony/Component/Filesystem", "source": { "type": "git", "url": "https://github.com/symfony/Filesystem.git", - "reference": "87acbbef6d35ba649f96f09cc572c45119b360c3" + "reference": "a3af8294bcce4a7c1b2892363b0c9d8109affad4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Filesystem/zipball/87acbbef6d35ba649f96f09cc572c45119b360c3", - "reference": "87acbbef6d35ba649f96f09cc572c45119b360c3", + "url": "https://api.github.com/repos/symfony/Filesystem/zipball/a3af8294bcce4a7c1b2892363b0c9d8109affad4", + "reference": "a3af8294bcce4a7c1b2892363b0c9d8109affad4", "shasum": "" }, "require": { @@ -404,7 +403,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3-dev" + "dev-master": "2.4-dev" } }, "autoload": { @@ -430,30 +429,33 @@ ], "description": "Symfony Filesystem Component", "homepage": "http://symfony.com", - "time": "2013-07-21 12:12:18" + "time": "2014-04-16 10:34:31" }, { "name": "symfony/http-foundation", - "version": "v2.3.4", + "version": "v2.4.4", "target-dir": "Symfony/Component/HttpFoundation", "source": { "type": "git", "url": "https://github.com/symfony/HttpFoundation.git", - "reference": "fdf130fe65457aedbc4639a22f4ef9d3be5c002c" + "reference": "22c4dee84271ad0cd08d19f26d89f2878e11159b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/fdf130fe65457aedbc4639a22f4ef9d3be5c002c", - "reference": "fdf130fe65457aedbc4639a22f4ef9d3be5c002c", + "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/22c4dee84271ad0cd08d19f26d89f2878e11159b", + "reference": "22c4dee84271ad0cd08d19f26d89f2878e11159b", "shasum": "" }, "require": { "php": ">=5.3.3" }, + "require-dev": { + "symfony/expression-language": "~2.4" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3-dev" + "dev-master": "2.4-dev" } }, "autoload": { @@ -482,7 +484,7 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "http://symfony.com", - "time": "2013-08-26 05:49:51" + "time": "2014-04-18 21:02:05" }, { "name": "symfony/http-kernel", @@ -694,18 +696,21 @@ "Twig_": "lib/" } }, - "notification-url": "http://packagist.org/downloads/", + "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" }, { "name": "Armin Ronacher", - "email": "armin.ronacher@active-4.com" + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" } ], "description": "Twig, the flexible, fast, and secure template language for PHP", @@ -1027,31 +1032,32 @@ }, { "name": "phpunit/dbunit", - "version": "1.2.3", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/dbunit.git", - "reference": "8386782a2d55153e44a06eb1a9d13d6ed35d9c2d" + "reference": "a5891b7a9c4f21587a51f9bc4e8f7042b741b480" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/dbunit/zipball/8386782a2d55153e44a06eb1a9d13d6ed35d9c2d", - "reference": "8386782a2d55153e44a06eb1a9d13d6ed35d9c2d", + "url": "https://api.github.com/repos/sebastianbergmann/dbunit/zipball/a5891b7a9c4f21587a51f9bc4e8f7042b741b480", + "reference": "a5891b7a9c4f21587a51f9bc4e8f7042b741b480", "shasum": "" }, "require": { "ext-pdo": "*", "ext-simplexml": "*", "php": ">=5.3.3", - "phpunit/phpunit": ">=3.7.0@stable" + "phpunit/phpunit": ">=3.7.0@stable", + "symfony/yaml": ">=2.1.0" }, "bin": [ - "dbunit.php" + "composer/bin/dbunit" ], "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "1.3.x-dev" } }, "autoload": { @@ -1081,44 +1087,48 @@ "testing", "xunit" ], - "time": "2013-03-01 11:50:46" + "time": "2014-03-26 11:25:06" }, { "name": "phpunit/php-code-coverage", - "version": "1.2.13", + "version": "2.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "466e7cd2554b4e264c9e3f31216d25ac0e5f3d94" + "reference": "bccecf50645068b44f49a84009e2a0499a500b99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/466e7cd2554b4e264c9e3f31216d25ac0e5f3d94", - "reference": "466e7cd2554b4e264c9e3f31216d25ac0e5f3d94", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/bccecf50645068b44f49a84009e2a0499a500b99", + "reference": "bccecf50645068b44f49a84009e2a0499a500b99", "shasum": "" }, "require": { "php": ">=5.3.3", - "phpunit/php-file-iterator": ">=1.3.0@stable", - "phpunit/php-text-template": ">=1.1.1@stable", - "phpunit/php-token-stream": ">=1.1.3@stable" + "phpunit/php-file-iterator": "~1.3.1", + "phpunit/php-text-template": "~1.2.0", + "phpunit/php-token-stream": "~1.2.2", + "sebastian/environment": "~1.0.0", + "sebastian/version": "~1.0.3" }, "require-dev": { - "phpunit/phpunit": "3.7.*@dev" + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4.0.14" }, "suggest": { "ext-dom": "*", - "ext-xdebug": ">=2.0.5" + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { "classmap": [ - "PHP/" + "src/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1142,20 +1152,20 @@ "testing", "xunit" ], - "time": "2013-09-10 08:14:32" + "time": "2014-04-30 09:01:21" }, { "name": "phpunit/php-file-iterator", - "version": "1.3.3", + "version": "1.3.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "16a78140ed2fc01b945cfa539665fadc6a038029" + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/16a78140ed2fc01b945cfa539665fadc6a038029", - "reference": "16a78140ed2fc01b945cfa539665fadc6a038029", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", "shasum": "" }, "require": { @@ -1182,25 +1192,25 @@ } ], "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "http://www.phpunit.de/", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", "keywords": [ "filesystem", "iterator" ], - "time": "2012-10-11 11:44:38" + "time": "2013-10-10 15:34:57" }, { "name": "phpunit/php-text-template", - "version": "1.1.4", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "5180896f51c5b3648ac946b05f9ec02be78a0b23" + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5180896f51c5b3648ac946b05f9ec02be78a0b23", - "reference": "5180896f51c5b3648ac946b05f9ec02be78a0b23", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", "shasum": "" }, "require": { @@ -1231,7 +1241,7 @@ "keywords": [ "template" ], - "time": "2012-10-31 18:15:28" + "time": "2014-01-30 17:20:04" }, { "name": "phpunit/php-timer", @@ -1279,16 +1289,16 @@ }, { "name": "phpunit/php-token-stream", - "version": "1.2.1", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "5220af2a7929aa35cf663d97c89ad3d50cf5fa3e" + "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/5220af2a7929aa35cf663d97c89ad3d50cf5fa3e", - "reference": "5220af2a7929aa35cf663d97c89ad3d50cf5fa3e", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/ad4e1e23ae01b483c16f600ff1bebec184588e32", + "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32", "shasum": "" }, "require": { @@ -1325,56 +1335,56 @@ "keywords": [ "tokenizer" ], - "time": "2013-09-13 04:58:23" + "time": "2014-03-03 05:10:30" }, { "name": "phpunit/phpunit", - "version": "3.7.24", + "version": "4.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "af7b77ccb5c64458bdfca95665d29558d1df7d08" + "reference": "efb1b1334605594417a3bd466477772d06d460a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/af7b77ccb5c64458bdfca95665d29558d1df7d08", - "reference": "af7b77ccb5c64458bdfca95665d29558d1df7d08", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/efb1b1334605594417a3bd466477772d06d460a8", + "reference": "efb1b1334605594417a3bd466477772d06d460a8", "shasum": "" }, "require": { "ext-dom": "*", + "ext-json": "*", "ext-pcre": "*", "ext-reflection": "*", "ext-spl": "*", "php": ">=5.3.3", - "phpunit/php-code-coverage": "~1.2.1", - "phpunit/php-file-iterator": ">=1.3.1", - "phpunit/php-text-template": ">=1.1.1", - "phpunit/php-timer": ">=1.0.4", - "phpunit/phpunit-mock-objects": "~1.2.0", + "phpunit/php-code-coverage": "~2.0", + "phpunit/php-file-iterator": "~1.3.1", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "~1.0.2", + "phpunit/phpunit-mock-objects": "~2.1", + "sebastian/comparator": "~1.0", + "sebastian/diff": "~1.1", + "sebastian/environment": "~1.0", + "sebastian/exporter": "~1.0", + "sebastian/version": "~1.0", "symfony/yaml": "~2.0" }, - "require-dev": { - "pear-pear/pear": "1.9.4" - }, "suggest": { - "ext-json": "*", - "ext-simplexml": "*", - "ext-tokenizer": "*", - "phpunit/php-invoker": ">=1.1.0,<1.2.0" + "phpunit/php-invoker": "~1.1" }, "bin": [ - "composer/bin/phpunit" + "phpunit" ], "type": "library", "extra": { "branch-alias": { - "dev-master": "3.7.x-dev" + "dev-master": "4.1.x-dev" } }, "autoload": { "classmap": [ - "PHPUnit/" + "src/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1399,33 +1409,41 @@ "testing", "xunit" ], - "time": "2013-08-09 06:58:24" + "time": "2014-05-02 07:13:40" }, { "name": "phpunit/phpunit-mock-objects", - "version": "1.2.3", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875" + "reference": "da0eb04d8ee95ec2898187e407e519c118d3d27c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/5794e3c5c5ba0fb037b11d8151add2a07fa82875", - "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/da0eb04d8ee95ec2898187e407e519c118d3d27c", + "reference": "da0eb04d8ee95ec2898187e407e519c118d3d27c", "shasum": "" }, "require": { "php": ">=5.3.3", - "phpunit/php-text-template": ">=1.1.1@stable" + "phpunit/php-text-template": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.1" }, "suggest": { "ext-soap": "*" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, "autoload": { "classmap": [ - "PHPUnit/" + "src/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1448,7 +1466,274 @@ "mock", "xunit" ], - "time": "2013-01-13 10:24:48" + "time": "2014-05-02 07:04:11" + }, + { + "name": "sebastian/comparator", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "f7069ee51fa9fb6c038e16a9d0e3439f5449dcf2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/f7069ee51fa9fb6c038e16a9d0e3439f5449dcf2", + "reference": "f7069ee51fa9fb6c038e16a9d0e3439f5449dcf2", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.1", + "sebastian/exporter": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2014-05-02 07:05:58" + }, + { + "name": "sebastian/diff", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "1e091702a5a38e6b4c1ba9ca816e3dd343df2e2d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/1e091702a5a38e6b4c1ba9ca816e3dd343df2e2d", + "reference": "1e091702a5a38e6b4c1ba9ca816e3dd343df2e2d", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "http://www.github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2013-08-03 16:46:33" + }, + { + "name": "sebastian/environment", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "79517609ec01139cd7e9fded0dd7ce08c952ef6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/79517609ec01139cd7e9fded0dd7ce08c952ef6a", + "reference": "79517609ec01139cd7e9fded0dd7ce08c952ef6a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "4.0.*@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2014-02-18 16:17:19" + }, + { + "name": "sebastian/exporter", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "1f9a98e6f5dfe0524cb8c6166f7c82f3e9ae1529" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/1f9a98e6f5dfe0524cb8c6166f7c82f3e9ae1529", + "reference": "1f9a98e6f5dfe0524cb8c6166f7c82f3e9ae1529", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "4.0.*@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2014-02-16 08:26:31" + }, + { + "name": "sebastian/version", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43", + "reference": "b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2014-03-07 15:35:33" }, { "name": "squizlabs/php_codesniffer", diff --git a/phpBB/config/console.yml b/phpBB/config/console.yml index a4aae75e40..3d57c257dd 100644 --- a/phpBB/config/console.yml +++ b/phpBB/config/console.yml @@ -34,6 +34,18 @@ services: tags: - { name: console.command } + console.command.db.migrate: + class: phpbb\console\command\db\migrate + arguments: + - @migrator + - @ext.manager + - @config + - @cache + - @log + - @user + tags: + - { name: console.command } + console.command.extension.disable: class: phpbb\console\command\extension\disable arguments: diff --git a/phpBB/config/profilefields.yml b/phpBB/config/profilefields.yml index d12a1f8a37..00f025e141 100644 --- a/phpBB/config/profilefields.yml +++ b/phpBB/config/profilefields.yml @@ -4,6 +4,7 @@ services: arguments: - @auth - @dbal.conn + - @dispatcher - @request - @template - @profilefields.type_collection diff --git a/phpBB/develop/add_permissions.php b/phpBB/develop/add_permissions.php index 449d931507..688e228729 100644 --- a/phpBB/develop/add_permissions.php +++ b/phpBB/develop/add_permissions.php @@ -376,6 +376,7 @@ function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting) case 'mssql': case 'sqlite': + case 'sqlite3': $sql = implode(' UNION ALL ', preg_replace('#^(.*?)$#', 'SELECT \1', $sql_subary)); break; diff --git a/phpBB/develop/create_schema_files.php b/phpBB/develop/create_schema_files.php index 9ab8bd193f..d89de2cee3 100644 --- a/phpBB/develop/create_schema_files.php +++ b/phpBB/develop/create_schema_files.php @@ -70,6 +70,7 @@ foreach ($supported_dbms as $dbms) case 'mysql_41': case 'firebird': case 'sqlite': + case 'sqlite3': fwrite($fp, "# DO NOT EDIT THIS FILE, IT IS GENERATED\n"); fwrite($fp, "#\n"); fwrite($fp, "# To change the contents of this file, edit\n"); diff --git a/phpBB/docs/AUTHORS b/phpBB/docs/AUTHORS index 5ca52c19c0..29ee72caa3 100644 --- a/phpBB/docs/AUTHORS +++ b/phpBB/docs/AUTHORS @@ -26,6 +26,7 @@ phpBB Developers: bantu (Andreas Fischer) dhruv.goel92 (Dhruv Goel) EXreaction (Nathan Guse) imkingdavid (David King) + marc1706 (Marc Alexander) nickvergessen (Joas Schilling) prototech (Cesar Gallegos) diff --git a/phpBB/docs/INSTALL.html b/phpBB/docs/INSTALL.html index 01eeea6540..0b5d06c191 100644 --- a/phpBB/docs/INSTALL.html +++ b/phpBB/docs/INSTALL.html @@ -134,7 +134,8 @@ <li>MySQL 3.23 or above (MySQLi supported)</li> <li>MariaDB 5.1 or above</li> <li>PostgreSQL 8.3+</li> - <li>SQLite 2.8.2+ (SQLite 3 is not supported)</li> + <li>SQLite 2.8.2+</li> + <li>SQLite 3.6.15+</li> <li>Firebird 2.1+</li> <li>MS SQL Server 2000 or above (directly or via ODBC or the native adapter)</li> <li>Oracle</li> diff --git a/phpBB/docs/events.md b/phpBB/docs/events.md index 67fa96ffbc..c57b2cceab 100644 --- a/phpBB/docs/events.md +++ b/phpBB/docs/events.md @@ -186,6 +186,54 @@ forumlist_body_last_row_after * Since: 3.1.0-b2 * Purpose: Add content after the very last row of the forum list. +index_body_block_birthday_append +=== +* Locations: + + styles/prosilver/template/index_body.html + + styles/subsilver2/template/index_body.html +* Since: 3.1.0-b3 +* Purpose: Append content to the birthday list on the Board index + +index_body_block_birthday_prepend +=== +* Locations: + + styles/prosilver/template/index_body.html + + styles/subsilver2/template/index_body.html +* Since: 3.1.0-b3 +* Purpose: Prepend content to the birthday list on the Board index + +index_body_block_online_append +=== +* Locations: + + styles/prosilver/template/index_body.html + + styles/subsilver2/template/index_body.html +* Since: 3.1.0-b3 +* Purpose: Append content to the online list on the Board index + +index_body_block_online_prepend +=== +* Locations: + + styles/prosilver/template/index_body.html + + styles/subsilver2/template/index_body.html +* Since: 3.1.0-b3 +* Purpose: Prepend content to the online list on the Board index + +index_body_block_stats_append +=== +* Locations: + + styles/prosilver/template/index_body.html + + styles/subsilver2/template/index_body.html +* Since: 3.1.0-b3 +* Purpose: Append content to the statistics list on the Board index + +index_body_block_stats_prepend +=== +* Locations: + + styles/prosilver/template/index_body.html + + styles/subsilver2/template/index_body.html +* Since: 3.1.0-b3 +* Purpose: Prepend content to the statistics list on the Board index + index_body_linklist_after === * Locations: @@ -260,6 +308,14 @@ memberlist_view_content_append * Since: 3.1.0-b2 * Purpose: Add custom content to the user profile view after the main content +memberlist_view_content_prepend +=== +* Locations: + + styles/prosilver/template/memberlist_view.html + + styles/subsilver2/template/memberlist_view.html +* Since: 3.1.0-b3 +* Purpose: Add custom content to the user profile view before the main content + memberlist_view_user_statistics_after === * Locations: @@ -403,6 +459,22 @@ overall_header_navigation_prepend * Since: 3.1.0-a1 * Purpose: Add links before the navigation links in the header +overall_header_navlink_append +=== +* Locations: + + styles/prosilver/template/navbar_header.html + + styles/subsilver2/template/breadcrumbs.html +* Since: 3.1.0-b3 +* Purpose: Add content after each individual navlink (breadcrumb) + +overall_header_navlink_prepend +=== +* Locations: + + styles/prosilver/template/navbar_header.html + + styles/subsilver2/template/breadcrumbs.html +* Since: 3.1.0-b3 +* Purpose: Add content before each individual navlink (breadcrumb) + overall_header_page_body_before === * Locations: @@ -499,6 +571,36 @@ quickreply_editor_message_before * Since: 3.1.0-a4 * Purpose: Add content before the quick reply textbox +search_results_post_after +=== +* Locations: + + styles/prosilver/template/search_results.html + + styles/subsilver2/template/search_results.html +* Since: 3.1.0-b3 +* Purpose: Add data after search result posts + +search_results_post_before +=== +* Locations: + + styles/prosilver/template/search_results.html + + styles/subsilver2/template/search_results.html +* Since: 3.1.0-b3 +* Purpose: Add data before search result posts + +search_results_postprofile_after +=== +* Locations: + + styles/prosilver/template/search_results.html +* Since: 3.1.0-b3 +* Purpose: Add content after the post author and stats in search results (posts view mode) + +search_results_postprofile_before +=== +* Locations: + + styles/prosilver/template/search_results.html +* Since: 3.1.0-b3 +* Purpose: Add content directly before the post author in search results (posts view mode) + simple_footer_after === * Locations: @@ -659,6 +761,22 @@ ucp_friend_list_after * Since: 3.1.0-a4 * Purpose: Add optional elements after list of friends in UCP +viewforum_forum_name_append +=== +* Locations: + + styles/prosilver/template/viewforum_body.html + + styles/subsilver2/template/viewforum_body.html +* Since: 3.1.0-b3 +* Purpose: Add content directly after the forum name link on the View forum screen + +viewforum_forum_name_prepend +=== +* Locations: + + styles/prosilver/template/viewforum_body.html + + styles/subsilver2/template/viewforum_body.html +* Since: 3.1.0-b3 +* Purpose: Add content directly before the forum name link on the View forum screen + viewtopic_print_head_append === * Locations: @@ -667,6 +785,22 @@ viewtopic_print_head_append * Since: 3.1.0-a1 * Purpose: Add asset calls directly before the `</head>` tag of the Print Topic screen +viewtopic_body_contact_fields_after +=== +* Locations: + + styles/prosilver/template/viewtopic_body.html +* Since: 3.1.0-b3 +* Purpose: Add data after the contact fields on the user profile when viewing +a post + +viewtopic_body_contact_fields_before +=== +* Locations: + + styles/prosilver/template/viewtopic_body.html +* Since: 3.1.0-b3 +* Purpose: Add data before the contact fields on the user profile when viewing +a post + viewtopic_body_footer_before === * Locations: @@ -677,6 +811,40 @@ viewtopic_body_footer_before and quick reply, directly before the jumpbox in Prosilver, breadcrumbs in Subsilver2. +viewtopic_body_poll_option_after +=== +* Locations: + + styles/prosilver/template/viewtopic_body.html + + styles/subsilver2/template/viewtopic_body.html +* Since: 3.1.0-b3 +* Purpose: Add content after the poll option +the list. + +viewtopic_body_poll_option_before +=== +* Locations: + + styles/prosilver/template/viewtopic_body.html + + styles/subsilver2/template/viewtopic_body.html +* Since: 3.1.0-b3 +* Purpose: Add content before the poll option +the list. + +viewtopic_body_poll_question_append +=== +* Locations: + + styles/prosilver/template/viewtopic_body.html + + styles/subsilver2/template/viewtopic_body.html +* Since: 3.1.0-b3 +* Purpose: Add content directly after the poll question on the View topic screen + +viewtopic_body_poll_question_prepend +=== +* Locations: + + styles/prosilver/template/viewtopic_body.html + + styles/subsilver2/template/viewtopic_body.html +* Since: 3.1.0-b3 +* Purpose: Add content directly before the poll question on the View topic screen + viewtopic_body_post_buttons_after === * Locations: @@ -753,6 +921,14 @@ viewtopic_body_topic_actions_before * Since: 3.1.0-a4 * Purpose: Add data before the topic actions buttons (after the posts sorting options) +viewtopic_topic_title_append +=== +* Locations: + + styles/prosilver/template/viewtopic_body.html + + styles/subsilver2/template/viewtopic_body.html +* Since: 3.1.0-b3 +* Purpose: Add content directly after the topic title link on the View topic screen + viewtopic_topic_title_prepend === * Locations: diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index 6b52fbbdb2..cf0f23a16e 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -345,6 +345,7 @@ class acp_board 'load_user_activity' => array('lang' => 'LOAD_USER_ACTIVITY', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'load_tplcompile' => array('lang' => 'RECOMPILE_STYLES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'allow_cdn' => array('lang' => 'ALLOW_CDN', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'allow_live_searches' => array('lang' => 'ALLOW_LIVE_SEARCHES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'legend3' => 'CUSTOM_PROFILE_FIELDS', 'load_cpf_memberlist' => array('lang' => 'LOAD_CPF_MEMBERLIST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), diff --git a/phpBB/includes/acp/acp_database.php b/phpBB/includes/acp/acp_database.php index d28ee5b067..51715141eb 100644 --- a/phpBB/includes/acp/acp_database.php +++ b/phpBB/includes/acp/acp_database.php @@ -101,6 +101,10 @@ class acp_database $extractor = new sqlite_extractor($format, $filename, $time, $download, $store); break; + case 'sqlite3': + $extractor = new sqlite3_extractor($format, $filename, $time, $download, $store); + break; + case 'postgres': $extractor = new postgres_extractor($format, $filename, $time, $download, $store); break; @@ -135,6 +139,7 @@ class acp_database switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $extractor->flush('DELETE FROM ' . $table_name . ";\n"); break; @@ -325,6 +330,7 @@ class acp_database case 'mysql4': case 'mysqli': case 'sqlite': + case 'sqlite3': while (($sql = $fgetd($fp, ";\n", $read, $seek, $eof)) !== false) { $db->sql_query($sql); @@ -1052,6 +1058,112 @@ class sqlite_extractor extends base_extractor /** * @package acp */ +class sqlite3_extractor extends base_extractor +{ + function write_start($prefix) + { + $sql_data = "--\n"; + $sql_data .= "-- phpBB Backup Script\n"; + $sql_data .= "-- Dump of tables for $prefix\n"; + $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n"; + $sql_data .= "--\n"; + $sql_data .= "BEGIN TRANSACTION;\n"; + $this->flush($sql_data); + } + + function write_table($table_name) + { + global $db; + $sql_data = '-- Table: ' . $table_name . "\n"; + $sql_data .= "DROP TABLE $table_name;\n"; + + $sql = "SELECT sql + FROM sqlite_master + WHERE type = 'table' + AND name = '" . $db->sql_escape($table_name) . "' + ORDER BY name ASC;"; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + // Create Table + $sql_data .= $row['sql'] . ";\n"; + + $result = $db->sql_query("PRAGMA index_list('" . $db->sql_escape($table_name) . "');"); + + while ($row = $db->sql_fetchrow($result)) + { + if (strpos($row['name'], 'autoindex') !== false) + { + continue; + } + + $result2 = $db->sql_query("PRAGMA index_info('" . $db->sql_escape($row['name']) . "');"); + + $fields = array(); + while ($row2 = $db->sql_fetchrow($result2)) + { + $fields[] = $row2['name']; + } + $db->sql_freeresult($result2); + + $sql_data .= 'CREATE ' . ($row['unique'] ? 'UNIQUE ' : '') . 'INDEX ' . $row['name'] . ' ON ' . $table_name . ' (' . implode(', ', $fields) . ");\n"; + } + $db->sql_freeresult($result); + + $this->flush($sql_data . "\n"); + } + + function write_data($table_name) + { + global $db; + + $result = $db->sql_query("PRAGMA table_info('" . $db->sql_escape($table_name) . "');"); + + $col_types = array(); + while ($row = $db->sql_fetchrow($result)) + { + $col_types[$row['name']] = $row['type']; + } + $db->sql_freeresult($result); + + $sql_insert = 'INSERT INTO ' . $table_name . ' (' . implode(', ', array_keys($col_types)) . ') VALUES ('; + + $sql = "SELECT * + FROM $table_name"; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + foreach ($row as $column_name => $column_data) + { + if (is_null($column_data)) + { + $row[$column_name] = 'NULL'; + } + else if ($column_data === '') + { + $row[$column_name] = "''"; + } + else if (stripos($col_types[$column_name], 'text') !== false || stripos($col_types[$column_name], 'char') !== false || stripos($col_types[$column_name], 'blob') !== false) + { + $row[$column_name] = sanitize_data_generic(str_replace("'", "''", $column_data)); + } + } + $this->flush($sql_insert . implode(', ', $row) . ");\n"); + } + } + + function write_end() + { + $this->flush("COMMIT;\n"); + parent::write_end(); + } +} + +/** +* @package acp +*/ class postgres_extractor extends base_extractor { function write_start($prefix) diff --git a/phpBB/includes/acp/acp_icons.php b/phpBB/includes/acp/acp_icons.php index 9c7acf506c..e4221a86dc 100644 --- a/phpBB/includes/acp/acp_icons.php +++ b/phpBB/includes/acp/acp_icons.php @@ -538,6 +538,7 @@ class acp_icons switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $db->sql_query('DELETE FROM ' . $table); break; diff --git a/phpBB/includes/acp/acp_main.php b/phpBB/includes/acp/acp_main.php index 4512905539..9c1613e24a 100644 --- a/phpBB/includes/acp/acp_main.php +++ b/phpBB/includes/acp/acp_main.php @@ -271,6 +271,7 @@ class acp_main switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $db->sql_query('DELETE FROM ' . TOPICS_POSTED_TABLE); break; @@ -376,6 +377,7 @@ class acp_main switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $db->sql_query("DELETE FROM $table"); break; diff --git a/phpBB/includes/acp/acp_profile.php b/phpBB/includes/acp/acp_profile.php index b42b852fba..8940410d72 100644 --- a/phpBB/includes/acp/acp_profile.php +++ b/phpBB/includes/acp/acp_profile.php @@ -114,6 +114,7 @@ class acp_profile switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': $sql = "SELECT sql FROM sqlite_master WHERE type = 'table' @@ -1204,7 +1205,8 @@ class acp_profile break; case 'sqlite': - if (version_compare(sqlite_libversion(), '3.0') == -1) + case 'sqlite3': + if (version_compare($db->sql_server_info(true), '3.0') == -1) { $sql = "SELECT sql FROM sqlite_master diff --git a/phpBB/includes/acp/acp_reasons.php b/phpBB/includes/acp/acp_reasons.php index 569bb73ab0..3f61a76d3a 100644 --- a/phpBB/includes/acp/acp_reasons.php +++ b/phpBB/includes/acp/acp_reasons.php @@ -253,6 +253,7 @@ class acp_reasons case 'oracle': case 'firebird': case 'sqlite': + case 'sqlite3': // Change the reports using this reason to 'other' $sql = 'UPDATE ' . REPORTS_TABLE . ' SET reason_id = ' . $other_reason_id . ", report_text = '" . $db->sql_escape($reason_row['reason_description']) . "\n\n' || report_text diff --git a/phpBB/includes/compatibility_globals.php b/phpBB/includes/compatibility_globals.php new file mode 100644 index 0000000000..fa468ed96a --- /dev/null +++ b/phpBB/includes/compatibility_globals.php @@ -0,0 +1,44 @@ +<?php +/** +* +* @package phpBB3 +* @copyright (c) 2014 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +// set up caching +$cache = $phpbb_container->get('cache'); + +// Instantiate some basic classes +$phpbb_dispatcher = $phpbb_container->get('dispatcher'); +$request = $phpbb_container->get('request'); +$user = $phpbb_container->get('user'); +$auth = $phpbb_container->get('auth'); +$db = $phpbb_container->get('dbal.conn'); + +// make sure request_var uses this request instance +request_var('', 0, false, false, $request); // "dependency injection" for a function + +// Grab global variables, re-cache if necessary +$config = $phpbb_container->get('config'); +set_config(null, null, null, $config); +set_config_count(null, null, null, $config); + +$phpbb_log = $phpbb_container->get('log'); +$symfony_request = $phpbb_container->get('symfony_request'); +$phpbb_filesystem = $phpbb_container->get('filesystem'); +$phpbb_path_helper = $phpbb_container->get('path_helper'); + +// load extensions +$phpbb_extension_manager = $phpbb_container->get('ext.manager'); +$phpbb_subscriber_loader = $phpbb_container->get('event.subscriber_loader'); + +$template = $phpbb_container->get('template'); diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 7b6345b9e3..786003a9ff 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3989,7 +3989,7 @@ function obtain_guest_count($item_id = 0, $item = 'forum') // Get number of online guests - if ($db->sql_layer === 'sqlite') + if ($db->sql_layer === 'sqlite' || $db->sql_layer === 'sqlite3') { $sql = 'SELECT COUNT(session_ip) as num_guests FROM ( diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php index 50b3b61eaa..db430c6940 100644 --- a/phpBB/includes/functions_admin.php +++ b/phpBB/includes/functions_admin.php @@ -2440,6 +2440,7 @@ function phpbb_cache_moderators($db, $cache, $auth) switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $db->sql_query('DELETE FROM ' . MODERATOR_CACHE_TABLE); break; @@ -2907,6 +2908,7 @@ function get_database_size() break; case 'sqlite': + case 'sqlite3': global $dbhost; if (file_exists($dbhost)) diff --git a/phpBB/includes/functions_convert.php b/phpBB/includes/functions_convert.php index 1646c79161..dbc66446b3 100644 --- a/phpBB/includes/functions_convert.php +++ b/phpBB/includes/functions_convert.php @@ -1650,6 +1650,7 @@ function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting = ACL_NO) case 'mssql': case 'sqlite': + case 'sqlite3': case 'mssqlnative': $sql = implode(' UNION ALL ', preg_replace('#^(.*?)$#', 'SELECT \1', $sql_subary)); break; @@ -2037,6 +2038,7 @@ function update_topics_posted() switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $db->sql_query('DELETE FROM ' . TOPICS_POSTED_TABLE); break; diff --git a/phpBB/includes/functions_install.php b/phpBB/includes/functions_install.php index 4f8ec99d88..f484461b77 100644 --- a/phpBB/includes/functions_install.php +++ b/phpBB/includes/functions_install.php @@ -106,6 +106,15 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'AVAILABLE' => true, '2.0.x' => false, ), + 'sqlite3' => array( + 'LABEL' => 'SQLite3', + 'SCHEMA' => 'sqlite', + 'MODULE' => 'sqlite3', + 'DELIM' => ';', + 'DRIVER' => 'phpbb\db\driver\sqlite3', + 'AVAILABLE' => true, + '2.0.x' => false, + ), ); if ($dbms) @@ -206,14 +215,14 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, $db->sql_return_on_error(true); // Check that we actually have a database name before going any further..... - if ($dbms_details['DRIVER'] != 'phpbb\db\driver\sqlite' && $dbms_details['DRIVER'] != 'phpbb\db\driver\oracle' && $dbname === '') + if ($dbms_details['DRIVER'] != 'phpbb\db\driver\sqlite' && $dbms_details['DRIVER'] != 'phpbb\db\driver\sqlite3' && $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'] == 'phpbb\db\driver\sqlite' && stripos(phpbb_realpath($dbhost), phpbb_realpath('../')) === 0) + if (($dbms_details['DRIVER'] == 'phpbb\db\driver\sqlite' || $dbms_details['DRIVER'] == 'phpbb\db\driver\sqlite3') && stripos(phpbb_realpath($dbhost), phpbb_realpath('../')) === 0) { $error[] = $lang['INST_ERR_DB_FORUM_PATH']; return false; @@ -243,6 +252,7 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, break; case 'phpbb\db\driver\sqlite': + case 'phpbb\db\driver\sqlite3': $prefix_length = 200; break; @@ -299,6 +309,14 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, } break; + case 'phpbb\db\driver\sqlite3': + $version = \SQLite3::version(); + if (version_compare($version['versionString'], '3.6.15', '<')) + { + $error[] = $lang['INST_ERR_DB_NO_SQLITE3']; + } + break; + 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')) diff --git a/phpBB/includes/ucp/ucp_pm_viewmessage.php b/phpBB/includes/ucp/ucp_pm_viewmessage.php index 364d0caf25..8a60a7e680 100644 --- a/phpBB/includes/ucp/ucp_pm_viewmessage.php +++ b/phpBB/includes/ucp/ucp_pm_viewmessage.php @@ -177,6 +177,18 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) } } + $u_pm = $u_jabber = ''; + + if ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && ($user_info['user_allow_pm'] || $auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_'))) + { + $u_pm = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose&u=' . $author_id); + } + + if ($user_info['user_jabber'] && $auth->acl_get('u_sendim')) + { + $u_jabber = append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contact&action=jabber&u=' . $author_id); + } + $msg_data = array( 'MESSAGE_AUTHOR_FULL' => get_username_string('full', $author_id, $user_info['username'], $user_info['user_colour'], $user_info['username']), 'MESSAGE_AUTHOR_COLOUR' => get_username_string('colour', $author_id, $user_info['username'], $user_info['user_colour'], $user_info['username']), @@ -208,8 +220,8 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) 'EDITED_MESSAGE' => $l_edited_by, 'MESSAGE_ID' => $message_row['msg_id'], - 'U_PM' => ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && ($user_info['user_allow_pm'] || $auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_'))) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose&u=' . $author_id) : '', - 'U_JABBER' => ($user_info['user_jabber'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contact&action=jabber&u=' . $author_id) : '', + 'U_PM' => $u_pm, + 'U_JABBER' => $u_jabber, 'U_DELETE' => ($auth->acl_get('u_pm_delete')) ? "$url&mode=compose&action=delete&f=$folder_id&p=" . $message_row['msg_id'] : '', 'U_EMAIL' => $user_info['email'], @@ -264,6 +276,32 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) $template->assign_vars($msg_data); + $contact_fields = array( + array( + 'ID' => 'pm', + 'NAME' => $user->lang['PRIVATE_MESSAGE'], + 'U_CONTACT' => $u_pm, + ), + array( + 'ID' => 'email', + 'NAME' => $user->lang['SEND_EMAIL'], + 'U_CONTACT' => $user_info['email'], + ), + array( + 'ID' => 'jabber', + 'NAME' => $user->lang['JABBER'], + 'U_CONTACT' => $u_jabber, + ), + ); + + foreach ($contact_fields as $field) + { + if ($field['U_CONTACT']) + { + $template->assign_block_vars('contact', $field); + } + } + // Display the custom profile fields if (!empty($cp_row['row'])) { @@ -272,6 +310,15 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) foreach ($cp_row['blockrow'] as $cp_block_row) { $template->assign_block_vars('custom_fields', $cp_block_row); + + if ($cp_block_row['S_PROFILE_CONTACT']) + { + $template->assign_block_vars('contact', array( + 'ID' => $cp_block_row['PROFILE_FIELD_IDENT'], + 'NAME' => $cp_block_row['PROFILE_FIELD_NAME'], + 'U_CONTACT' => $cp_block_row['PROFILE_FIELD_CONTACT'], + )); + } } } diff --git a/phpBB/includes/ucp/ucp_register.php b/phpBB/includes/ucp/ucp_register.php index ff51ca7b3c..8660a06dcf 100644 --- a/phpBB/includes/ucp/ucp_register.php +++ b/phpBB/includes/ucp/ucp_register.php @@ -64,10 +64,7 @@ class ucp_register $agreed = false; } - $user->lang_name = $user_lang = $use_lang; - $user->lang = array(); - $user->data['user_lang'] = $user->lang_name; - $user->add_lang(array('common', 'ucp')); + $user_lang = $use_lang; } else { @@ -101,7 +98,6 @@ class ucp_register if (!$agreed || ($coppa === false && $config['coppa_enable']) || ($coppa && !$config['coppa_enable'])) { - $add_lang = ($change_lang) ? '&change_lang=' . urlencode($change_lang) : ''; $add_coppa = ($coppa !== false) ? '&coppa=' . $coppa : ''; $s_hidden_fields = array_merge($s_hidden_fields, array( @@ -147,12 +143,15 @@ class ucp_register 'L_COPPA_NO' => sprintf($user->lang['UCP_COPPA_BEFORE'], $coppa_birthday), 'L_COPPA_YES' => sprintf($user->lang['UCP_COPPA_ON_AFTER'], $coppa_birthday), - 'U_COPPA_NO' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&coppa=0' . $add_lang), - 'U_COPPA_YES' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&coppa=1' . $add_lang), + 'U_COPPA_NO' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&coppa=0'), + 'U_COPPA_YES' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&coppa=1'), 'S_SHOW_COPPA' => true, 'S_HIDDEN_FIELDS' => build_hidden_fields($s_hidden_fields), - 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register' . $add_lang), + 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register'), + + 'COOKIE_NAME' => $config['cookie_name'], + 'COOKIE_PATH' => $config['cookie_path'], )); } else @@ -164,7 +163,10 @@ class ucp_register 'S_SHOW_COPPA' => false, 'S_REGISTRATION' => true, 'S_HIDDEN_FIELDS' => build_hidden_fields($s_hidden_fields), - 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register' . $add_lang . $add_coppa), + 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register' . $add_coppa), + + 'COOKIE_NAME' => $config['cookie_name'], + 'COOKIE_PATH' => $config['cookie_path'], ) ); } @@ -469,6 +471,9 @@ class ucp_register 'S_COPPA' => $coppa, 'S_HIDDEN_FIELDS' => $s_hidden_fields, 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register'), + + 'COOKIE_NAME' => $config['cookie_name'], + 'COOKIE_PATH' => $config['cookie_path'], )); // diff --git a/phpBB/install/convertors/functions_phpbb20.php b/phpBB/install/convertors/functions_phpbb20.php index f3b8c82131..b5a69abe93 100644 --- a/phpBB/install/convertors/functions_phpbb20.php +++ b/phpBB/install/convertors/functions_phpbb20.php @@ -1843,6 +1843,7 @@ function phpbb_create_userconv_table() break; case 'sqlite': + case 'sqlite3': $create_sql = 'CREATE TABLE ' . USERCONV_TABLE . ' ( user_id INTEGER NOT NULL DEFAULT \'0\', username_clean varchar(255) NOT NULL DEFAULT \'\' diff --git a/phpBB/install/install_convert.php b/phpBB/install/install_convert.php index 82311bd04d..13001426f7 100644 --- a/phpBB/install/install_convert.php +++ b/phpBB/install/install_convert.php @@ -249,6 +249,7 @@ class install_convert extends module switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $db->sql_query('DELETE FROM ' . SESSIONS_KEYS_TABLE); $db->sql_query('DELETE FROM ' . SESSIONS_TABLE); @@ -696,6 +697,7 @@ class install_convert extends module switch ($src_db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $convert->src_truncate_statement = 'DELETE FROM '; break; @@ -728,6 +730,7 @@ class install_convert extends module switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $convert->truncate_statement = 'DELETE FROM '; break; diff --git a/phpBB/install/schemas/schema_data.sql b/phpBB/install/schemas/schema_data.sql index fbf1374346..2ee6b5f806 100644 --- a/phpBB/install/schemas/schema_data.sql +++ b/phpBB/install/schemas/schema_data.sql @@ -21,6 +21,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_cdn', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_emailreuse', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_password_reset', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_forum_notify', '1'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_live_searches', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_mass_pm', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_name_chars', 'USERNAME_CHARS_ANY'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_namechange', '0'); diff --git a/phpBB/language/en/acp/board.php b/phpBB/language/en/acp/board.php index e21d959e40..505709d513 100644 --- a/phpBB/language/en/acp/board.php +++ b/phpBB/language/en/acp/board.php @@ -356,6 +356,8 @@ $lang = array_merge($lang, array( 'ALLOW_CDN' => 'Allow usage of third party content delivery networks', 'ALLOW_CDN_EXPLAIN' => 'If this setting is enabled, some files will be served from external third party servers instead of your server. This reduces the network bandwidth required by your server, but may present a privacy issue for some board administrators. In a default phpBB installation, this includes loading “jQuery” and the font “Open Sans” from Google’s content delivery network.', + 'ALLOW_LIVE_SEARCHES' => 'Allow live searches', + 'ALLOW_LIVE_SEARCHES_EXPLAIN' => 'If this setting is enabled, users are provided with keyword suggestions as they type in certain fields throughout the board.', 'CUSTOM_PROFILE_FIELDS' => 'Custom profile fields', 'LIMIT_LOAD' => 'Limit system load', 'LIMIT_LOAD_EXPLAIN' => 'If the system’s 1-minute load average exceeds this value the board will automatically go offline. A value of 1.0 equals ~100% utilisation of one processor. This only functions on UNIX based servers and where this information is accessible. The value here resets itself to 0 if phpBB was unable to get the load limit.', diff --git a/phpBB/language/en/app.php b/phpBB/language/en/app.php index cb56015c30..6697532150 100644 --- a/phpBB/language/en/app.php +++ b/phpBB/language/en/app.php @@ -41,9 +41,6 @@ if (empty($lang) || !is_array($lang)) $lang = array_merge($lang, array( 'CONTROLLER_ARGUMENT_VALUE_MISSING' => 'Missing value for argument #%1$s: <strong>%3$s</strong> in class <strong>%2$s</strong>', 'CONTROLLER_NOT_SPECIFIED' => 'No controller has been specified.', - 'CONTROLLER_NOT_FOUND' => 'The requested page could not be found.', 'CONTROLLER_METHOD_NOT_SPECIFIED' => 'No method was specified for the controller.', - 'CONTROLLER_SERVICE_NOT_GIVEN' => 'The controller "<strong>%s</strong>" must have a service specified in ./config/routing.yml.', 'CONTROLLER_SERVICE_UNDEFINED' => 'The service for controller "<strong>%s</strong>" is not defined in ./config/services.yml.', - 'CONTROLLER_RETURN_TYPE_INVALID' => 'The controller object <strong>%s</strong> must return a Symfony\Component\HttpFoundation\Response object.', )); diff --git a/phpBB/language/en/common.php b/phpBB/language/en/common.php index 569ec776f5..aac4f2516e 100644 --- a/phpBB/language/en/common.php +++ b/phpBB/language/en/common.php @@ -167,6 +167,7 @@ $lang = array_merge($lang, array( 'CONGRATULATIONS' => 'Congratulations to', 'CONNECTION_FAILED' => 'Connection failed.', 'CONNECTION_SUCCESS' => 'Connection was successful!', + 'CONTACT_USER' => 'Contact', 'COOKIES_DELETED' => 'All board cookies successfully deleted.', 'CURRENT_TIME' => 'It is currently %s', @@ -217,8 +218,6 @@ $lang = array_merge($lang, array( 'ERROR' => 'Error', 'EXPAND_VIEW' => 'Expand view', 'EXTENSION' => 'Extension', - 'EXTENSION_CONTROLLER_MISSING' => 'The extension <strong>%s</strong> is missing a controller class and cannot be accessed through the front-end.', - 'EXTENSION_CLASS_WRONG_TYPE' => 'The extension controller class <strong>%s</strong> is not an instance of the phpbb_extension_controller_interface.', 'EXTENSION_DISABLED' => 'The extension <strong>%s</strong> is not enabled.', 'EXTENSION_DISABLED_AFTER_POSTING' => 'The extension <strong>%s</strong> has been deactivated and can no longer be displayed.', 'EXTENSION_DOES_NOT_EXIST' => 'The extension <strong>%s</strong> does not exist.', @@ -348,6 +347,7 @@ $lang = array_merge($lang, array( 'LDAP_NO_SERVER_CONNECTION' => 'Could not connect to LDAP server.', 'LDAP_SEARCH_FAILED' => 'An error occurred while searching the LDAP directory.', 'LEGEND' => 'Legend', + 'LIVE_SEARCHES_NOT_ALLOWED' => 'Live searches are not allowed.', 'LOADING' => 'Loading', 'LOCATION' => 'Location', 'LOCK_POST' => 'Lock post', diff --git a/phpBB/language/en/install.php b/phpBB/language/en/install.php index 081361f661..caefc1219d 100644 --- a/phpBB/language/en/install.php +++ b/phpBB/language/en/install.php @@ -151,7 +151,8 @@ $lang = array_merge($lang, array( 'DLL_MYSQLI' => 'MySQL with MySQLi Extension', 'DLL_ORACLE' => 'Oracle', 'DLL_POSTGRES' => 'PostgreSQL', - 'DLL_SQLITE' => 'SQLite', + 'DLL_SQLITE' => 'SQLite 2', + 'DLL_SQLITE3' => 'SQLite 3', 'DLL_XML' => 'XML support [ Jabber ]', 'DLL_ZLIB' => 'zlib compression support [ gz, .tar.gz, .zip ]', 'DL_CONFIG' => 'Download config', @@ -212,6 +213,7 @@ $lang = array_merge($lang, array( <li>MySQL 3.23 or above (MySQLi supported)</li> <li>PostgreSQL 8.3+</li> <li>SQLite 2.8.2+</li> + <li>SQLite 3.6.15+</li> <li>Firebird 2.1+</li> <li>MS SQL Server 2000 or above (directly or via ODBC)</li> <li>MS SQL Server 2005 or above (native)</li> @@ -235,6 +237,7 @@ $lang = array_merge($lang, array( 'INST_ERR_DB_NO_ERROR' => 'No error message given.', 'INST_ERR_DB_NO_MYSQLI' => 'The version of MySQL installed on this machine is incompatible with the “MySQL with MySQLi Extension” option you have selected. Please try the “MySQL” option instead.', 'INST_ERR_DB_NO_SQLITE' => 'The version of the SQLite extension you have installed is too old, it must be upgraded to at least 2.8.2.', + 'INST_ERR_DB_NO_SQLITE3' => 'The version of the SQLite extension you have installed is too old, it must be upgraded to at least 3.6.15.', 'INST_ERR_DB_NO_ORACLE' => 'The version of Oracle installed on this machine requires you to set the <var>NLS_CHARACTERSET</var> parameter to <var>UTF8</var>. Either upgrade your installation to 9.2+ or change the parameter.', 'INST_ERR_DB_NO_FIREBIRD' => 'The version of Firebird installed on this machine is older than 2.1, please upgrade to a newer version.', 'INST_ERR_DB_NO_FIREBIRD_PS'=> 'The database you selected for Firebird has a page size less than 8192, it must be at least 8192.', diff --git a/phpBB/language/en/memberlist.php b/phpBB/language/en/memberlist.php index 95efe35b7d..f92286a092 100644 --- a/phpBB/language/en/memberlist.php +++ b/phpBB/language/en/memberlist.php @@ -47,7 +47,6 @@ $lang = array_merge($lang, array( 'BEFORE' => 'Before', 'CC_EMAIL' => 'Send a copy of this email to yourself.', - 'CONTACT_USER' => 'Contact', 'DEST_LANG' => 'Language', 'DEST_LANG_EXPLAIN' => 'Select an appropriate language (if available) for the recipient of this message.', diff --git a/phpBB/memberlist.php b/phpBB/memberlist.php index 3ce340b396..6c28f962dc 100644 --- a/phpBB/memberlist.php +++ b/phpBB/memberlist.php @@ -40,7 +40,7 @@ if ($mode == 'leaders') } // Check our mode... -if (!in_array($mode, array('', 'group', 'viewprofile', 'email', 'contact', 'searchuser', 'team'))) +if (!in_array($mode, array('', 'group', 'viewprofile', 'email', 'contact', 'searchuser', 'team', 'livesearch'))) { trigger_error('NO_MODE'); } @@ -50,6 +50,13 @@ switch ($mode) case 'email': break; + case 'livesearch': + if (!$config['allow_live_searches']) + { + trigger_error('LIVE_SEARCHES_NOT_ALLOWED'); + } + // No break + default: // Can this user view profiles/memberlist? if (!$auth->acl_gets('u_viewprofile', 'a_user', 'a_useradd', 'a_userdel')) @@ -985,6 +992,35 @@ switch ($mode) break; + case 'livesearch': + + $username_chars = $request->variable('username', '', true); + + $sql = 'SELECT username, user_id, user_colour + FROM ' . USERS_TABLE . ' + WHERE ' . $db->sql_in_set('user_type', array(USER_NORMAL, USER_FOUNDER)) . ' + AND username_clean ' . $db->sql_like_expression(utf8_clean_string($username_chars) . $db->any_char); + $result = $db->sql_query_limit($sql, 10); + $user_list = array(); + + while ($row = $db->sql_fetchrow($result)) + { + $user_list[] = array( + 'user_id' => (int) $row['user_id'], + 'result' => $row['username'], + 'username_full' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), + 'display' => get_username_string('no_profile', $row['user_id'], $row['username'], $row['user_colour']), + ); + } + $db->sql_freeresult($result); + $json_response = new \phpbb\json_response(); + $json_response->send(array( + 'keyword' => $username_chars, + 'results' => $user_list, + )); + + break; + case 'group': default: // The basic memberlist @@ -1622,6 +1658,7 @@ switch ($mode) 'U_FIND_MEMBER' => ($config['load_search'] || $auth->acl_get('a_')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser' . (($start) ? "&start=$start" : '') . (!empty($params) ? '&' . implode('&', $params) : '')) : '', 'U_HIDE_FIND_MEMBER' => ($mode == 'searchuser' || ($mode == '' && $submit)) ? $u_hide_find_member : '', + 'U_LIVE_SEARCH' => ($config['allow_live_searches']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=livesearch') : false, 'U_SORT_USERNAME' => $sort_url . '&sk=a&sd=' . (($sort_key == 'a' && $sort_dir == 'a') ? 'd' : 'a'), 'U_SORT_JOINED' => $sort_url . '&sk=c&sd=' . (($sort_key == 'c' && $sort_dir == 'a') ? 'd' : 'a'), 'U_SORT_POSTS' => $sort_url . '&sk=d&sd=' . (($sort_key == 'd' && $sort_dir == 'a') ? 'd' : 'a'), @@ -1726,7 +1763,7 @@ function show_profile($data, $user_notes_enabled = false, $warn_user_enabled = f $data['user_type'] != USER_IGNORE && // They must not be deactivated by the administrator - ($data['user_type'] != USER_INACTIVE && $data['user_inactive_reason'] == INACTIVE_MANUAL) && + ($data['user_type'] != USER_INACTIVE || $data['user_inactive_reason'] != INACTIVE_MANUAL) && // They must be able to read PMs sizeof($auth->acl_get_list($user_id, 'u_readpm')) && diff --git a/phpBB/phpbb/console/command/db/migrate.php b/phpBB/phpbb/console/command/db/migrate.php new file mode 100644 index 0000000000..16a09af6fc --- /dev/null +++ b/phpBB/phpbb/console/command/db/migrate.php @@ -0,0 +1,128 @@ +<?php +/** +* +* @package phpBB3 +* @copyright (c) 2014 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ +namespace phpbb\console\command\db; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class migrate extends \phpbb\console\command\command +{ + /** @var \phpbb\db\migrator */ + protected $migrator; + + /** @var \phpbb\extension\manager */ + protected $extension_manager; + + /** @var \phpbb\config\config */ + protected $config; + + /** @var \phpbb\cache\service */ + protected $cache; + + /** @var \phpbb\log\log */ + protected $log; + + /** @var \phpbb\user */ + protected $user; + + function __construct(\phpbb\db\migrator $migrator, \phpbb\extension\manager $extension_manager, \phpbb\config\config $config, \phpbb\cache\service $cache, \phpbb\log\log $log, \phpbb\user $user) + { + $this->migrator = $migrator; + $this->extension_manager = $extension_manager; + $this->config = $config; + $this->cache = $cache; + $this->log = $log; + $this->user = $user; + $this->user->add_lang(array('common', 'acp/common', 'install', 'migrator')); + parent::__construct(); + } + + protected function configure() + { + $this + ->setName('db:migrate') + ->setDescription('Updates the database by applying migrations.') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->load_migrations(); + $orig_version = $this->config['version']; + while (!$this->migrator->finished()) + { + $migration_start_time = microtime(true); + + try + { + $this->migrator->update(); + } + catch (\phpbb\db\migration\exception $e) + { + $output->writeln('<error>' . $e->getLocalisedMessage($this->user) . '</error>'); + $this->finalise_update(); + return 1; + } + + $migration_stop_time = microtime(true) - $migration_start_time; + + $state = array_merge( + array( + 'migration_schema_done' => false, + 'migration_data_done' => false, + ), + $this->migrator->last_run_migration['state'] + ); + + if (!empty($this->migrator->last_run_migration['effectively_installed'])) + { + $msg = $this->user->lang('MIGRATION_EFFECTIVELY_INSTALLED', $this->migrator->last_run_migration['name']); + $output->writeln("<comment>$msg</comment>"); + } + else if ($this->migrator->last_run_migration['task'] == 'process_data_step' && $state['migration_data_done']) + { + $msg = $this->user->lang('MIGRATION_DATA_DONE', $this->migrator->last_run_migration['name'], $migration_stop_time); + $output->writeln("<info>$msg</info>"); + } + else if ($this->migrator->last_run_migration['task'] == 'process_data_step') + { + $output->writeln($this->user->lang('MIGRATION_DATA_IN_PROGRESS', $this->migrator->last_run_migration['name'], $migration_stop_time)); + } + else if ($state['migration_schema_done']) + { + $msg = $this->user->lang('MIGRATION_SCHEMA_DONE', $this->migrator->last_run_migration['name'], $migration_stop_time); + $output->writeln("<info>$msg</info>"); + } + } + + if ($orig_version != $this->config['version']) + { + $this->log->add('admin', 'LOG_UPDATE_DATABASE', $orig_version, $this->config['version']); + } + + $this->finalise_update(); + $output->writeln($this->user->lang['DATABASE_UPDATE_COMPLETE']); + } + + protected function load_migrations() + { + $migrations = $this->extension_manager + ->get_finder() + ->core_path('phpbb/db/migration/data/') + ->extension_directory('/migrations') + ->get_classes(); + $this->migrator->set_migrations($migrations); + } + + protected function finalise_update() + { + $this->cache->purge(); + $this->config->increment('assets_version', 1); + } +} diff --git a/phpBB/phpbb/controller/provider.php b/phpBB/phpbb/controller/provider.php index 9df8130210..2c7493f64c 100644 --- a/phpBB/phpbb/controller/provider.php +++ b/phpBB/phpbb/controller/provider.php @@ -46,7 +46,7 @@ class provider // We hardcode the path to the core config directory // because the finder cannot find it $this->routing_files = array_merge($this->routing_files, array('config/routing.yml'), array_keys($finder - ->directory('config') + ->directory('/config') ->suffix('routing.yml') ->find() )); diff --git a/phpBB/phpbb/db/driver/sqlite3.php b/phpBB/phpbb/db/driver/sqlite3.php new file mode 100644 index 0000000000..971b3e55d3 --- /dev/null +++ b/phpBB/phpbb/db/driver/sqlite3.php @@ -0,0 +1,375 @@ +<?php +/** +* +* @package dbal +* @copyright (c) 2014 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +namespace phpbb\db\driver; + +/** +* SQLite3 Database Abstraction Layer +* Minimum Requirement: 3.6.15+ +* @package dbal +*/ +class sqlite3 extends \phpbb\db\driver\driver +{ + /** + * @var string Stores errors during connection setup in case the driver is not available + */ + protected $connect_error = ''; + + /** + * @var \SQLite3 The SQLite3 database object to operate against + */ + protected $dbo = null; + + /** + * {@inheritDoc} + */ + public function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) + { + $this->persistency = false; + $this->user = $sqluser; + $this->server = $sqlserver . (($port) ? ':' . $port : ''); + $this->dbname = $database; + + if (!class_exists('SQLite3', false)) + { + $this->connect_error = 'SQLite3 not found, is the extension installed?'; + return $this->sql_error(''); + } + + try + { + $this->dbo = new \SQLite3($this->server, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE); + $this->db_connect_id = true; + } + catch (Exception $e) + { + return array('message' => $e->getMessage()); + } + + return true; + } + + /** + * {@inheritDoc} + */ + public function sql_server_info($raw = false, $use_cache = true) + { + global $cache; + + if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('sqlite_version')) === false) + { + $version = \SQLite3::version(); + + $this->sql_server_version = $version['versionString']; + + if (!empty($cache) && $use_cache) + { + $cache->put('sqlite_version', $this->sql_server_version); + } + } + + return ($raw) ? $this->sql_server_version : 'SQLite ' . $this->sql_server_version; + } + + /** + * SQL Transaction + * + * @param string $status Should be one of the following strings: + * begin, commit, rollback + * @return bool Success/failure of the transaction query + */ + protected function _sql_transaction($status = 'begin') + { + switch ($status) + { + case 'begin': + return $this->dbo->exec('BEGIN IMMEDIATE'); + break; + + case 'commit': + return $this->dbo->exec('COMMIT'); + break; + + case 'rollback': + return $this->dbo->exec('ROLLBACK'); + break; + } + + return true; + } + + /** + * {@inheritDoc} + */ + public function sql_query($query = '', $cache_ttl = 0) + { + if ($query != '') + { + global $cache; + + // EXPLAIN only in extra debug mode + if (defined('DEBUG')) + { + $this->sql_report('start', $query); + } + + $this->last_query_text = $query; + $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false; + $this->sql_add_num_queries($this->query_result); + + if ($this->query_result === false) + { + if (($this->query_result = @$this->dbo->query($query)) === false) + { + $this->sql_error($query); + } + + if (defined('DEBUG')) + { + $this->sql_report('stop', $query); + } + + if ($cache && $cache_ttl) + { + $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); + } + } + else if (defined('DEBUG')) + { + $this->sql_report('fromcache', $query); + } + } + else + { + return false; + } + + return $this->query_result; + } + + /** + * Build LIMIT query + * + * @param string $query The SQL query to execute + * @param int $total The number of rows to select + * @param int $offset + * @param int $cache_ttl Either 0 to avoid caching or + * the time in seconds which the result shall be kept in cache + * @return mixed Buffered, seekable result handle, false on error + */ + protected function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) + { + $this->query_result = false; + + // if $total is set to 0 we do not want to limit the number of rows + if ($total == 0) + { + $total = -1; + } + + $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total); + + return $this->sql_query($query, $cache_ttl); + } + + /** + * {@inheritDoc} + */ + public function sql_affectedrows() + { + return ($this->db_connect_id) ? $this->dbo->changes() : false; + } + + /** + * {@inheritDoc} + */ + public function sql_fetchrow($query_id = false) + { + global $cache; + + if ($query_id === false) + { + $query_id = $this->query_result; + } + + if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) + { + return $cache->sql_fetchrow($query_id); + } + + return is_object($query_id) ? $query_id->fetchArray(SQLITE3_ASSOC) : false; + } + + /** + * {@inheritDoc} + */ + public function sql_nextid() + { + return ($this->db_connect_id) ? $this->dbo->lastInsertRowID() : false; + } + + /** + * {@inheritDoc} + */ + public function sql_freeresult($query_id = false) + { + global $cache; + + if ($query_id === false) + { + $query_id = $this->query_result; + } + + if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) + { + return $cache->sql_freeresult($query_id); + } + + if ($query_id) + { + return @$query_id->finalize(); + } + } + + /** + * {@inheritDoc} + */ + public function sql_escape($msg) + { + return \SQLite3::escapeString($msg); + } + + /** + * {@inheritDoc} + * + * For SQLite an underscore is a not-known character... + */ + public function sql_like_expression($expression) + { + // Unlike LIKE, GLOB is case sensitive (unfortunatly). SQLite users need to live with it! + // We only catch * and ? here, not the character map possible on file globbing. + $expression = str_replace(array(chr(0) . '_', chr(0) . '%'), array(chr(0) . '?', chr(0) . '*'), $expression); + + $expression = str_replace(array('?', '*'), array("\?", "\*"), $expression); + $expression = str_replace(array(chr(0) . "\?", chr(0) . "\*"), array('?', '*'), $expression); + + return 'GLOB \'' . $this->sql_escape($expression) . '\''; + } + + /** + * return sql error array + * + * @return array + */ + protected function _sql_error() + { + if (class_exists('SQLite3', false)) + { + $error = array( + 'message' => $this->dbo->lastErrorMsg(), + 'code' => $this->dbo->lastErrorCode(), + ); + } + else + { + $error = array( + 'message' => $this->connect_error, + 'code' => '', + ); + } + + return $error; + } + + /** + * Build db-specific query data + * + * @param string $stage Available stages: FROM, WHERE + * @param mixed $data A string containing the CROSS JOIN query or an array of WHERE clauses + * + * @return string The db-specific query fragment + */ + protected function _sql_custom_build($stage, $data) + { + return $data; + } + + /** + * Close sql connection + * + * @return bool False if failure + */ + protected function _sql_close() + { + return $this->dbo->close(); + } + + /** + * Build db-specific report + * + * @param string $mode Available modes: display, start, stop, + * add_select_row, fromcache, record_fromcache + * @param string $query The Query that should be explained + * @return mixed Either a full HTML page, boolean or null + */ + protected function _sql_report($mode, $query = '') + { + switch ($mode) + { + case 'start': + + $explain_query = $query; + if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) + { + $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; + } + else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) + { + $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; + } + + if (preg_match('/^SELECT/', $explain_query)) + { + $html_table = false; + + if ($result = $this->dbo->query("EXPLAIN QUERY PLAN $explain_query")) + { + while ($row = $result->fetchArray(SQLITE3_ASSOC)) + { + $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); + } + } + + if ($html_table) + { + $this->html_hold .= '</table>'; + } + } + + break; + + case 'fromcache': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $result = $this->dbo->query($query); + while ($void = $result->fetchArray(SQLITE3_ASSOC)) + { + // Take the time spent on parsing rows into account + } + + $splittime = explode(' ', microtime()); + $splittime = $splittime[0] + $splittime[1]; + + $this->sql_report('record_fromcache', $query, $endtime, $splittime); + + break; + } + } +} diff --git a/phpBB/phpbb/db/migration/data/v310/live_searches_config.php b/phpBB/phpbb/db/migration/data/v310/live_searches_config.php new file mode 100644 index 0000000000..8b147c954c --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v310/live_searches_config.php @@ -0,0 +1,25 @@ +<?php +/** +* +* @package migration +* @copyright (c) 2014 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +namespace phpbb\db\migration\data\v310; + +class live_searches_config extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return isset($this->config['allow_live_searches']); + } + + public function update_data() + { + return array( + array('config.add', array('allow_live_searches', '1')), + ); + } +} diff --git a/phpBB/phpbb/db/tools.php b/phpBB/phpbb/db/tools.php index 2b0132075b..a983ed91b5 100644 --- a/phpBB/phpbb/db/tools.php +++ b/phpBB/phpbb/db/tools.php @@ -257,6 +257,36 @@ class tools 'VARBINARY' => 'blob', ), + 'sqlite3' => array( + 'INT:' => 'INT(%d)', + 'BINT' => 'BIGINT(20)', + 'UINT' => 'INTEGER UNSIGNED', + 'UINT:' => 'INTEGER UNSIGNED', + 'TINT:' => 'TINYINT(%d)', + 'USINT' => 'INTEGER UNSIGNED', + 'BOOL' => 'INTEGER UNSIGNED', + 'VCHAR' => 'VARCHAR(255)', + 'VCHAR:' => 'VARCHAR(%d)', + 'CHAR:' => 'CHAR(%d)', + 'XSTEXT' => 'TEXT(65535)', + 'STEXT' => 'TEXT(65535)', + 'TEXT' => 'TEXT(65535)', + 'MTEXT' => 'MEDIUMTEXT(16777215)', + 'XSTEXT_UNI'=> 'TEXT(65535)', + 'STEXT_UNI' => 'TEXT(65535)', + 'TEXT_UNI' => 'TEXT(65535)', + 'MTEXT_UNI' => 'MEDIUMTEXT(16777215)', + 'TIMESTAMP' => 'INTEGER UNSIGNED', //'int(11) UNSIGNED', + 'DECIMAL' => 'DECIMAL(5,2)', + 'DECIMAL:' => 'DECIMAL(%d,2)', + 'PDECIMAL' => 'DECIMAL(6,3)', + 'PDECIMAL:' => 'DECIMAL(%d,3)', + 'VCHAR_UNI' => 'VARCHAR(255)', + 'VCHAR_UNI:'=> 'VARCHAR(%d)', + 'VCHAR_CI' => 'VARCHAR(255)', + 'VARBINARY' => 'BLOB', + ), + 'postgres' => array( 'INT:' => 'INT4', 'BINT' => 'INT8', @@ -299,7 +329,7 @@ class tools * A list of supported DBMS. We change this class to support more DBMS, the DBMS itself only need to follow some rules. * @var array */ - var $supported_dbms = array('firebird', 'mssql', 'mssqlnative', 'mysql_40', 'mysql_41', 'oracle', 'postgres', 'sqlite'); + var $supported_dbms = array('firebird', 'mssql', 'mssqlnative', 'mysql_40', 'mysql_41', 'oracle', 'postgres', 'sqlite', 'sqlite3'); /** * This is set to true if user only wants to return the 'to-be-executed' SQL statement(s) (as an array). @@ -389,6 +419,13 @@ class tools WHERE type = "table"'; break; + case 'sqlite3': + $sql = 'SELECT name + FROM sqlite_master + WHERE type = "table" + AND name <> "sqlite_sequence"'; + break; + case 'mssql': case 'mssql_odbc': case 'mssqlnative': @@ -567,6 +604,7 @@ class tools case 'mysql_41': case 'postgres': case 'sqlite': + case 'sqlite3': $table_sql .= ",\n\t PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')'; break; @@ -604,6 +642,7 @@ class tools case 'mysql_40': case 'sqlite': + case 'sqlite3': $table_sql .= "\n);"; $statements[] = $table_sql; break; @@ -722,7 +761,7 @@ class tools $sqlite = false; // For SQLite we need to perform the schema changes in a much more different way - if ($this->db->sql_layer == 'sqlite' && $this->return_statements) + if (($this->db->sql_layer == 'sqlite' || $this->db->sql_layer == 'sqlite3') && $this->return_statements) { $sqlite_data = array(); $sqlite = true; @@ -1140,6 +1179,7 @@ class tools break; case 'sqlite': + case 'sqlite3': $sql = "SELECT sql FROM sqlite_master WHERE type = 'table' @@ -1273,6 +1313,7 @@ class tools break; case 'sqlite': + case 'sqlite3': $sql = "PRAGMA index_list('" . $table_name . "');"; $col = 'name'; break; @@ -1293,6 +1334,7 @@ class tools case 'oracle': case 'postgres': case 'sqlite': + case 'sqlite3': $row[$col] = substr($row[$col], strlen($table_name) + 1); break; } @@ -1377,6 +1419,7 @@ class tools break; case 'sqlite': + case 'sqlite3': $sql = "PRAGMA index_list('" . $table_name . "');"; $col = 'name'; break; @@ -1390,7 +1433,7 @@ class tools continue; } - if ($this->sql_layer == 'sqlite' && !$row['unique']) + if (($this->sql_layer == 'sqlite' || $this->sql_layer == 'sqlite3') && !$row['unique']) { continue; } @@ -1418,6 +1461,7 @@ class tools case 'firebird': case 'postgres': case 'sqlite': + case 'sqlite3': $row[$col] = substr($row[$col], strlen($table_name) + 1); break; } @@ -1629,11 +1673,17 @@ class tools break; case 'sqlite': + case 'sqlite3': $return_array['primary_key_set'] = false; if (isset($column_data[2]) && $column_data[2] == 'auto_increment') { $sql .= ' INTEGER PRIMARY KEY'; $return_array['primary_key_set'] = true; + + if ($this->sql_layer === 'sqlite3') + { + $sql .= ' AUTOINCREMENT'; + } } else { @@ -1770,67 +1820,63 @@ class tools break; case 'sqlite': - if ($inline && $this->return_statements) { return $column_name . ' ' . $column_data['column_type_sql']; } - if (version_compare(sqlite_libversion(), '3.0') == -1) + $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name); + if (empty($recreate_queries)) { - $sql = "SELECT sql - FROM sqlite_master - WHERE type = 'table' - AND name = '{$table_name}' - ORDER BY type DESC, name;"; - $result = $this->db->sql_query($sql); - - if (!$result) - { - break; - } + break; + } - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); + $statements[] = 'begin'; - $statements[] = 'begin'; + $sql_create_table = array_shift($recreate_queries); - // Create a backup table and populate it, destroy the existing one - $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']); - $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; - $statements[] = 'DROP TABLE ' . $table_name; + // Create a backup table and populate it, destroy the existing one + $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table); + $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; + $statements[] = 'DROP TABLE ' . $table_name; - preg_match('#\((.*)\)#s', $row['sql'], $matches); + preg_match('#\((.*)\)#s', $sql_create_table, $matches); - $new_table_cols = trim($matches[1]); - $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); - $column_list = array(); + $new_table_cols = trim($matches[1]); + $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); + $column_list = array(); - foreach ($old_table_cols as $declaration) + foreach ($old_table_cols as $declaration) + { + $entities = preg_split('#\s+#', trim($declaration)); + if ($entities[0] == 'PRIMARY') { - $entities = preg_split('#\s+#', trim($declaration)); - if ($entities[0] == 'PRIMARY') - { - continue; - } - $column_list[] = $entities[0]; + continue; } + $column_list[] = $entities[0]; + } - $columns = implode(',', $column_list); + $columns = implode(',', $column_list); - $new_table_cols = $column_name . ' ' . $column_data['column_type_sql'] . ',' . $new_table_cols; + $new_table_cols = $column_name . ' ' . $column_data['column_type_sql'] . ',' . $new_table_cols; - // create a new table and fill it up. destroy the temp one - $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');'; - $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; - $statements[] = 'DROP TABLE ' . $table_name . '_temp'; + // create a new table and fill it up. destroy the temp one + $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');'; + $statements = array_merge($statements, $recreate_queries); - $statements[] = 'commit'; - } - else + $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; + $statements[] = 'DROP TABLE ' . $table_name . '_temp'; + + $statements[] = 'commit'; + break; + + case 'sqlite3': + if ($inline && $this->return_statements) { - $statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' [' . $column_data['column_type_sql'] . ']'; + return $column_name . ' ' . $column_data['column_type_sql']; } + + $statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' ' . $column_data['column_type_sql']; break; } @@ -1908,67 +1954,61 @@ class tools break; case 'sqlite': + case 'sqlite3': if ($inline && $this->return_statements) { return $column_name; } - if (version_compare(sqlite_libversion(), '3.0') == -1) + $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name, $column_name); + if (empty($recreate_queries)) { - $sql = "SELECT sql - FROM sqlite_master - WHERE type = 'table' - AND name = '{$table_name}' - ORDER BY type DESC, name;"; - $result = $this->db->sql_query($sql); - - if (!$result) - { - break; - } + break; + } - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); + $statements[] = 'begin'; - $statements[] = 'begin'; + $sql_create_table = array_shift($recreate_queries); - // Create a backup table and populate it, destroy the existing one - $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']); - $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; - $statements[] = 'DROP TABLE ' . $table_name; + // Create a backup table and populate it, destroy the existing one + $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table); + $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; + $statements[] = 'DROP TABLE ' . $table_name; - preg_match('#\((.*)\)#s', $row['sql'], $matches); + preg_match('#\((.*)\)#s', $sql_create_table, $matches); - $new_table_cols = trim($matches[1]); - $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); - $column_list = array(); + $new_table_cols = trim($matches[1]); + $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); + $column_list = array(); - foreach ($old_table_cols as $declaration) + foreach ($old_table_cols as $declaration) + { + $entities = preg_split('#\s+#', trim($declaration)); + if ($entities[0] == 'PRIMARY' || $entities[0] === $column_name) { - $entities = preg_split('#\s+#', trim($declaration)); - if ($entities[0] == 'PRIMARY' || $entities[0] === $column_name) - { - continue; - } - $column_list[] = $entities[0]; + continue; } + $column_list[] = $entities[0]; + } - $columns = implode(',', $column_list); - - $new_table_cols = preg_replace('/' . $column_name . '[^,]+(?:,|$)/m', '', $new_table_cols); - - // create a new table and fill it up. destroy the temp one - $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');'; - $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; - $statements[] = 'DROP TABLE ' . $table_name . '_temp'; + $columns = implode(',', $column_list); - $statements[] = 'commit'; - } - else + $new_table_cols = trim(preg_replace('/' . $column_name . '[^,]+(?:,|$)/m', '', $new_table_cols)); + if (substr($new_table_cols, -1) === ',') { - $statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN ' . $column_name; + // Remove the comma from the last entry again + $new_table_cols = substr($new_table_cols, 0, -1); } + + // create a new table and fill it up. destroy the temp one + $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');'; + $statements = array_merge($statements, $recreate_queries); + + $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; + $statements[] = 'DROP TABLE ' . $table_name . '_temp'; + + $statements[] = 'commit'; break; } @@ -1998,6 +2038,7 @@ class tools case 'oracle': case 'postgres': case 'sqlite': + case 'sqlite3': $statements[] = 'DROP INDEX ' . $table_name . '_' . $index_name; break; } @@ -2104,35 +2145,29 @@ class tools break; case 'sqlite': + case 'sqlite3': if ($inline && $this->return_statements) { return $column; } - $sql = "SELECT sql - FROM sqlite_master - WHERE type = 'table' - AND name = '{$table_name}' - ORDER BY type DESC, name;"; - $result = $this->db->sql_query($sql); - - if (!$result) + $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name); + if (empty($recreate_queries)) { break; } - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - $statements[] = 'begin'; + $sql_create_table = array_shift($recreate_queries); + // Create a backup table and populate it, destroy the existing one - $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']); + $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table); $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; $statements[] = 'DROP TABLE ' . $table_name; - preg_match('#\((.*)\)#s', $row['sql'], $matches); + preg_match('#\((.*)\)#s', $sql_create_table, $matches); $new_table_cols = trim($matches[1]); $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); @@ -2152,6 +2187,8 @@ class tools // create a new table and fill it up. destroy the temp one $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ', PRIMARY KEY (' . implode(', ', $column) . '));'; + $statements = array_merge($statements, $recreate_queries); + $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; $statements[] = 'DROP TABLE ' . $table_name . '_temp'; @@ -2182,6 +2219,7 @@ class tools case 'postgres': case 'oracle': case 'sqlite': + case 'sqlite3': $statements[] = 'CREATE UNIQUE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')'; break; @@ -2225,6 +2263,7 @@ class tools case 'postgres': case 'oracle': case 'sqlite': + case 'sqlite3': $statements[] = 'CREATE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')'; break; @@ -2316,6 +2355,7 @@ class tools break; case 'sqlite': + case 'sqlite3': $sql = "PRAGMA index_info('" . $table_name . "');"; $col = 'name'; break; @@ -2335,6 +2375,7 @@ class tools case 'oracle': case 'postgres': case 'sqlite': + case 'sqlite3': $row[$col] = substr($row[$col], strlen($table_name) + 1); break; } @@ -2488,35 +2529,29 @@ class tools break; case 'sqlite': + case 'sqlite3': if ($inline && $this->return_statements) { return $column_name . ' ' . $column_data['column_type_sql']; } - $sql = "SELECT sql - FROM sqlite_master - WHERE type = 'table' - AND name = '{$table_name}' - ORDER BY type DESC, name;"; - $result = $this->db->sql_query($sql); - - if (!$result) + $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name); + if (empty($recreate_queries)) { break; } - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - $statements[] = 'begin'; + $sql_create_table = array_shift($recreate_queries); + // Create a temp table and populate it, destroy the existing one - $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']); + $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table); $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; $statements[] = 'DROP TABLE ' . $table_name; - preg_match('#\((.*)\)#s', $row['sql'], $matches); + preg_match('#\((.*)\)#s', $sql_create_table, $matches); $new_table_cols = trim($matches[1]); $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); @@ -2534,8 +2569,10 @@ class tools $columns = implode(',', $column_list); - // create a new table and fill it up. destroy the temp one + // Create a new table and fill it up. destroy the temp one $statements[] = 'CREATE TABLE ' . $table_name . ' (' . implode(',', $old_table_cols) . ');'; + $statements = array_merge($statements, $recreate_queries); + $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; $statements[] = 'DROP TABLE ' . $table_name . '_temp'; @@ -2701,4 +2738,75 @@ class tools return $this->is_sql_server_2000; } + + /** + * Returns the Queries which are required to recreate a table including indexes + * + * @param string $table_name + * @param string $remove_column When we drop a column, we remove the column + * from all indexes. If the index has no other + * column, we drop it completly. + * @return array + */ + protected function sqlite_get_recreate_table_queries($table_name, $remove_column = '') + { + $queries = array(); + + $sql = "SELECT sql + FROM sqlite_master + WHERE type = 'table' + AND name = '{$table_name}'"; + $result = $this->db->sql_query($sql); + $sql_create_table = $this->db->sql_fetchfield('sql'); + $this->db->sql_freeresult($result); + + if (!$sql_create_table) + { + return array(); + } + $queries[] = $sql_create_table; + + $sql = "SELECT sql + FROM sqlite_master + WHERE type = 'index' + AND tbl_name = '{$table_name}'"; + $result = $this->db->sql_query($sql); + while ($sql_create_index = $this->db->sql_fetchfield('sql')) + { + if ($remove_column) + { + $match = array(); + preg_match('#(?:[\w ]+)\((.*)\)#', $sql_create_index, $match); + if (!isset($match[1])) + { + continue; + } + + // Find and remove $remove_column from the index + $columns = explode(', ', $match[1]); + $found_column = array_search($remove_column, $columns); + if ($found_column !== false) + { + unset($columns[$found_column]); + + // If the column list is not empty add the index to the list + if (!empty($columns)) + { + $queries[] = str_replace($match[1], implode(', ', $columns), $sql_create_index); + } + } + else + { + $queries[] = $sql_create_index; + } + } + else + { + $queries[] = $sql_create_index; + } + } + $this->db->sql_freeresult($result); + + return $queries; + } } diff --git a/phpBB/phpbb/profilefields/manager.php b/phpBB/phpbb/profilefields/manager.php index 37449c67c4..7d545a5f72 100644 --- a/phpBB/phpbb/profilefields/manager.php +++ b/phpBB/phpbb/profilefields/manager.php @@ -28,6 +28,12 @@ class manager protected $db; /** + * Event dispatcher object + * @var \phpbb\event\dispatcher + */ + protected $dispatcher; + + /** * Request object * @var \phpbb\request\request */ @@ -64,6 +70,7 @@ class manager * * @param \phpbb\auth\auth $auth Auth object * @param \phpbb\db\driver\driver_interface $db Database object + * @param \phpbb\event\dispatcher $dispatcher Event dispatcher object * @param \phpbb\request\request $request Request object * @param \phpbb\template\template $template Template object * @param \phpbb\di\service_collection $type_collection @@ -72,10 +79,11 @@ class manager * @param string $fields_language_table * @param string $fields_data_table */ - public function __construct(\phpbb\auth\auth $auth, \phpbb\db\driver\driver_interface $db, \phpbb\request\request $request, \phpbb\template\template $template, \phpbb\di\service_collection $type_collection, \phpbb\user $user, $fields_table, $fields_language_table, $fields_data_table) + public function __construct(\phpbb\auth\auth $auth, \phpbb\db\driver\driver_interface $db, \phpbb\event\dispatcher $dispatcher, \phpbb\request\request $request, \phpbb\template\template $template, \phpbb\di\service_collection $type_collection, \phpbb\user $user, $fields_table, $fields_language_table, $fields_data_table) { $this->auth = $auth; $this->db = $db; + $this->dispatcher = $dispatcher; $this->request = $request; $this->template = $template; $this->type_collection = $type_collection; @@ -313,6 +321,17 @@ class manager } $this->db->sql_freeresult($result); + /** + * Event to modify profile fields data retrieved from the database + * + * @event core.grab_profile_fields_data + * @var array user_ids Single user id or an array of ids + * @var array field_data Array with profile fields data + * @since 3.1.0-b3 + */ + $vars = array('user_ids', 'field_data'); + extract($this->dispatcher->trigger_event('core.grab_profile_fields_data', compact($vars))); + $user_fields = array(); // Go through the fields in correct order @@ -351,6 +370,18 @@ class manager $tpl_fields = array(); $tpl_fields['row'] = $tpl_fields['blockrow'] = array(); + /** + * Event to modify data of the generated profile fields, before the template assignment loop + * + * @event core.generate_profile_fields_template_data_before + * @var array profile_row Array with users profile field data + * @var array tpl_fields Array with template data fields + * @var bool use_contact_fields Should we display contact fields as such? + * @since 3.1.0-b3 + */ + $vars = array('profile_row', 'tpl_fields', 'use_contact_fields'); + extract($this->dispatcher->trigger_event('core.generate_profile_fields_template_data_before', compact($vars))); + foreach ($profile_row as $ident => $ident_ary) { $profile_field = $this->type_collection[$ident_ary['data']['field_type']]; @@ -404,6 +435,18 @@ class manager ); } + /** + * Event to modify template data of the generated profile fields + * + * @event core.generate_profile_fields_template_data + * @var array profile_row Array with users profile field data + * @var array tpl_fields Array with template data fields + * @var bool use_contact_fields Should we display contact fields as such? + * @since 3.1.0-b3 + */ + $vars = array('profile_row', 'tpl_fields', 'use_contact_fields'); + extract($this->dispatcher->trigger_event('core.generate_profile_fields_template_data', compact($vars))); + return $tpl_fields; } diff --git a/phpBB/phpbb/search/fulltext_native.php b/phpBB/phpbb/search/fulltext_native.php index 7d51d164c7..f3b229cc7c 100644 --- a/phpBB/phpbb/search/fulltext_native.php +++ b/phpBB/phpbb/search/fulltext_native.php @@ -768,6 +768,7 @@ class fulltext_native extends \phpbb\search\base break; case 'sqlite': + case 'sqlite3': $sql_array_count['SELECT'] = ($type == 'posts') ? 'DISTINCT p.post_id' : 'DISTINCT p.topic_id'; $sql = 'SELECT COUNT(' . (($type == 'posts') ? 'post_id' : 'topic_id') . ') as total_results FROM (' . $this->db->sql_build_query('SELECT', $sql_array_count) . ')'; @@ -997,7 +998,7 @@ class fulltext_native extends \phpbb\search\base } else { - if ($this->db->sql_layer == 'sqlite') + if ($this->db->sql_layer == 'sqlite' || $this->db->sql_layer == 'sqlite3') { $sql = 'SELECT COUNT(topic_id) as total_results FROM (SELECT DISTINCT t.topic_id'; @@ -1014,7 +1015,7 @@ class fulltext_native extends \phpbb\search\base $post_visibility $sql_fora AND t.topic_id = p.topic_id - $sql_time" . (($this->db->sql_layer == 'sqlite') ? ')' : ''); + $sql_time" . (($this->db->sql_layer == 'sqlite' || $this->db->sql_layer == 'sqlite3') ? ')' : ''); } $result = $this->db->sql_query($sql); @@ -1481,6 +1482,7 @@ class fulltext_native extends \phpbb\search\base switch ($this->db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $this->db->sql_query('DELETE FROM ' . SEARCH_WORDLIST_TABLE); $this->db->sql_query('DELETE FROM ' . SEARCH_WORDMATCH_TABLE); diff --git a/phpBB/phpbb/session.php b/phpBB/phpbb/session.php index f530d30f1f..ea421ffcf3 100644 --- a/phpBB/phpbb/session.php +++ b/phpBB/phpbb/session.php @@ -1045,8 +1045,9 @@ class session * @param string $name Name of the cookie, will be automatically prefixed with the phpBB cookie name. track becomes [cookie_name]_track then. * @param string $cookiedata The data to hold within the cookie * @param int $cookietime The expiration time as UNIX timestamp. If 0 is provided, a session cookie is set. + * @param bool $httponly Use HttpOnly. Defaults to true. Use false to make cookie accessible by client-side scripts. */ - function set_cookie($name, $cookiedata, $cookietime) + function set_cookie($name, $cookiedata, $cookietime, $httponly = true) { global $config; @@ -1054,7 +1055,7 @@ class session $expire = gmdate('D, d-M-Y H:i:s \\G\\M\\T', $cookietime); $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') ? '' : '; domain=' . $config['cookie_domain']; - header('Set-Cookie: ' . $name_data . (($cookietime) ? '; expires=' . $expire : '') . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . '; HttpOnly', false); + header('Set-Cookie: ' . $name_data . (($cookietime) ? '; expires=' . $expire : '') . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . ';' . (($httponly) ? ' HttpOnly' : ''), false); } /** diff --git a/phpBB/phpbb/template/twig/lexer.php b/phpBB/phpbb/template/twig/lexer.php index f4efc58540..49577f6e95 100644 --- a/phpBB/phpbb/template/twig/lexer.php +++ b/phpBB/phpbb/template/twig/lexer.php @@ -191,9 +191,16 @@ class lexer extends \Twig_Lexer $parent_class = $this; $callback = function ($matches) use ($parent_class, $parent_nodes) { - $name = $matches[1]; - $subset = trim(substr($matches[2], 1, -1)); // Remove parenthesis - $body = $matches[3]; + $hard_parents = explode('.', $matches[1]); + array_pop($hard_parents); // ends with . + if ($hard_parents) + { + $parent_nodes = array_merge($hard_parents, $parent_nodes); + } + + $name = $matches[2]; + $subset = trim(substr($matches[3], 1, -1)); // Remove parenthesis + $body = $matches[4]; // Replace <!-- BEGINELSE --> $body = str_replace('<!-- BEGINELSE -->', '{% else %}', $body); @@ -242,7 +249,7 @@ class lexer extends \Twig_Lexer return "{% for {$name} in {$parent}{$name}{$subset} %}{$body}{% endfor %}"; }; - return preg_replace_callback('#<!-- BEGIN ([!a-zA-Z0-9_]+)(\([0-9,\-]+\))? -->(.+?)<!-- END \1 -->#s', $callback, $code); + return preg_replace_callback('#<!-- BEGIN ((?:[a-zA-Z0-9_]+\.)*)([!a-zA-Z0-9_]+)(\([0-9,\-]+\))? -->(.+?)<!-- END \1\2 -->#s', $callback, $code); } /** diff --git a/phpBB/phpbb/user.php b/phpBB/phpbb/user.php index 18b7a3d096..f8e473dcad 100644 --- a/phpBB/phpbb/user.php +++ b/phpBB/phpbb/user.php @@ -69,7 +69,7 @@ class user extends \phpbb\session */ function setup($lang_set = false, $style_id = false) { - global $db, $template, $config, $auth, $phpEx, $phpbb_root_path, $cache; + global $db, $request, $template, $config, $auth, $phpEx, $phpbb_root_path, $cache; global $phpbb_dispatcher; if ($this->data['user_id'] != ANONYMOUS) @@ -80,7 +80,25 @@ class user extends \phpbb\session } else { - $user_lang_name = basename($config['default_lang']); + $lang_override = $request->variable('language', ''); + if ($lang_override) + { + $this->set_cookie('lang', $lang_override, 0, false); + } + else + { + $lang_override = $request->variable($config['cookie_name'] . '_lang', '', true, \phpbb\request\request_interface::COOKIE); + } + if ($lang_override) + { + $use_lang = basename($lang_override); + $user_lang_name = (file_exists($this->lang_path . $use_lang . "/common.$phpEx")) ? $use_lang : basename($config['default_lang']); + $this->data['user_lang'] = $user_lang_name; + } + else + { + $user_lang_name = basename($config['default_lang']); + } $user_date_format = $config['default_dateformat']; $user_timezone = $config['board_timezone']; @@ -190,7 +208,7 @@ class user extends \phpbb\session } unset($lang_set_ext); - $style_request = request_var('style', 0); + $style_request = $request->variable('style', 0); if ($style_request && (!$config['override_user_style'] || $auth->acl_get('a_styles')) && !defined('ADMIN_START')) { global $SID, $_EXTRA_URL; diff --git a/phpBB/search.php b/phpBB/search.php index dfb53c6896..7583cd9e10 100644 --- a/phpBB/search.php +++ b/phpBB/search.php @@ -635,12 +635,66 @@ if ($keywords || $author || $author_id || $search_id || $submit) } $db->sql_freeresult($result); - $sql = 'SELECT p.*, f.forum_id, f.forum_name, t.*, u.username, u.username_clean, u.user_sig, u.user_sig_bbcode_uid, u.user_colour - FROM ' . POSTS_TABLE . ' p - LEFT JOIN ' . TOPICS_TABLE . ' t ON (p.topic_id = t.topic_id) - LEFT JOIN ' . FORUMS_TABLE . ' f ON (p.forum_id = f.forum_id) - LEFT JOIN ' . USERS_TABLE . " u ON (p.poster_id = u.user_id) - WHERE $sql_where"; + $sql_array = array( + 'SELECT' => 'p.*, f.forum_id, f.forum_name, t.*, u.username, u.username_clean, u.user_sig, u.user_sig_bbcode_uid, u.user_colour', + 'FROM' => array( + POSTS_TABLE => 'p', + ), + 'LEFT_JOIN' => array( + array( + 'FROM' => array(TOPICS_TABLE => 't'), + 'ON' => 'p.topic_id = t.topic_id', + ), + array( + 'FROM' => array(FORUMS_TABLE => 'f'), + 'ON' => 'p.forum_id = f.forum_id', + ), + array( + 'FROM' => array(USERS_TABLE => 'u'), + 'ON' => 'p.poster_id = u.user_id', + ), + ), + 'WHERE' => $sql_where, + 'ORDER_BY' => $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'), + ); + + /** + * Event to modify the SQL query before the posts data is retrieved + * + * @event core.search_get_posts_data + * @var array sql_array The SQL array + * @var array zebra Array of zebra data for the current user + * @var int total_match_count The total number of search matches + * @var string keywords String of the specified keywords + * @var array sort_by_sql Array of SQL sorting instructions + * @var string s_sort_dir The sort direction + * @var string s_sort_key The sort key + * @var string s_limit_days Limit the age of results + * @var array ex_fid_ary Array of excluded forum ids + * @var array author_id_ary Array of exclusive author ids + * @var string search_fields The data fields to search in + * @var int search_id The id of the search request + * @var int start The starting id of the results + * @since 3.1.0-b3 + */ + $vars = array( + 'sql_array', + 'zebra', + 'total_match_count', + 'keywords', + 'sort_by_sql', + 's_sort_dir', + 's_sort_key', + 's_limit_days', + 'ex_fid_ary', + 'author_id_ary', + 'search_fields', + 'search_id', + 'start', + ); + extract($phpbb_dispatcher->trigger_event('core.search_get_posts_data', compact($vars))); + + $sql = $db->sql_build_query('SELECT', $sql_array); } else { @@ -689,8 +743,8 @@ if ($keywords || $author || $author_id || $search_id || $submit) $sql = "SELECT $sql_select FROM $sql_from WHERE $sql_where"; + $sql .= ' ORDER BY ' . $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'); } - $sql .= ' ORDER BY ' . $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'); $result = $db->sql_query($sql); $result_topic_id = 0; diff --git a/phpBB/styles/prosilver/template/ajax.js b/phpBB/styles/prosilver/template/ajax.js index bc68e5ae0c..e9f8064b9e 100644 --- a/phpBB/styles/prosilver/template/ajax.js +++ b/phpBB/styles/prosilver/template/ajax.js @@ -315,13 +315,17 @@ $('.poll_view_results a').click(function(e) { $('[data-ajax]').each(function() { var $this = $(this), ajax = $this.attr('data-ajax'), + filter = $this.attr('data-filter'), fn; if (ajax !== 'false') { fn = (ajax !== 'true') ? ajax : null; + filter = (filter !== undefined) ? phpbb.getFunctionByName(filter) : null; + phpbb.ajaxify({ selector: this, refresh: $this.attr('data-refresh') !== undefined, + filter: filter, callback: fn }); } diff --git a/phpBB/styles/prosilver/template/index_body.html b/phpBB/styles/prosilver/template/index_body.html index 3e9aae28e3..f9c5b4cf20 100644 --- a/phpBB/styles/prosilver/template/index_body.html +++ b/phpBB/styles/prosilver/template/index_body.html @@ -48,22 +48,34 @@ <!-- IF S_DISPLAY_ONLINE_LIST --> <div class="stat-block online-list"> <!-- IF U_VIEWONLINE --><h3><a href="{U_VIEWONLINE}">{L_WHO_IS_ONLINE}</a></h3><!-- ELSE --><h3>{L_WHO_IS_ONLINE}</h3><!-- ENDIF --> - <p>{TOTAL_USERS_ONLINE} ({L_ONLINE_EXPLAIN})<br />{RECORD_USERS}<br /> <br />{LOGGED_IN_USER_LIST} - <!-- IF LEGEND --><br /><em>{L_LEGEND}{L_COLON} {LEGEND}</em><!-- ENDIF --></p> + <p> + <!-- EVENT index_body_block_online_prepend --> + {TOTAL_USERS_ONLINE} ({L_ONLINE_EXPLAIN})<br />{RECORD_USERS}<br /> <br />{LOGGED_IN_USER_LIST} + <!-- IF LEGEND --><br /><em>{L_LEGEND}{L_COLON} {LEGEND}</em><!-- ENDIF --> + <!-- EVENT index_body_block_online_append --> + </p> </div> <!-- ENDIF --> <!-- IF S_DISPLAY_BIRTHDAY_LIST --> <div class="stat-block birthday-list"> <h3>{L_BIRTHDAYS}</h3> - <p><!-- IF .birthdays -->{L_CONGRATULATIONS}{L_COLON} <strong><!-- BEGIN birthdays -->{birthdays.USERNAME}<!-- IF birthdays.AGE !== '' --> ({birthdays.AGE})<!-- ENDIF --><!-- IF not birthdays.S_LAST_ROW -->, <!-- ENDIF --><!-- END birthdays --></strong><!-- ELSE -->{L_NO_BIRTHDAYS}<!-- ENDIF --></p> + <p> + <!-- EVENT index_body_block_birthday_prepend --> + <!-- IF .birthdays -->{L_CONGRATULATIONS}{L_COLON} <strong><!-- BEGIN birthdays -->{birthdays.USERNAME}<!-- IF birthdays.AGE !== '' --> ({birthdays.AGE})<!-- ENDIF --><!-- IF not birthdays.S_LAST_ROW -->, <!-- ENDIF --><!-- END birthdays --></strong><!-- ELSE -->{L_NO_BIRTHDAYS}<!-- ENDIF --> + <!-- EVENT index_body_block_birthday_append --> + </p> </div> <!-- ENDIF --> <!-- IF NEWEST_USER --> <div class="stat-block statistics"> <h3>{L_STATISTICS}</h3> - <p>{TOTAL_POSTS} • {TOTAL_TOPICS} • {TOTAL_USERS} • {NEWEST_USER}</p> + <p> + <!-- EVENT index_body_block_stats_prepend --> + {TOTAL_POSTS} • {TOTAL_TOPICS} • {TOTAL_USERS} • {NEWEST_USER} + <!-- EVENT index_body_block_stats_append --> + </p> </div> <!-- ENDIF --> diff --git a/phpBB/styles/prosilver/template/memberlist_search.html b/phpBB/styles/prosilver/template/memberlist_search.html index ee89b103b5..f4439b6934 100644 --- a/phpBB/styles/prosilver/template/memberlist_search.html +++ b/phpBB/styles/prosilver/template/memberlist_search.html @@ -7,9 +7,21 @@ <p>{L_FIND_USERNAME_EXPLAIN}</p> <fieldset class="fields1 column1"> - <dl> + <dl style="overflow: visible;"> <dt><label for="username">{L_USERNAME}{L_COLON}</label></dt> - <dd><input type="text" name="username" id="username" value="{USERNAME}" class="inputbox" /></dd> + <dd> + <input type="text" name="username" id="username" value="{USERNAME}" class="inputbox"<!-- IF U_LIVE_SEARCH --> autocomplete="off" data-filter="phpbb.search.filter" data-ajax="member_search" data-min-length="3" data-url="{U_LIVE_SEARCH}" data-results="#user-search" data-overlay="false"<!-- ENDIF --> /> + <!-- IF U_LIVE_SEARCH --> + <div class="dropdown-container"> + <div class="dropdown live-search hidden" id="user-search"> + <div class="pointer"><div class="pointer-inner"></div></div> + <ul class="dropdown-contents search-results"> + <li class="search-result-tpl"><span class="search-result"></span></li> + </ul> + </div> + </div> + <!-- ENDIF --> + </dd> </dl> <!-- IF S_EMAIL_SEARCH_ALLOWED --> <dl> diff --git a/phpBB/styles/prosilver/template/memberlist_view.html b/phpBB/styles/prosilver/template/memberlist_view.html index 3ef3f7ca07..a8b1e972fe 100644 --- a/phpBB/styles/prosilver/template/memberlist_view.html +++ b/phpBB/styles/prosilver/template/memberlist_view.html @@ -2,6 +2,8 @@ <h2 class="memberlist-title">{PAGE_TITLE}</h2> +<!-- EVENT memberlist_view_content_prepend --> + <form method="post" action="{S_PROFILE_ACTION}" id="viewprofile"> <div class="panel bg1<!-- IF S_ONLINE --> online<!-- ENDIF -->"> <div class="inner"> diff --git a/phpBB/styles/prosilver/template/navbar_header.html b/phpBB/styles/prosilver/template/navbar_header.html index 7fbaa1254f..2347b044a3 100644 --- a/phpBB/styles/prosilver/template/navbar_header.html +++ b/phpBB/styles/prosilver/template/navbar_header.html @@ -6,7 +6,7 @@ <li class="small-icon icon-home breadcrumbs"> <!-- IF U_SITE_HOME --><span class="crumb"><a href="{U_SITE_HOME}"{$MICRODATA}>{L_SITE_HOME}</a></span><!-- ENDIF --> <span class="crumb"><a href="{U_INDEX}" accesskey="h"{$MICRODATA}>{L_INDEX}</a></span> - <!-- BEGIN navlinks --><span class="crumb"><a href="{navlinks.U_VIEW_FORUM}"{$MICRODATA}>{navlinks.FORUM_NAME}</a></span><!-- END navlinks --> + <!-- BEGIN navlinks --><!-- EVENT overall_header_navlink_prepend --><span class="crumb"><a href="{navlinks.U_VIEW_FORUM}"{$MICRODATA}>{navlinks.FORUM_NAME}</a></span><!-- EVENT overall_header_navlink_append --><!-- END navlinks --> <!-- EVENT overall_header_breadcrumb_append --> </li> diff --git a/phpBB/styles/prosilver/template/search_results.html b/phpBB/styles/prosilver/template/search_results.html index 818b8ee642..fe0b0362ce 100644 --- a/phpBB/styles/prosilver/template/search_results.html +++ b/phpBB/styles/prosilver/template/search_results.html @@ -113,6 +113,7 @@ <!-- ELSE --> <!-- BEGIN searchresults --> + <!-- EVENT search_results_post_before --> <div class="search post <!-- IF searchresults.S_ROW_COUNT is odd -->bg1<!-- ELSE -->bg2<!-- ENDIF --><!-- IF searchresults.S_POST_REPORTED --> reported<!-- ENDIF -->"> <div class="inner"> @@ -122,12 +123,14 @@ </div> <!-- ELSE --> <dl class="postprofile"> + <!-- EVENT search_results_postprofile_before --> <dt class="author">{L_POST_BY_AUTHOR} {searchresults.POST_AUTHOR_FULL}</dt> <dd class="search-result-date">{searchresults.POST_DATE}</dd> <dd>{L_FORUM}{L_COLON} <a href="{searchresults.U_VIEW_FORUM}">{searchresults.FORUM_TITLE}</a></dd> <dd>{L_TOPIC}{L_COLON} <a href="{searchresults.U_VIEW_TOPIC}">{searchresults.TOPIC_TITLE}</a></dd> <dd>{L_REPLIES}{L_COLON} <strong>{searchresults.TOPIC_REPLIES}</strong></dd> <dd>{L_VIEWS}{L_COLON} <strong>{searchresults.TOPIC_VIEWS}</strong></dd> + <!-- EVENT search_results_postprofile_after --> </dl> <div class="postbody"> @@ -144,6 +147,7 @@ </div> </div> + <!-- EVENT search_results_post_after --> <!-- BEGINELSE --> <div class="panel"> <div class="inner"> diff --git a/phpBB/styles/prosilver/template/simple_footer.html b/phpBB/styles/prosilver/template/simple_footer.html index 10edece3cd..02e24ab796 100644 --- a/phpBB/styles/prosilver/template/simple_footer.html +++ b/phpBB/styles/prosilver/template/simple_footer.html @@ -4,11 +4,27 @@ <!-- IF TRANSLATION_INFO --><br />{TRANSLATION_INFO}<!-- ENDIF --> <!-- IF DEBUG_OUTPUT --><br />{DEBUG_OUTPUT}<!-- ENDIF --> </div> + + <div id="darkenwrapper" data-ajax-error-title="{L_AJAX_ERROR_TITLE}" data-ajax-error-text="{L_AJAX_ERROR_TEXT}" data-ajax-error-text-abort="{L_AJAX_ERROR_TEXT_ABORT}" data-ajax-error-text-timeout="{L_AJAX_ERROR_TEXT_TIMEOUT}" data-ajax-error-text-parsererror="{L_AJAX_ERROR_TEXT_PARSERERROR}"> + <div id="darken"> </div> + </div> + <div id="loading_indicator"></div> + + <div id="phpbb_alert" class="phpbb_alert" data-l-err="{L_ERROR}" data-l-timeout-processing-req="{L_TIMEOUT_PROCESSING_REQ}"> + <a href="#" class="alert_close"></a> + <h3 class="alert_title"></h3><p class="alert_text"></p> + </div> + <div id="phpbb_confirm" class="phpbb_alert"> + <a href="#" class="alert_close"></a> + <div class="alert_text"></div> + </div> </div> <script type="text/javascript" src="{T_JQUERY_LINK}"></script> <!-- IF S_ALLOW_CDN --><script type="text/javascript">window.jQuery || document.write(unescape('%3Cscript src="{T_ASSETS_PATH}/javascript/jquery.js?assets_version={T_ASSETS_VERSION}" type="text/javascript"%3E%3C/script%3E'));</script><!-- ENDIF --> +<script type="text/javascript" src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script> <!-- INCLUDEJS forum_fn.js --> +<!-- INCLUDEJS ajax.js --> <!-- EVENT simple_footer_after --> diff --git a/phpBB/styles/prosilver/template/ucp_agreement.html b/phpBB/styles/prosilver/template/ucp_agreement.html index b52acdd955..bc4f23cee7 100644 --- a/phpBB/styles/prosilver/template/ucp_agreement.html +++ b/phpBB/styles/prosilver/template/ucp_agreement.html @@ -10,6 +10,7 @@ */ function change_language(lang_iso) { + document.cookie = '{COOKIE_NAME}_lang=' + lang_iso + '; path={COOKIE_PATH}'; document.forms['register'].change_lang.value = lang_iso; document.forms['register'].submit(); } diff --git a/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html b/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html index f14e4708e7..81171e97b2 100644 --- a/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html +++ b/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html @@ -33,27 +33,33 @@ <!-- END custom_fields --> <!-- EVENT ucp_pm_viewmessage_custom_fields_after --> - - <!-- IF U_PM or U_EMAIL or U_JABBER --> - <dd class="profile-contact"> - <ul class="profile-icons"> - <!-- EVENT ucp_pm_viewmessage_contact_fields_before --> - <!-- IF U_PM --><li class="pm-icon"><a href="{U_PM}" title="{L_PRIVATE_MESSAGE}"><span>{L_PRIVATE_MESSAGE}</span></a></li><!-- ENDIF --> - <!-- IF U_EMAIL --><li class="email-icon"><a href="{U_EMAIL}" title="{L_SEND_EMAIL_USER} {MESSAGE_AUTHOR}"><span>{L_SEND_EMAIL_USER} {MESSAGE_AUTHOR}</span></a></li><!-- ENDIF --> - <!-- IF U_JABBER --><li class="jabber-icon"><a href="{U_JABBER}" onclick="popup(this.href, 550, 320); return false;" title="{L_JABBER}"><span>{L_JABBER}</span></a></li><!-- ENDIF --> - <!-- BEGIN custom_fields --> - <!-- IF custom_fields.S_PROFILE_CONTACT --> - <li class="{custom_fields.PROFILE_FIELD_IDENT}-icon"> - <a href="<!-- IF custom_fields.PROFILE_FIELD_CONTACT -->{custom_fields.PROFILE_FIELD_CONTACT}<!-- ELSE -->{U_MESSAGE_AUTHOR}<!-- ENDIF -->"> - <span>{custom_fields.PROFILE_FIELD_NAME}</span> - </a> - </li> - <!-- ENDIF --> - <!-- END custom_fields --> - <!-- EVENT ucp_pm_viewmessage_contact_fields_after --> - </ul> - </dd> + <!-- EVENT ucp_pm_viewmessage_contact_fields_before --> + <!-- IF .contact --> + <dd class="profile-contact"> + <strong>{L_CONTACT_USER}{L_COLON}</strong> + <div class="dropdown-container dropdown-left"> + <a href="#" class="dropdown-trigger"><span class="imageset icon_contact"></span></a> + <div class="dropdown hidden"> + <div class="pointer"><div class="pointer-inner"></div></div> + <div class="dropdown-contents contact-icons"> + <!-- BEGIN contact --> + {% set REMAINDER = contact.S_ROW_COUNT % 4 %} + <!-- DEFINE $S_LAST_CELL = ((REMAINDER eq 3) or (contact.S_LAST_ROW and contact.S_NUM_ROWS < 4)) --> + <!-- IF REMAINDER eq 0 --> + <div> + <!-- ENDIF --> + <a href="<!-- IF contact.U_CONTACT -->{contact.U_CONTACT}<!-- ELSE -->{contact.U_PROFILE_AUTHOR}<!-- ENDIF -->" title="{contact.NAME}"<!-- IF $S_LAST_CELL --> class="last-cell"<!-- ENDIF --><!-- IF contact.ID eq 'jabber' --> onclick="popup(this.href, 550, 320); return false;"<!-- ENDIF -->> + <span class="contact-icon {contact.ID}-icon"></span> + </a> + <!-- IF REMAINDER eq 3 or contact.S_LAST_ROW --> + </div> + <!-- ENDIF --> + <!-- END contact --> + </div> + </div> + </dd> <!-- ENDIF --> + <!-- EVENT ucp_pm_viewmessage_contact_fields_after --> </dl> <div class="postbody"> diff --git a/phpBB/styles/prosilver/template/ucp_register.html b/phpBB/styles/prosilver/template/ucp_register.html index fc469eff36..b27003faab 100644 --- a/phpBB/styles/prosilver/template/ucp_register.html +++ b/phpBB/styles/prosilver/template/ucp_register.html @@ -7,6 +7,7 @@ */ function change_language(lang_iso) { + document.cookie = '{COOKIE_NAME}_lang=' + lang_iso + '; path={COOKIE_PATH}'; document.forms['register'].change_lang.value = lang_iso; document.forms['register'].submit.click(); } diff --git a/phpBB/styles/prosilver/template/viewforum_body.html b/phpBB/styles/prosilver/template/viewforum_body.html index 33d309bcb8..6646f40f01 100644 --- a/phpBB/styles/prosilver/template/viewforum_body.html +++ b/phpBB/styles/prosilver/template/viewforum_body.html @@ -1,6 +1,6 @@ <!-- INCLUDE overall_header.html --> <!-- IF U_MCP or U_ACP --><p class="responsive-center">[ <!-- IF U_ACP --><a href="{U_ACP}" title="{L_ACP}" data-responsive-text="{L_ACP_SHORT}">{L_ACP}</a><!-- IF U_MCP --> | <!-- ENDIF --><!-- ENDIF --><!-- IF U_MCP --><a href="{U_MCP}" title="{L_MCP}" data-responsive-text="{L_MCP_SHORT}">{L_MCP}</a><!-- ENDIF --> ]</p><!-- ENDIF --> -<h2 class="forum-title"><a href="{U_VIEW_FORUM}">{FORUM_NAME}</a></h2> +<h2 class="forum-title"><!-- EVENT viewforum_forum_name_prepend --><a href="{U_VIEW_FORUM}">{FORUM_NAME}</a><!-- EVENT viewforum_forum_name_append --></h2> <!-- IF FORUM_DESC or MODERATORS or U_MCP --> <div> diff --git a/phpBB/styles/prosilver/template/viewtopic_body.html b/phpBB/styles/prosilver/template/viewtopic_body.html index 01a49d6888..ed45835da6 100644 --- a/phpBB/styles/prosilver/template/viewtopic_body.html +++ b/phpBB/styles/prosilver/template/viewtopic_body.html @@ -1,6 +1,6 @@ <!-- INCLUDE overall_header.html --> <!-- IF U_MCP or U_ACP --><p class="responsive-center">[ <!-- IF U_ACP --><a href="{U_ACP}" title="{L_ACP}" data-responsive-text="{L_ACP_SHORT}">{L_ACP}</a><!-- IF U_MCP --> | <!-- ENDIF --><!-- ENDIF --><!-- IF U_MCP --><a href="{U_MCP}" title="{L_MCP}" data-responsive-text="{L_MCP_SHORT}">{L_MCP}</a><!-- ENDIF --> ]</p><!-- ENDIF --> -<h2 class="topic-title"><!-- EVENT viewtopic_topic_title_prepend --><a href="{U_VIEW_TOPIC}">{TOPIC_TITLE}</a></h2> +<h2 class="topic-title"><!-- EVENT viewtopic_topic_title_prepend --><a href="{U_VIEW_TOPIC}">{TOPIC_TITLE}</a><!-- EVENT viewtopic_topic_title_append --></h2> <!-- NOTE: remove the style="display: none" when you want to have the forum description on the topic body --> <!-- IF FORUM_DESC --><div style="display: none !important;">{FORUM_DESC}<br /></div><!-- ENDIF --> @@ -67,17 +67,19 @@ <div class="inner"> <div class="content"> - <h2 class="poll-title">{POLL_QUESTION}</h2> + <h2 class="poll-title"><!-- EVENT viewtopic_body_poll_question_prepend -->{POLL_QUESTION}<!-- EVENT viewtopic_body_poll_question_append --></h2> <p class="author">{L_POLL_LENGTH}<!-- IF S_CAN_VOTE and L_POLL_LENGTH --><br /><!-- ENDIF --><!-- IF S_CAN_VOTE --><span class="poll_max_votes">{L_MAX_VOTES}</span><!-- ENDIF --></p> <fieldset class="polls"> <!-- BEGIN poll_option --> + <!-- EVENT viewtopic_body_poll_option_before --> <dl class="<!-- IF poll_option.POLL_OPTION_VOTED -->voted<!-- ENDIF --><!-- IF poll_option.POLL_OPTION_MOST_VOTES --> most-votes<!-- ENDIF -->"<!-- IF poll_option.POLL_OPTION_VOTED --> title="{L_POLL_VOTED_OPTION}"<!-- ENDIF --> data-poll-option-id="{poll_option.POLL_OPTION_ID}"> <dt><!-- IF S_CAN_VOTE --><label for="vote_{poll_option.POLL_OPTION_ID}">{poll_option.POLL_OPTION_CAPTION}</label><!-- ELSE -->{poll_option.POLL_OPTION_CAPTION}<!-- ENDIF --></dt> <!-- IF S_CAN_VOTE --><dd style="width: auto;" class="poll_option_select"><!-- IF S_IS_MULTI_CHOICE --><input type="checkbox" name="vote_id[]" id="vote_{poll_option.POLL_OPTION_ID}" value="{poll_option.POLL_OPTION_ID}"<!-- IF poll_option.POLL_OPTION_VOTED --> checked="checked"<!-- ENDIF --> /><!-- ELSE --><input type="radio" name="vote_id[]" id="vote_{poll_option.POLL_OPTION_ID}" value="{poll_option.POLL_OPTION_ID}"<!-- IF poll_option.POLL_OPTION_VOTED --> checked="checked"<!-- ENDIF --> /><!-- ENDIF --></dd><!-- ENDIF --> <dd class="resultbar<!-- IF not S_DISPLAY_RESULTS --> hidden<!-- ENDIF -->"><div class="<!-- IF poll_option.POLL_OPTION_PCT < 20 -->pollbar1<!-- ELSEIF poll_option.POLL_OPTION_PCT < 40 -->pollbar2<!-- ELSEIF poll_option.POLL_OPTION_PCT < 60 -->pollbar3<!-- ELSEIF poll_option.POLL_OPTION_PCT < 80 -->pollbar4<!-- ELSE -->pollbar5<!-- ENDIF -->" style="width:{poll_option.POLL_OPTION_PERCENT_REL};">{poll_option.POLL_OPTION_RESULT}</div></dd> <dd class="poll_option_percent<!-- IF not S_DISPLAY_RESULTS --> hidden<!-- ENDIF -->"><!-- IF poll_option.POLL_OPTION_RESULT == 0 -->{L_NO_VOTES}<!-- ELSE -->{poll_option.POLL_OPTION_PERCENT}<!-- ENDIF --></dd> </dl> + <!-- EVENT viewtopic_body_poll_option_after --> <!-- END poll_option --> <dl class="poll_total_votes<!-- IF not S_DISPLAY_RESULTS --> hidden<!-- ENDIF -->"> @@ -143,26 +145,34 @@ <!-- END custom_fields --> <!-- EVENT viewtopic_body_postrow_custom_fields_after --> - <!-- IF not S_IS_BOT --> - <!-- IF postrow.U_PM or postrow.U_EMAIL or postrow.U_JABBER --> + <!-- EVENT viewtopic_body_contact_fields_before --> + <!-- IF not S_IS_BOT and .postrow.contact --> <dd class="profile-contact"> - <ul class="profile-icons"> - <!-- IF postrow.U_PM --><li class="pm-icon"><a href="{postrow.U_PM}" title="{L_PRIVATE_MESSAGE}"><span>{L_PRIVATE_MESSAGE}</span></a></li><!-- ENDIF --> - <!-- IF postrow.U_EMAIL --><li class="email-icon"><a href="{postrow.U_EMAIL}" title="{L_SEND_EMAIL_USER} {postrow.POST_AUTHOR}"><span>{L_SEND_EMAIL_USER} {postrow.POST_AUTHOR}</span></a></li><!-- ENDIF --> - <!-- IF postrow.U_JABBER --><li class="jabber-icon"><a href="{postrow.U_JABBER}" onclick="popup(this.href, 550, 320); return false;" title="{L_JABBER}"><span>{L_JABBER}</span></a></li><!-- ENDIF --> - <!-- BEGIN custom_fields --> - <!-- IF postrow.custom_fields.S_PROFILE_CONTACT --> - <li class="{postrow.custom_fields.PROFILE_FIELD_IDENT}-icon"> - <a href="<!-- IF postrow.custom_fields.PROFILE_FIELD_CONTACT -->{postrow.custom_fields.PROFILE_FIELD_CONTACT}<!-- ELSE -->{postrow.U_POST_AUTHOR}<!-- ENDIF -->"> - <span>{postrow.custom_fields.PROFILE_FIELD_NAME}</span> - </a> - </li> - <!-- ENDIF --> - <!-- END custom_fields --> - </ul> + <strong>{L_CONTACT_USER}{L_COLON}</strong> + <div class="dropdown-container dropdown-left"> + <a href="#" class="dropdown-trigger"><span class="imageset icon_contact"></span></a> + <div class="dropdown hidden"> + <div class="pointer"><div class="pointer-inner"></div></div> + <div class="dropdown-contents contact-icons"> + <!-- BEGIN contact --> + {% set REMAINDER = postrow.contact.S_ROW_COUNT % 4 %} + <!-- DEFINE $S_LAST_CELL = ((REMAINDER eq 3) or (postrow.contact.S_LAST_ROW and postrow.contact.S_NUM_ROWS < 4)) --> + <!-- IF REMAINDER eq 0 --> + <div> + <!-- ENDIF --> + <a href="<!-- IF postrow.contact.U_CONTACT -->{postrow.contact.U_CONTACT}<!-- ELSE -->{postrow.contact.U_PROFILE_AUTHOR}<!-- ENDIF -->" title="{postrow.contact.NAME}"<!-- IF $S_LAST_CELL --> class="last-cell"<!-- ENDIF --><!-- IF postrow.contact.ID eq 'jabber' --> onclick="popup(this.href, 550, 320); return false;"<!-- ENDIF -->> + <span class="contact-icon {postrow.contact.ID}-icon"></span> + </a> + <!-- IF REMAINDER eq 3 or postrow.contact.S_LAST_ROW --> + </div> + <!-- ENDIF --> + <!-- END contact --> + </div> + </div> + </div> </dd> <!-- ENDIF --> - <!-- ENDIF --> + <!-- EVENT viewtopic_body_contact_fields_after --> </dl> diff --git a/phpBB/styles/prosilver/theme/buttons.css b/phpBB/styles/prosilver/theme/buttons.css index 3422af8b64..9ca04516cc 100644 --- a/phpBB/styles/prosilver/theme/buttons.css +++ b/phpBB/styles/prosilver/theme/buttons.css @@ -214,20 +214,53 @@ ul.profile-icons.responsive a.responsive-menu-link:before { max-width: 40%; } +.contact-icons.dropdown-contents { + min-width: 0; + padding: 0; +} + +.contact-icon { + background-repeat: no-repeat; + display: block; + height: 16px; + width: 16px; +} +.contact-icons a { + border-bottom: 1px dotted; + border-right: 1px dotted; + display: block; + float: left; + padding: 8px; +} + +.contact-icons .last-cell { + border-right: none; +} + +.contact-icons div:last-child a { + border-bottom: none; +} + +.contact-icons div { + clear: left; +} + + /* Profile & navigation icons */ -.email-icon, .email-icon a { background: none top left no-repeat; } -.aim-icon, .aim-icon a { background: none top left no-repeat; } -.phpbb_aol-icon, .phpbb_aol-icon a { background: none top left no-repeat; } -.yahoo-icon, .yahoo-icon a { background: none top left no-repeat; } -.phpbb_yahoo-icon, .phpbb_yahoo-icon a { background: none top left no-repeat; } -.web-icon, .web-icon a { background: none top left no-repeat; } -.phpbb_website-icon, .phpbb_website-icon a { background: none top left no-repeat; } -.msnm-icon, .msnm-icon a { background: none top left no-repeat; } -.phpbb_wlm-icon, .phpbb_wlm-icon a { background: none top left no-repeat; } -.icq-icon, .icq-icon a { background: none top left no-repeat; } -.phpbb_icq-icon, .phpbb_icq-icon a { background: none top left no-repeat; } -.jabber-icon, .jabber-icon a { background: none top left no-repeat; } -.pm-icon, .pm-icon a { background: none top left no-repeat; } +.pm-icon { background-position: 0 0; } +.email-icon { background-position: -21px 0; } +.jabber-icon { background-position: -80px 0; } +.phpbb_icq-icon { background-position: -61px 0 ; } +.phpbb_wlm-icon { background-position: -182px 0; } +.phpbb_aol-icon { background-position: -244px 0; } +.phpbb_website-icon { background-position: -40px 0; } +.phpbb_youtube-icon { background-position: -98px 0; } +.phpbb_facebook-icon { background-position: -119px 0; } +.phpbb_google_plus-icon { background-position: -140px 0; } +.phpbb_skype-icon { background-position: -161px 0; } +.phpbb_twitter-icon { background-position: -203px 0; } +.phpbb_yahoo-icon { background-position: -224px 0; } + .quote-icon, .quote-icon a { background: none top left no-repeat; } /* Moderator icons */ diff --git a/phpBB/styles/prosilver/theme/colours.css b/phpBB/styles/prosilver/theme/colours.css index 30650e7411..39f28b4774 100644 --- a/phpBB/styles/prosilver/theme/colours.css +++ b/phpBB/styles/prosilver/theme/colours.css @@ -710,6 +710,14 @@ Colours and backgrounds for buttons.css background-image: url("images/buttons.png"); } +.contact-icons a { + border-color: #DCDCDC; +} + +.contact-icons a:hover { + background-color: #F2F6F9; +} + /* Icon images ---------------------------------------- */ .icon-faq { background-image: url("./images/icon_faq.gif"); } @@ -732,19 +740,8 @@ Colours and backgrounds for buttons.css .icon-print { background-image: url("./images/icon_print.gif"); } /* Profile & navigation icons */ -.email-icon, .email-icon a { background-image: url("./images/icon_contact_email.gif"); } -.phpbb_aol-icon, .phpbb_aol-icon a { background-image: url("./images/icon_contact_aim.gif"); } -.aim-icon, .aim-icon a { background-image: url("./images/icon_contact_aim.gif"); } -.yahoo-icon, .yahoo-icon a { background-image: url("./images/icon_contact_yahoo.gif"); } -.phpbb_yahoo-icon, .phpbb_yahoo-icon a { background-image: url("./images/icon_contact_yahoo.gif"); } -.web-icon, .web-icon a { background-image: url("./images/icon_contact_www.gif"); } -.phpbb_website-icon, .phpbb_website-icon a { background-image: url("./images/icon_contact_www.gif"); } -.msnm-icon, .msnm-icon a { background-image: url("./images/icon_contact_msnm.gif"); } -.phpbb_wlm-icon, .phpbb_wlm-icon a { background-image: url("./images/icon_contact_msnm.gif"); } -.icq-icon, .icq-icon a { background-image: url("./images/icon_contact_icq.gif"); } -.phpbb_icq-icon, .phpbb_icq-icon a { background-image: url("./images/icon_contact_icq.gif"); } -.jabber-icon, .jabber-icon a { background-image: url("./images/icon_contact_jabber.gif"); } -.pm-icon, .pm-icon a { background-image: url("./en/icon_contact_pm.gif"); } +.contact-icon { background-image: url("./images/icons_contact.png"); } + .quote-icon, .quote-icon a { background-image: url("./en/icon_post_quote.gif"); } ul.profile-icons.responsive a.responsive-menu-link { background-image: url("./images/icon_post_menu.png"); } diff --git a/phpBB/styles/prosilver/theme/common.css b/phpBB/styles/prosilver/theme/common.css index 3d5a0a433d..94fad55ae9 100644 --- a/phpBB/styles/prosilver/theme/common.css +++ b/phpBB/styles/prosilver/theme/common.css @@ -261,7 +261,6 @@ a#logo:hover { } .navbar { - padding: 0 10px; padding: 5px 10px 5px 10px; border-radius: 7px; } @@ -470,6 +469,11 @@ ul.linklist.bulletin li.no-bulletin:before { border: 1px solid transparent; border-radius: 5px; padding: 9px 0 0; + margin-right: -500px; +} + +.dropdown.live-search { + top: auto; } .dropdown-container.topic-tools { @@ -485,6 +489,8 @@ ul.linklist.bulletin li.no-bulletin:before { .dropdown-left .dropdown, .nojs .rightside .dropdown { left: auto; right: 0; + margin-left: -500px; + margin-right: 0; } .dropdown-button-control .dropdown { diff --git a/phpBB/styles/prosilver/theme/content.css b/phpBB/styles/prosilver/theme/content.css index d27fb81fee..dc6ab9aef3 100644 --- a/phpBB/styles/prosilver/theme/content.css +++ b/phpBB/styles/prosilver/theme/content.css @@ -731,6 +731,20 @@ fieldset.polls dd div { height: auto !important; } +dd.profile-contact { + overflow: visible; +} + +.profile-contact .dropdown-container { + display: inline-block; + text-align: left; + width: 30px; +} + +.profile-contact .icon_contact { + vertical-align: middle; +} + .online { background-image: none; background-position: 100% 0; diff --git a/phpBB/styles/prosilver/theme/en/stylesheet.css b/phpBB/styles/prosilver/theme/en/stylesheet.css index 82b7df0830..d8ca2558e5 100644 --- a/phpBB/styles/prosilver/theme/en/stylesheet.css +++ b/phpBB/styles/prosilver/theme/en/stylesheet.css @@ -7,16 +7,10 @@ ul.profile-icons li.edit-icon { width: 42px; height: 20px; } .online { background-image: url("./icon_user_online.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"); } .edit-icon, .edit-icon a { background-image: url("./icon_post_edit.gif"); } /* EN Language Pack */ -.imageset.icon_contact_pm { - background-image: url("./icon_contact_pm.gif"); - padding-left: 28px; - padding-top: 20px; -} .imageset.icon_post_edit { background-image: url("./icon_post_edit.gif"); padding-left: 42px; diff --git a/phpBB/styles/prosilver/theme/forms.css b/phpBB/styles/prosilver/theme/forms.css index 88f2bd65c5..0c0a3e5ca9 100644 --- a/phpBB/styles/prosilver/theme/forms.css +++ b/phpBB/styles/prosilver/theme/forms.css @@ -96,7 +96,7 @@ fieldset.fields1 div { } /* Set it back to 0px for the reCaptcha divs: PHPBB3-9587 */ -fieldset.fields1 #recaptcha_widget_div div { +fieldset.fields1 #recaptcha_widget_div div, fieldset.fields1 .live-search div { margin-bottom: 0; } diff --git a/phpBB/styles/prosilver/theme/images/icon_contact.png b/phpBB/styles/prosilver/theme/images/icon_contact.png Binary files differnew file mode 100644 index 0000000000..04e4d9ad17 --- /dev/null +++ b/phpBB/styles/prosilver/theme/images/icon_contact.png diff --git a/phpBB/styles/prosilver/theme/images/icon_contact_aim.gif b/phpBB/styles/prosilver/theme/images/icon_contact_aim.gif Binary files differdeleted file mode 100644 index be039fcde2..0000000000 --- a/phpBB/styles/prosilver/theme/images/icon_contact_aim.gif +++ /dev/null diff --git a/phpBB/styles/prosilver/theme/images/icon_contact_email.gif b/phpBB/styles/prosilver/theme/images/icon_contact_email.gif Binary files differdeleted file mode 100644 index caa3683005..0000000000 --- a/phpBB/styles/prosilver/theme/images/icon_contact_email.gif +++ /dev/null diff --git a/phpBB/styles/prosilver/theme/images/icon_contact_icq.gif b/phpBB/styles/prosilver/theme/images/icon_contact_icq.gif Binary files differdeleted file mode 100644 index 48a09373eb..0000000000 --- a/phpBB/styles/prosilver/theme/images/icon_contact_icq.gif +++ /dev/null diff --git a/phpBB/styles/prosilver/theme/images/icon_contact_jabber.gif b/phpBB/styles/prosilver/theme/images/icon_contact_jabber.gif Binary files differdeleted file mode 100644 index e335433e97..0000000000 --- a/phpBB/styles/prosilver/theme/images/icon_contact_jabber.gif +++ /dev/null diff --git a/phpBB/styles/prosilver/theme/images/icon_contact_msnm.gif b/phpBB/styles/prosilver/theme/images/icon_contact_msnm.gif Binary files differdeleted file mode 100644 index e25469c3a5..0000000000 --- a/phpBB/styles/prosilver/theme/images/icon_contact_msnm.gif +++ /dev/null diff --git a/phpBB/styles/prosilver/theme/images/icon_contact_www.gif b/phpBB/styles/prosilver/theme/images/icon_contact_www.gif Binary files differdeleted file mode 100644 index 83cee9728d..0000000000 --- a/phpBB/styles/prosilver/theme/images/icon_contact_www.gif +++ /dev/null diff --git a/phpBB/styles/prosilver/theme/images/icon_contact_yahoo.gif b/phpBB/styles/prosilver/theme/images/icon_contact_yahoo.gif Binary files differdeleted file mode 100644 index 305f297fdb..0000000000 --- a/phpBB/styles/prosilver/theme/images/icon_contact_yahoo.gif +++ /dev/null diff --git a/phpBB/styles/prosilver/theme/images/icons_contact.png b/phpBB/styles/prosilver/theme/images/icons_contact.png Binary files differnew file mode 100644 index 0000000000..f84abd36a5 --- /dev/null +++ b/phpBB/styles/prosilver/theme/images/icons_contact.png diff --git a/phpBB/styles/prosilver/theme/imageset.css b/phpBB/styles/prosilver/theme/imageset.css index e6d306c7fd..6bc345889e 100644 --- a/phpBB/styles/prosilver/theme/imageset.css +++ b/phpBB/styles/prosilver/theme/imageset.css @@ -356,13 +356,14 @@ span.imageset { padding-top: 20px; } +.imageset.icon_contact { + background-image: url("./images/icon_contact.png"); + padding-left: 16px; + padding-top: 12px; +} + /* English images for fallback */ -.imageset.icon_contact_pm { - background-image: url("./en/icon_contact_pm.gif"); - padding-left: 28px; - padding-top: 20px; -} .imageset.icon_post_edit { background-image: url("./en/icon_post_edit.gif"); padding-left: 42px; diff --git a/phpBB/styles/subsilver2/template/breadcrumbs.html b/phpBB/styles/subsilver2/template/breadcrumbs.html index 47cb82c790..646525c206 100644 --- a/phpBB/styles/subsilver2/template/breadcrumbs.html +++ b/phpBB/styles/subsilver2/template/breadcrumbs.html @@ -2,7 +2,7 @@ <table class="tablebg" width="100%" cellspacing="1" cellpadding="0" style="margin-top: 5px;"> <tr> <td class="row1"> - <p class="breadcrumbs"><!-- IF U_SITE_HOME --><a href="{U_SITE_HOME}"{$MICRODATA}>{L_SITE_HOME}</a> <strong>»</strong> <!-- ENDIF --><a href="{U_INDEX}"{$MICRODATA}>{L_INDEX}</a><!-- BEGIN navlinks --> » <a href="{navlinks.U_VIEW_FORUM}"{$MICRODATA}>{navlinks.FORUM_NAME}</a><!-- END navlinks --> + <p class="breadcrumbs"><!-- IF U_SITE_HOME --><a href="{U_SITE_HOME}"{$MICRODATA}>{L_SITE_HOME}</a> <strong>»</strong> <!-- ENDIF --><a href="{U_INDEX}"{$MICRODATA}>{L_INDEX}</a><!-- BEGIN navlinks --><!-- EVENT overall_header_navlink_prepend --> » <a href="{navlinks.U_VIEW_FORUM}"{$MICRODATA}>{navlinks.FORUM_NAME}</a><!-- EVENT overall_header_navlink_append --><!-- END navlinks --> <!-- EVENT overall_header_breadcrumb_append --></p> <!-- EVENT overall_footer_timezone_before --> <p class="datetime">{S_TIMEZONE}</p> diff --git a/phpBB/styles/subsilver2/template/index_body.html b/phpBB/styles/subsilver2/template/index_body.html index 9e859eac0e..cb67768b15 100644 --- a/phpBB/styles/subsilver2/template/index_body.html +++ b/phpBB/styles/subsilver2/template/index_body.html @@ -44,7 +44,13 @@ <!-- ELSE --> <td class="row1" align="center" valign="middle"><img src="{T_THEME_PATH}/images/whosonline.gif" alt="{L_WHO_IS_ONLINE}" /></td> <!-- ENDIF --> - <td class="row1" width="100%"><span class="genmed">{TOTAL_USERS_ONLINE} ({L_ONLINE_EXPLAIN})<br />{RECORD_USERS}<br /><br />{LOGGED_IN_USER_LIST}</span></td> + <td class="row1" width="100%"> + <span class="genmed"> + <!-- EVENT index_body_block_online_prepend --> + {TOTAL_USERS_ONLINE} ({L_ONLINE_EXPLAIN})<br />{RECORD_USERS}<br /><br />{LOGGED_IN_USER_LIST} + <!-- EVENT index_body_block_online_append --> + </span> + </td> </tr> <!-- IF LEGEND --> <tr> @@ -63,7 +69,13 @@ </tr> <tr> <td class="row1" align="center" valign="middle"><img src="{T_THEME_PATH}/images/whosonline.gif" alt="{L_BIRTHDAYS}" /></td> - <td class="row1" width="100%"><p class="genmed"><!-- IF .birthdays -->{L_CONGRATULATIONS}{L_COLON} <b><!-- BEGIN birthdays -->{birthdays.USERNAME}<!-- IF birthdays.AGE !== '' --> ({birthdays.AGE})<!-- ENDIF --><!-- IF not birthdays.S_LAST_ROW -->, <!-- ENDIF --><!-- END birthdays --></b><!-- ELSE -->{L_NO_BIRTHDAYS}<!-- ENDIF --></p></td> + <td class="row1" width="100%"> + <p class="genmed"> + <!-- EVENT index_body_block_birthday_prepend --> + <!-- IF .birthdays -->{L_CONGRATULATIONS}{L_COLON} <b><!-- BEGIN birthdays -->{birthdays.USERNAME}<!-- IF birthdays.AGE !== '' --> ({birthdays.AGE})<!-- ENDIF --><!-- IF not birthdays.S_LAST_ROW -->, <!-- ENDIF --><!-- END birthdays --></b><!-- ELSE -->{L_NO_BIRTHDAYS}<!-- ENDIF --> + <!-- EVENT index_body_block_birthday_append --> + </p> + </td> </tr> </table> <!-- ENDIF --> @@ -76,7 +88,13 @@ </tr> <tr> <td class="row1"><img src="{T_THEME_PATH}/images/whosonline.gif" alt="{L_STATISTICS}" /></td> - <td class="row1" width="100%" valign="middle"><p class="genmed">{TOTAL_POSTS} | {TOTAL_TOPICS} | {TOTAL_USERS} | {NEWEST_USER}</p></td> + <td class="row1" width="100%" valign="middle"> + <p class="genmed"> + <!-- EVENT index_body_block_stats_prepend --> + {TOTAL_POSTS} | {TOTAL_TOPICS} | {TOTAL_USERS} | {NEWEST_USER} + <!-- EVENT index_body_block_stats_append --> + </p> + </td> </tr> </table> diff --git a/phpBB/styles/subsilver2/template/memberlist_view.html b/phpBB/styles/subsilver2/template/memberlist_view.html index 52f40707c0..4c8014a370 100644 --- a/phpBB/styles/subsilver2/template/memberlist_view.html +++ b/phpBB/styles/subsilver2/template/memberlist_view.html @@ -2,6 +2,8 @@ <div id="pagecontent"> + <!-- EVENT memberlist_view_content_prepend --> + <form method="post" action="{S_PROFILE_ACTION}"> <table class="tablebg" width="100%" cellspacing="1"> diff --git a/phpBB/styles/subsilver2/template/search_results.html b/phpBB/styles/subsilver2/template/search_results.html index 092779055d..ff34055b29 100644 --- a/phpBB/styles/subsilver2/template/search_results.html +++ b/phpBB/styles/subsilver2/template/search_results.html @@ -91,6 +91,7 @@ <!-- BEGIN searchresults --> <tr class="row2"> + <!-- EVENT search_results_post_before --> <!-- IF searchresults.S_IGNORE_POST --> <td class="gensmall" colspan="2" height="25" align="center">{searchresults.L_IGNORE_POST}</td> <!-- ELSE --> @@ -126,6 +127,7 @@ </td> </tr> <!-- ENDIF --> + <!-- EVENT search_results_post_after --> <tr> <td class="spacer" colspan="2"><img src="images/spacer.gif" height="1" alt="" /></td> </tr> diff --git a/phpBB/styles/subsilver2/template/ucp_agreement.html b/phpBB/styles/subsilver2/template/ucp_agreement.html index 054d25282f..3afe6e89a0 100644 --- a/phpBB/styles/subsilver2/template/ucp_agreement.html +++ b/phpBB/styles/subsilver2/template/ucp_agreement.html @@ -10,6 +10,7 @@ */ function change_language(lang_iso) { + document.cookie = '{COOKIE_NAME}_lang=' + lang_iso + '; path={COOKIE_PATH}'; document.forms['register'].change_lang.value = lang_iso; document.forms['register'].submit(); } diff --git a/phpBB/styles/subsilver2/template/ucp_register.html b/phpBB/styles/subsilver2/template/ucp_register.html index 3392c557a2..1d55b952e5 100644 --- a/phpBB/styles/subsilver2/template/ucp_register.html +++ b/phpBB/styles/subsilver2/template/ucp_register.html @@ -7,6 +7,7 @@ */ function change_language(lang_iso) { + document.cookie = '{COOKIE_NAME}_lang=' + lang_iso + '; path={COOKIE_PATH}'; document.forms['register'].change_lang.value = lang_iso; document.forms['register'].submit.click(); } diff --git a/phpBB/styles/subsilver2/template/viewforum_body.html b/phpBB/styles/subsilver2/template/viewforum_body.html index 44e8f30ce4..a7a130a8df 100644 --- a/phpBB/styles/subsilver2/template/viewforum_body.html +++ b/phpBB/styles/subsilver2/template/viewforum_body.html @@ -103,7 +103,7 @@ <!-- IF S_IS_POSTABLE or S_NO_READ_ACCESS --> <div id="pageheader"> - <h2><a class="titles" href="{U_VIEW_FORUM}">{FORUM_NAME}</a></h2> + <h2><!-- EVENT viewforum_forum_name_prepend --><a class="titles" href="{U_VIEW_FORUM}">{FORUM_NAME}</a><!-- EVENT viewforum_forum_name_append --></h2> <!-- IF MODERATORS --> <p class="moderators"><!-- IF S_SINGLE_MODERATOR -->{L_MODERATOR}<!-- ELSE -->{L_MODERATORS}<!-- ENDIF -->{L_COLON} {MODERATORS}</p> diff --git a/phpBB/styles/subsilver2/template/viewtopic_body.html b/phpBB/styles/subsilver2/template/viewtopic_body.html index 307ed0f391..6ac4e0ea33 100644 --- a/phpBB/styles/subsilver2/template/viewtopic_body.html +++ b/phpBB/styles/subsilver2/template/viewtopic_body.html @@ -15,7 +15,7 @@ <!-- ENDIF --> <div id="pageheader"> - <h2><!-- EVENT viewtopic_topic_title_prepend --><a class="titles" href="{U_VIEW_TOPIC}">{TOPIC_TITLE}</a></h2> + <h2><!-- EVENT viewtopic_topic_title_prepend --><a class="titles" href="{U_VIEW_TOPIC}">{TOPIC_TITLE}</a><!-- EVENT viewtopic_topic_title_append --></h2> <!-- IF MODERATORS --> <p class="moderators"><!-- IF S_SINGLE_MODERATOR -->{L_MODERATOR}<!-- ELSE -->{L_MODERATORS}<!-- ENDIF -->{L_COLON} {MODERATORS}</p> @@ -72,13 +72,14 @@ <table cellspacing="0" cellpadding="4" border="0" align="center"> <tr> - <td align="center"><span class="gen"><b>{POLL_QUESTION}</b></span><br /><span class="gensmall">{L_POLL_LENGTH}</span></td> + <td align="center"><span class="gen"><!-- EVENT viewtopic_body_poll_question_prepend --><b>{POLL_QUESTION}</b><!-- EVENT viewtopic_body_poll_question_append --></span><br /><span class="gensmall">{L_POLL_LENGTH}</span></td> </tr> <tr> <td align="{S_CONTENT_FLOW_BEGIN}"> <table cellspacing="0" cellpadding="2" border="0"> <!-- BEGIN poll_option --> <tr> + <!-- EVENT viewtopic_body_poll_option_before --> <!-- IF S_CAN_VOTE --> <td<!-- IF poll_option.POLL_OPTION_MOST_VOTES --> class="most-votes"<!-- ENDIF -->> <!-- IF S_IS_MULTI_CHOICE --> @@ -97,6 +98,7 @@ <td class="gensmall" valign="top"><b title="{L_POLL_VOTED_OPTION}">x</b></td> <!-- ENDIF --> <!-- ENDIF --> + <!-- EVENT viewtopic_body_poll_option_after --> </tr> <!-- END poll_option --> </table> diff --git a/phpBB/viewonline.php b/phpBB/viewonline.php index 9b462b2656..52fd9f640c 100644 --- a/phpBB/viewonline.php +++ b/phpBB/viewonline.php @@ -101,6 +101,7 @@ if (!$show_guests) switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': $sql = 'SELECT COUNT(session_ip) as num_guests FROM ( SELECT DISTINCT session_ip diff --git a/phpBB/viewtopic.php b/phpBB/viewtopic.php index fc40dd65bb..1f59019245 100644 --- a/phpBB/viewtopic.php +++ b/phpBB/viewtopic.php @@ -1609,7 +1609,7 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) $user_cache[$poster_id]['user_type'] != USER_IGNORE && // They must not be deactivated by the administrator - ($user_cache[$poster_id]['user_type'] != USER_INACTIVE && $user_cache[$poster_id]['user_inactive_reason'] == INACTIVE_MANUAL) && + ($user_cache[$poster_id]['user_type'] != USER_INACTIVE || $user_cache[$poster_id]['user_inactive_reason'] != INACTIVE_MANUAL) && // They must be able to read PMs in_array($poster_id, $can_receive_pm_list) && @@ -1618,9 +1618,16 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) !in_array($poster_id, $permanently_banned_users) && // They must allow users to contact via PM - (($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_')) || $data['user_allow_pm']) + (($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_')) || $user_cache[$poster_id]['allow_pm']) ); + $u_pm = ''; + + if ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && $can_receive_pm) + { + $u_pm = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose&action=quotepost&p=' . $row['post_id']); + } + // $post_row = array( 'POST_AUTHOR_FULL' => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_full'] : get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), @@ -1660,7 +1667,7 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) 'U_DELETE' => ($delete_allowed) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=delete&f=$forum_id&p={$row['post_id']}") : '', 'U_SEARCH' => $user_cache[$poster_id]['search'], - 'U_PM' => ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && $can_receive_pm) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose&action=quotepost&p=' . $row['post_id']) : '', + 'U_PM' => $u_pm, 'U_EMAIL' => $user_cache[$poster_id]['email'], 'U_JABBER' => $user_cache[$poster_id]['jabber'], @@ -1744,11 +1751,46 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) // Dump vars into template $template->assign_block_vars('postrow', $post_row); + $contact_fields = array( + array( + 'ID' => 'pm', + 'NAME' => $user->lang['PRIVATE_MESSAGES'], + 'U_CONTACT' => $u_pm, + ), + array( + 'ID' => 'email', + 'NAME' => $user->lang['SEND_EMAIL'], + 'U_CONTACT' => $user_cache[$poster_id]['email'], + ), + array( + 'ID' => 'jabber', + 'NAME' => $user->lang['JABBER'], + 'U_CONTACT' => $user_cache[$poster_id]['jabber'], + ), + ); + + foreach ($contact_fields as $field) + { + if ($field['U_CONTACT']) + { + $template->assign_block_vars('postrow.contact', $field); + } + } + if (!empty($cp_row['blockrow'])) { foreach ($cp_row['blockrow'] as $field_data) { $template->assign_block_vars('postrow.custom_fields', $field_data); + + if ($field_data['S_PROFILE_CONTACT']) + { + $template->assign_block_vars('postrow.contact', array( + 'ID' => $field_data['PROFILE_FIELD_IDENT'], + 'NAME' => $field_data['PROFILE_FIELD_NAME'], + 'U_CONTACT' => $field_data['PROFILE_FIELD_CONTACT'], + )); + } } } diff --git a/phpunit.xml.all b/phpunit.xml.all index d5ee606ce2..73d0536b9d 100644 --- a/phpunit.xml.all +++ b/phpunit.xml.all @@ -13,17 +13,17 @@ > <testsuites> <testsuite name="phpBB Test Suite"> - <directory suffix="_test.php">./tests/</directory> - <exclude>tests/lint_test.php</exclude> + <directory suffix="_test.php">./tests</directory> + <exclude>./tests/lint_test.php</exclude> </testsuite> <testsuite name="phpBB Lint Test"> - <file>tests/lint_test.php</file> + <file>./tests/lint_test.php</file> </testsuite> </testsuites> <filter> <blacklist> - <directory>./tests/</directory> + <directory>./tests</directory> </blacklist> <whitelist> <directory suffix=".php">./phpBB/includes/</directory> diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 700af8b2b2..dd039fb567 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -13,11 +13,12 @@ > <testsuites> <testsuite name="phpBB Test Suite"> - <directory suffix="_test.php">./tests/</directory> - <exclude>tests/lint_test.php</exclude> + <directory suffix="_test.php">./tests</directory> + <exclude>./tests/functional</exclude> + <exclude>./tests/lint_test.php</exclude> </testsuite> <testsuite name="phpBB Lint Test"> - <file>tests/lint_test.php</file> + <file>./tests/lint_test.php</file> </testsuite> </testsuites> @@ -30,7 +31,7 @@ <filter> <blacklist> - <directory>./tests/</directory> + <directory>./tests</directory> </blacklist> <whitelist> <directory suffix=".php">./phpBB/includes/</directory> diff --git a/phpunit.xml.functional b/phpunit.xml.functional index 44d060e615..ead8f4af68 100644 --- a/phpunit.xml.functional +++ b/phpunit.xml.functional @@ -13,11 +13,12 @@ > <testsuites> <testsuite name="phpBB Test Suite"> - <directory suffix="_test.php">./tests/</directory> - <exclude>tests/lint_test.php</exclude> + <directory suffix="_test.php">./tests</directory> + <exclude>./tests/functional</exclude> + <exclude>./tests/lint_test.php</exclude> </testsuite> <testsuite name="phpBB Lint Test"> - <file>tests/lint_test.php</file> + <file>./tests/lint_test.php</file> </testsuite> </testsuites> @@ -29,7 +30,7 @@ <filter> <blacklist> - <directory>./tests/</directory> + <directory>./tests</directory> </blacklist> <whitelist> <directory suffix=".php">./phpBB/includes/</directory> diff --git a/tests/controller/controller_test.php b/tests/controller/controller_test.php index 550679ff07..7d9fe652eb 100644 --- a/tests/controller/controller_test.php +++ b/tests/controller/controller_test.php @@ -8,8 +8,6 @@ */ use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\Routing\Route; -use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; @@ -43,6 +41,8 @@ class phpbb_controller_controller_test extends phpbb_test_case $this->assertInstanceOf('Symfony\Component\Routing\Route', $routes->get('controller2')); $this->assertEquals('/foo/bar', $routes->get('controller2')->getPath()); + + $this->assertNull($routes->get('controller_noroute')); } public function test_controller_resolver() diff --git a/tests/controller/ext/vendor2/foo/subfolder/config/routing.yml b/tests/controller/ext/vendor2/foo/subfolder/config/routing.yml new file mode 100644 index 0000000000..b4d8d19107 --- /dev/null +++ b/tests/controller/ext/vendor2/foo/subfolder/config/routing.yml @@ -0,0 +1,3 @@ +controller_noroute: + pattern: /donotfindthis + defaults: { _controller: foo.controller:handle } diff --git a/tests/mock/session_testable.php b/tests/mock/session_testable.php index d81ae3163e..a2a403727b 100644 --- a/tests/mock/session_testable.php +++ b/tests/mock/session_testable.php @@ -20,7 +20,7 @@ class phpbb_mock_session_testable extends \phpbb\session { private $_cookies = array(); - public function set_cookie($name, $data, $time) + public function set_cookie($name, $data, $time, $httponly = true) { $this->_cookies[$name] = array($data, $time); } diff --git a/tests/session/fixtures/sessions_key.xml b/tests/session/fixtures/sessions_key.xml index 4f349cd282..245f89a604 100644 --- a/tests/session/fixtures/sessions_key.xml +++ b/tests/session/fixtures/sessions_key.xml @@ -22,7 +22,6 @@ <value>4</value> <value>127.0.0.1</value> <value>user agent</value> - <value>1</value> </row> </table> <table name="phpbb_users"> diff --git a/tests/template/datasets/ext_trivial/ext/trivial/styles/all/template/event/test_event_subloop.html b/tests/template/datasets/ext_trivial/ext/trivial/styles/all/template/event/test_event_subloop.html index 4fdba859f3..98fa1770ba 100644 --- a/tests/template/datasets/ext_trivial/ext/trivial/styles/all/template/event/test_event_subloop.html +++ b/tests/template/datasets/ext_trivial/ext/trivial/styles/all/template/event/test_event_subloop.html @@ -1,2 +1,2 @@ -[{event_loop.S_ROW_COUNT}<!-- BEGIN subloop -->[subloop:{event_loop.subloop.S_ROW_COUNT}] -<!-- END subloop -->] +[{event_loop.S_ROW_COUNT}<!-- BEGIN event_loop.subloop -->[subloop:{event_loop.subloop.S_ROW_COUNT}] +<!-- END event_loop.subloop -->] diff --git a/tests/template/template_events_test.php b/tests/template/template_events_test.php index d09f22944f..866d42d831 100644 --- a/tests/template/template_events_test.php +++ b/tests/template/template_events_test.php @@ -102,7 +102,6 @@ Zeta test event in all', ), array(), 'event_loop[0[subloop:0]]', - 'Event files are missing opened parent loops: PHPBB3-12382', ), ); } diff --git a/tests/template/template_test.php b/tests/template/template_test.php index 49804c26c5..0d19e7afd1 100644 --- a/tests/template/template_test.php +++ b/tests/template/template_test.php @@ -330,7 +330,6 @@ class phpbb_template_template_test extends phpbb_template_template_test_case array(), "[bar|[bar|]][bar1|[bar1|[bar1|works]]]", array(), - 'Included files are missing opened parent loops: PHPBB3-12382', ), /* Does not pass with the current implementation. array( diff --git a/tests/template/templates/loop_nested_include1.html b/tests/template/templates/loop_nested_include1.html index 0f1a180b4d..88efffc99c 100644 --- a/tests/template/templates/loop_nested_include1.html +++ b/tests/template/templates/loop_nested_include1.html @@ -1,5 +1,5 @@ [{test_loop.foo}| -<!-- BEGIN inner --> +<!-- BEGIN test_loop.inner --> [{test_loop.foo}| {test_loop.inner.myinner}] -<!-- END inner -->] +<!-- END test_loop.inner -->] diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index 887dad5b50..796a6e57cf 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -53,6 +53,7 @@ class phpbb_database_test_connection_manager switch ($this->dbms['PDO']) { case 'sqlite2': + case 'sqlite': // SQLite3 driver $dsn .= $this->config['dbhost']; break; @@ -191,6 +192,7 @@ class phpbb_database_test_connection_manager switch ($this->config['dbms']) { case 'phpbb\db\driver\sqlite': + case 'phpbb\db\driver\sqlite3': case 'phpbb\db\driver\firebird': $this->connect(); // Drop all of the tables @@ -272,6 +274,13 @@ class phpbb_database_test_connection_manager WHERE type = "table"'; break; + case 'phpbb\db\driver\sqlite3': + $sql = 'SELECT name + FROM sqlite_master + WHERE type = "table" + AND name <> "sqlite_sequence"'; + break; + case 'phpbb\db\driver\mssql': case 'phpbb\db\driver\mssql_odbc': case 'phpbb\db\driver\mssqlnative': @@ -436,6 +445,11 @@ class phpbb_database_test_connection_manager 'DELIM' => ';', 'PDO' => 'sqlite2', ), + 'phpbb\db\driver\sqlite3' => array( + 'SCHEMA' => 'sqlite', + 'DELIM' => ';', + 'PDO' => 'sqlite', + ), ); if (isset($available_dbms[$dbms])) @@ -623,6 +637,14 @@ class phpbb_database_test_connection_manager $queries[] = 'SELECT ' . implode(', ', $setval_queries); } break; + + case 'phpbb\db\driver\sqlite3': + /** + * Just delete all of the sequences. When an insertion occurs, the sequence will be automatically + * re-created from the key with the AUTOINCREMENT attribute + */ + $queries[] = 'DELETE FROM sqlite_sequence'; + break; } foreach ($queries as $query) diff --git a/tests/test_framework/phpbb_test_case_helpers.php b/tests/test_framework/phpbb_test_case_helpers.php index 2f225fe7af..aba63a0498 100644 --- a/tests/test_framework/phpbb_test_case_helpers.php +++ b/tests/test_framework/phpbb_test_case_helpers.php @@ -104,7 +104,19 @@ class phpbb_test_case_helpers { $config = array(); - if (extension_loaded('sqlite') && version_compare(PHPUnit_Runner_Version::id(), '3.4.15', '>=')) + + if (extension_loaded('sqlite3')) + { + $config = array_merge($config, array( + 'dbms' => 'phpbb\db\driver\sqlite3', + 'dbhost' => dirname(__FILE__) . '/../phpbb_unit_tests.sqlite3', // filename + 'dbport' => '', + 'dbname' => '', + 'dbuser' => '', + 'dbpasswd' => '', + )); + } + else if (extension_loaded('sqlite')) { $config = array_merge($config, array( 'dbms' => 'phpbb\db\driver\sqlite', diff --git a/travis/phing-sniff.sh b/travis/phing-sniff.sh new file mode 100755 index 0000000000..1473b99da4 --- /dev/null +++ b/travis/phing-sniff.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# +# @copyright (c) 2014 phpBB Group +# @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +# +set -e +set -x + +DB=$1 +TRAVIS_PHP_VERSION=$2 + +if [ "$TRAVIS_PHP_VERSION" == "5.5" -a "$DB" == "mysql" ] +then + cd build + ../phpBB/vendor/bin/phing sniff + cd .. +fi diff --git a/travis/phpunit-mariadb-travis.xml b/travis/phpunit-mariadb-travis.xml index 1eaee5b7d8..aa245a8224 100644 --- a/travis/phpunit-mariadb-travis.xml +++ b/travis/phpunit-mariadb-travis.xml @@ -13,9 +13,9 @@ bootstrap="../tests/bootstrap.php"> <testsuites> <testsuite name="phpBB Test Suite"> - <directory suffix="_test.php">../tests/</directory> - <exclude>tests/functional</exclude> - <exclude>tests/lint_test.php</exclude> + <directory suffix="_test.php">../tests</directory> + <exclude>../tests/functional</exclude> + <exclude>../tests/lint_test.php</exclude> </testsuite> <testsuite name="phpBB Functional Tests"> <directory suffix="_test.php" phpVersion="5.3.19" phpVersionOperator=">=">../tests/functional</directory> diff --git a/travis/phpunit-mysql-travis.xml b/travis/phpunit-mysql-travis.xml index 5fa6c06e46..60c279d774 100644 --- a/travis/phpunit-mysql-travis.xml +++ b/travis/phpunit-mysql-travis.xml @@ -13,12 +13,12 @@ bootstrap="../tests/bootstrap.php"> <testsuites> <testsuite name="phpBB Test Suite"> - <directory suffix="_test.php">../tests/</directory> - <exclude>tests/functional</exclude> - <exclude>tests/lint_test.php</exclude> + <directory suffix="_test.php">../tests</directory> + <exclude>../tests/functional</exclude> + <exclude>../tests/lint_test.php</exclude> </testsuite> <testsuite name="phpBB Lint Test"> - <file>tests/lint_test.php</file> + <file>../tests/lint_test.php</file> </testsuite> <testsuite name="phpBB Functional Tests"> <directory suffix="_test.php" phpVersion="5.3.19" phpVersionOperator=">=">../tests/functional</directory> diff --git a/travis/phpunit-postgres-travis.xml b/travis/phpunit-postgres-travis.xml index 88d9e0f46a..956278e90c 100644 --- a/travis/phpunit-postgres-travis.xml +++ b/travis/phpunit-postgres-travis.xml @@ -13,9 +13,9 @@ bootstrap="../tests/bootstrap.php"> <testsuites> <testsuite name="phpBB Test Suite"> - <directory suffix="_test.php">../tests/</directory> - <exclude>tests/functional</exclude> - <exclude>tests/lint_test.php</exclude> + <directory suffix="_test.php">../tests</directory> + <exclude>../tests/functional</exclude> + <exclude>../tests/lint_test.php</exclude> </testsuite> <testsuite name="phpBB Functional Tests"> <directory suffix="_test.php" phpVersion="5.3.19" phpVersionOperator=">=">../tests/functional</directory> @@ -29,8 +29,6 @@ </groups> <php> - <!-- "Real" test database --> - <!-- uncomment, otherwise sqlite memory runs --> <server name="PHPBB_TEST_DBMS" value="phpbb\db\driver\postgres"/> <server name="PHPBB_TEST_DBHOST" value="localhost" /> <server name="PHPBB_TEST_DBPORT" value="5432" /> diff --git a/travis/phpunit-sqlite3-travis.xml b/travis/phpunit-sqlite3-travis.xml new file mode 100644 index 0000000000..72b8b8c8ca --- /dev/null +++ b/travis/phpunit-sqlite3-travis.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> +<phpunit backupGlobals="true" + backupStaticAttributes="true" + colors="true" + convertErrorsToExceptions="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + processIsolation="false" + stopOnFailure="false" + syntaxCheck="true" + strict="true" + verbose="true" + bootstrap="../tests/bootstrap.php"> + <testsuites> + <testsuite name="phpBB Test Suite"> + <directory suffix="_test.php">../tests</directory> + <exclude>../tests/functional</exclude> + <exclude>../tests/lint_test.php</exclude> + </testsuite> + <testsuite name="phpBB Functional Tests"> + <directory suffix="_test.php" phpVersion="5.3.19" phpVersionOperator=">=">../tests/functional</directory> + </testsuite> + </testsuites> + + <groups> + <exclude> + <group>slow</group> + </exclude> + </groups> + + <php> + <!--server name="PHPBB_TEST_DBMS" value="phpbb\db\driver\sqlite3" /--> + <!--server name="PHPBB_TEST_DBHOST" value="../phpbb_unit_tests.sqlite3" /--> + <!--server name="PHPBB_TEST_DBPORT" value="" /--> + <!--server name="PHPBB_TEST_DBNAME" value="" /--> + <!--server name="PHPBB_TEST_DBUSER" value="" /--> + <!--server name="PHPBB_TEST_DBPASSWD" value="" /--> + <server name="PHPBB_TEST_REDIS_HOST" value="localhost" /> + <server name="PHPBB_TEST_TABLE_PREFIX" value="phpbb_"/> + <server name="PHPBB_FUNCTIONAL_URL" value="http://localhost/" /> + </php> +</phpunit> diff --git a/travis/setup-database.sh b/travis/setup-database.sh new file mode 100755 index 0000000000..c1917042cd --- /dev/null +++ b/travis/setup-database.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# +# @copyright (c) 2014 phpBB Group +# @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +# +set -e +set -x + +DB=$1 +TRAVIS_PHP_VERSION=$2 + +if [ "$DB" == "postgres" ] +then + psql -c 'DROP DATABASE IF EXISTS phpbb_tests;' -U postgres + psql -c 'create database phpbb_tests;' -U postgres +fi + +if [ "$TRAVIS_PHP_VERSION" == "5.3" -a "$DB" == "mysql" ] +then + mysql -e 'SET GLOBAL storage_engine=MyISAM;' +fi + +if [ "$DB" == "mysql" -o "$DB" == "mariadb" ] +then + mysql -e 'create database IF NOT EXISTS phpbb_tests;' +fi diff --git a/travis/setup-phpbb.sh b/travis/setup-phpbb.sh new file mode 100755 index 0000000000..f079a0a6b7 --- /dev/null +++ b/travis/setup-phpbb.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# +# @copyright (c) 2014 phpBB Group +# @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +# +set -e +set -x + +DB=$1 +TRAVIS_PHP_VERSION=$2 + +if [ "$DB" == "mariadb" ] +then + travis/setup-mariadb.sh +fi + +if [ "$TRAVIS_PHP_VERSION" != "hhvm" ] +then + travis/setup-php-extensions.sh +fi + +if [ `php -r "echo (int) version_compare(PHP_VERSION, '5.3.19', '>=');"` == "1" ] +then + travis/setup-webserver.sh +fi + +cd phpBB +php ../composer.phar install --dev --no-interaction --prefer-source +cd .. |