diff options
Diffstat (limited to 'phpBB')
119 files changed, 2650 insertions, 2569 deletions
diff --git a/phpBB/adm/style/acp_groups.html b/phpBB/adm/style/acp_groups.html index 6049673e0a..d24d62497d 100644 --- a/phpBB/adm/style/acp_groups.html +++ b/phpBB/adm/style/acp_groups.html @@ -117,7 +117,6 @@ <dl> <dt><label>{L_AVATAR_TYPE}{L_COLON}</label></dt> <dd><select name="avatar_driver" id="avatar_driver" data-togglable-settings="true"> - <option value="">{L_NO_AVATAR}</option> <!-- BEGIN avatar_drivers --> <option value="{avatar_drivers.DRIVER}"<!-- IF avatar_drivers.SELECTED --> selected="selected"<!-- ENDIF --> data-toggle-setting="#avatar_option_{avatar_drivers.DRIVER}">{avatar_drivers.L_TITLE}</option> <!-- END avatar_drivers --> diff --git a/phpBB/adm/style/acp_users_avatar.html b/phpBB/adm/style/acp_users_avatar.html index 8ad4ad710b..8466985fb3 100644 --- a/phpBB/adm/style/acp_users_avatar.html +++ b/phpBB/adm/style/acp_users_avatar.html @@ -14,7 +14,6 @@ <dl> <dt><label>{L_AVATAR_TYPE}</label></dt> <dd><select name="avatar_driver" id="avatar_driver" data-togglable-settings="true"> - <option value="">{L_NO_AVATAR}</option> <!-- BEGIN avatar_drivers --> <option value="{avatar_drivers.DRIVER}"<!-- IF avatar_drivers.SELECTED --> selected="selected"<!-- ENDIF --> data-toggle-setting="#avatar_option_{avatar_drivers.DRIVER}">{avatar_drivers.L_TITLE}</option> <!-- END avatar_drivers --> diff --git a/phpBB/composer.json b/phpBB/composer.json index 0ab30b0837..e74dd120f0 100644 --- a/phpBB/composer.json +++ b/phpBB/composer.json @@ -37,8 +37,6 @@ "twig/twig": "1.13.*" }, "require-dev": { - "behat/mink": "1.4.*", - "behat/mink-goutte-driver": "1.0.*", "fabpot/goutte": "1.0.*", "phpunit/dbunit": "1.3.*", "phpunit/phpunit": "4.1.*", diff --git a/phpBB/composer.lock b/phpBB/composer.lock index 3860a98b31..671daa70e1 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": "6bc742a2b9feb426db9987d27085f915", + "hash": "27d5da149e0b5d76b76f43210306b666", "packages": [ { "name": "lusitanian/oauth", @@ -255,12 +255,14 @@ ], "authors": [ { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" }, { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" } ], "description": "Symfony Debug Component", @@ -719,167 +721,6 @@ ], "packages-dev": [ { - "name": "behat/mink", - "version": "v1.4.3", - "source": { - "type": "git", - "url": "https://github.com/Behat/Mink.git", - "reference": "0817070a6e2ec9f475fad9bfb81a962c462eb934" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Behat/Mink/zipball/0817070a6e2ec9f475fad9bfb81a962c462eb934", - "reference": "0817070a6e2ec9f475fad9bfb81a962c462eb934", - "shasum": "" - }, - "require": { - "php": ">=5.3.1", - "symfony/css-selector": ">=2.0,<2.4-dev" - }, - "suggest": { - "behat/mink-browserkit-driver": "extremely fast headless driver for Symfony\\Kernel-based apps (Sf2, Silex)", - "behat/mink-goutte-driver": "fast headless driver for any app without JS emulation", - "behat/mink-selenium2-driver": "slow, but JS-enabled driver for any app (requires Selenium2)", - "behat/mink-zombie-driver": "fast and JS-enabled headless driver for any app (requires node.js)" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-develop": "1.4.x-dev" - } - }, - "autoload": { - "psr-0": { - "Behat\\Mink": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - } - ], - "description": "Web acceptance testing framework for PHP 5.3", - "homepage": "http://mink.behat.org/", - "keywords": [ - "browser", - "testing", - "web" - ], - "time": "2013-03-02 15:53:18" - }, - { - "name": "behat/mink-browserkit-driver", - "version": "v1.0.5", - "source": { - "type": "git", - "url": "https://github.com/Behat/MinkBrowserKitDriver.git", - "reference": "f2771b5fc4dbc233859addf37a7d150852f78418" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Behat/MinkBrowserKitDriver/zipball/f2771b5fc4dbc233859addf37a7d150852f78418", - "reference": "f2771b5fc4dbc233859addf37a7d150852f78418", - "shasum": "" - }, - "require": { - "behat/mink": "~1.4.3", - "php": ">=5.3.1", - "symfony/browser-kit": "~2.0", - "symfony/dom-crawler": "~2.0" - }, - "require-dev": { - "silex/silex": "@dev" - }, - "type": "mink-driver", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-0": { - "Behat\\Mink\\Driver": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - } - ], - "description": "Symfony2 BrowserKit driver for Mink framework", - "homepage": "http://mink.behat.org/", - "keywords": [ - "Mink", - "Symfony2", - "browser", - "testing" - ], - "time": "2013-04-13 12:17:15" - }, - { - "name": "behat/mink-goutte-driver", - "version": "v1.0.9", - "source": { - "type": "git", - "url": "https://github.com/Behat/MinkGoutteDriver.git", - "reference": "fa1b073b48761464feb0b05e6825da44b20118d8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Behat/MinkGoutteDriver/zipball/fa1b073b48761464feb0b05e6825da44b20118d8", - "reference": "fa1b073b48761464feb0b05e6825da44b20118d8", - "shasum": "" - }, - "require": { - "behat/mink-browserkit-driver": ">=1.0.5,<1.2.0", - "fabpot/goutte": "~1.0.1", - "php": ">=5.3.1" - }, - "type": "mink-driver", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-0": { - "Behat\\Mink\\Driver": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - } - ], - "description": "Goutte driver for Mink framework", - "homepage": "http://mink.behat.org/", - "keywords": [ - "browser", - "goutte", - "headless", - "testing" - ], - "time": "2013-07-03 18:43:54" - }, - { "name": "fabpot/goutte", "version": "v1.0.3", "source": { @@ -2428,11 +2269,17 @@ "time": "2014-05-17 21:49:26" } ], - "aliases": [], + "aliases": [ + + ], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": [ + + ], "platform": { "php": ">=5.3.3" }, - "platform-dev": [] + "platform-dev": [ + + ] } diff --git a/phpBB/config/auth_providers.yml b/phpBB/config/auth_providers.yml index d2f22ec477..db7c603bcd 100644 --- a/phpBB/config/auth_providers.yml +++ b/phpBB/config/auth_providers.yml @@ -14,6 +14,7 @@ services: - @passwords.manager - @request - @user + - @service_container - %core.root_path% - %core.php_ext% tags: diff --git a/phpBB/config/captcha.yml b/phpBB/config/captcha.yml new file mode 100644 index 0000000000..bca37767af --- /dev/null +++ b/phpBB/config/captcha.yml @@ -0,0 +1,62 @@ +parameters: + tables.captcha_qa_questions: %core.table_prefix%captcha_questions + tables.captcha_qa_answers: %core.table_prefix%captcha_answers + tables.captcha_qa_confirm: %core.table_prefix%qa_confirm + +services: + captcha.factory: + class: phpbb\captcha\factory + arguments: + - @service_container + - @captcha.plugins.service_collection + + captcha.plugins.service_collection: + class: phpbb\di\service_collection + arguments: + - @service_container + tags: + - { name: service_collection, tag: captcha.plugins } + + core.captcha.plugins.gd: + class: phpbb\captcha\plugins\gd + scope: prototype # scope MUST be prototype for this to work! + calls: + - [set_name, [core.captcha.plugins.gd]] + tags: + - { name: captcha.plugins } + + core.captcha.plugins.gd_wave: + class: phpbb\captcha\plugins\gd_wave + scope: prototype # scope MUST be prototype for this to work! + calls: + - [set_name, [core.captcha.plugins.gd_wave]] + tags: + - { name: captcha.plugins } + + core.captcha.plugins.nogd: + class: phpbb\captcha\plugins\nogd + scope: prototype # scope MUST be prototype for this to work! + calls: + - [set_name, [core.captcha.plugins.nogd]] + tags: + - { name: captcha.plugins } + + core.captcha.plugins.qa: + class: phpbb\captcha\plugins\qa + scope: prototype # scope MUST be prototype for this to work! + arguments: + - %tables.captcha_qa_questions% + - %tables.captcha_qa_answers% + - %tables.captcha_qa_confirm% + calls: + - [set_name, [core.captcha.plugins.qa]] + tags: + - { name: captcha.plugins } + + core.captcha.plugins.recaptcha: + class: phpbb\captcha\plugins\recaptcha + scope: prototype # scope MUST be prototype for this to work! + calls: + - [set_name, [core.captcha.plugins.recaptcha]] + tags: + - { name: captcha.plugins } diff --git a/phpBB/config/parameters.yml b/phpBB/config/parameters.yml new file mode 100644 index 0000000000..5bf2c678ee --- /dev/null +++ b/phpBB/config/parameters.yml @@ -0,0 +1,2 @@ +parameters: + datetime.class: \phpbb\datetime diff --git a/phpBB/config/services.yml b/phpBB/config/services.yml index a9f9f5ed19..a588046245 100644 --- a/phpBB/config/services.yml +++ b/phpBB/config/services.yml @@ -10,6 +10,8 @@ imports: - { resource: mimetype_guessers.yml } - { resource: passwords.yml } - { resource: profilefields.yml } + - { resource: captcha.yml } + - { resource: parameters.yml } services: acl.permissions: @@ -346,6 +348,8 @@ services: user: class: phpbb\user + arguments: + - %datetime.class% user_loader: class: phpbb\user_loader diff --git a/phpBB/docs/CHANGELOG.html b/phpBB/docs/CHANGELOG.html index 71971108b1..d882d2e3f4 100644 --- a/phpBB/docs/CHANGELOG.html +++ b/phpBB/docs/CHANGELOG.html @@ -46,8 +46,9 @@ <ol> <li><a href="#changelog">Changelog</a> <ol style="list-style-type: lower-roman;"> - <li><a href="#v310b3">Changes since 3.1.0-RC1</a></li> - <li><a href="#v310b3">Changes since 3.1.0-b4</a></li> + <li><a href="#v310RC2">Changes since 3.1.0-RC2</a></li> + <li><a href="#v310RC1">Changes since 3.1.0-RC1</a></li> + <li><a href="#v310b4">Changes since 3.1.0-b4</a></li> <li><a href="#v310b3">Changes since 3.1.0-b3</a></li> <li><a href="#v310b2">Changes since 3.1.0-b2</a></li> <li><a href="#v310b1">Changes since 3.1.0-b1</a></li> @@ -95,7 +96,131 @@ <div class="content"> - <a name="v310RC1"></a><h3>1.i. Changes since 3.1.0-RC1</h3> + <a name="v310RC2"></a><h3>1.i. Changes since 3.1.0-RC2</h3> + + <h4>Bug</h4> + <ul> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11148">PHPBB3-11148</a>] - Fix uploading attachments from Android 4 powered devices</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11480">PHPBB3-11480</a>] - Prevent Private Message system from returning "Unknown folder" when inbox folder is full</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11520">PHPBB3-11520</a>] - Post count not incremented when you fork a topic</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11854">PHPBB3-11854</a>] - Captcha code is still in includes/</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12232">PHPBB3-12232</a>] - MCP Banning: Max execution time exceeded</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12448">PHPBB3-12448</a>] - Migration tools don't allow adding columns with default == NULL</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12492">PHPBB3-12492</a>] - DB_TEST: Special chars are not supported.</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12535">PHPBB3-12535</a>] - The profile link should be better adjusted to the avatar image it surrounds in viewtopic.php</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12685">PHPBB3-12685</a>] - CLI doesn't load extension commands</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12710">PHPBB3-12710</a>] - phpBB 3.0.12 on Oracle fails to upgrade to 3.1.0</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12718">PHPBB3-12718</a>] - Hard Deleting Post does not Decrease Post Count</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12742">PHPBB3-12742</a>] - Notifications duplicate code that requires an event</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12744">PHPBB3-12744</a>] - RTL board header is one line higher than LTR</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12748">PHPBB3-12748</a>] - UCP Terms of Use Typo</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12770">PHPBB3-12770</a>] - search_wordmatch unique key name is too long</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12776">PHPBB3-12776</a>] - docs/INSTALL.html is missing 3.0 to 3.1 update instructions</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12789">PHPBB3-12789</a>] - Cached directories are not deleted when the cache is purged (with ACM memory enabled).</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12791">PHPBB3-12791</a>] - String profile fields do not use links, smilies and line breaks in memberlist</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12792">PHPBB3-12792</a>] - Profile field type strings function get_profile_contact_value duplicates raw()</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12793">PHPBB3-12793</a>] - String '0' does not display for string profile fields</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12794">PHPBB3-12794</a>] - Google+ profile field validation is too strict</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12809">PHPBB3-12809</a>] - RTL styling issues with new jump-box dropdown</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12814">PHPBB3-12814</a>] - Error while trying to setup LDAP Authentication in ACP</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12822">PHPBB3-12822</a>] - Preselect avatar type if only 1 type is enabled</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12837">PHPBB3-12837</a>] - Viewing contact form displays "VIEWING_MEMBERS" on viewonline</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12842">PHPBB3-12842</a>] - Out of memory issue in code sniffer call for extensions</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12843">PHPBB3-12843</a>] - When you click on "Mark forums read" in the browser, a console error occurs</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12844">PHPBB3-12844</a>] - $dbpasswd is cleared too early in connection manager</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12845">PHPBB3-12845</a>] - HTML5 Invalid using role="navigation"</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12846">PHPBB3-12846</a>] - SQLite3 bug in profilefield_base_migration.php</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12849">PHPBB3-12849</a>] - ReferenceError in core.js</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12851">PHPBB3-12851</a>] - Font colour button title is not consistent with other buttons</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12853">PHPBB3-12853</a>] - Problems with ACP/MCP links in mobile design with other translations</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12854">PHPBB3-12854</a>] - Admin contact page should not be used when board emails are disabled</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12855">PHPBB3-12855</a>] - Container is being recompiled on every page request although DEBUG_CONTAINER is not set</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12859">PHPBB3-12859</a>] - Missing post button events from view pm template</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12870">PHPBB3-12870</a>] - Console database migrate function can not update from 3.0.12 to 3.1</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12873">PHPBB3-12873</a>] - Wrong identifier tested in \db\tools\sql_create_(unique_)index()</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12875">PHPBB3-12875</a>] - Extension's info_acp_lang files don't fallback correctly when the user's language is not included in the extension</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12881">PHPBB3-12881</a>] - Debug error - Undefined index: mark_time</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12882">PHPBB3-12882</a>] - $config['search_type'] - is not correctly updated when updating from 3.0 to 3.1</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12883">PHPBB3-12883</a>] - Do not use basename() to get the search class in phpbb\cron\task\core\tidy_search</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12886">PHPBB3-12886</a>] - Redundant lock and unlock expressions for QuickMod in viewtopic.php</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12887">PHPBB3-12887</a>] - Typo in timezone handling code: 'offest' should be 'offset'</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12891">PHPBB3-12891</a>] - Long page generation time when banlist is long</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12895">PHPBB3-12895</a>] - ?style=1 appended to url after using the UCP</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12898">PHPBB3-12898</a>] - In cron.php we try to release the lock after the call to garbage_collection()</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12901">PHPBB3-12901</a>] - Wrong type hint in show_available_child_styles() doc block</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12902">PHPBB3-12902</a>] - Remove duplicate entry in build_cfg_template() switch statement</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12903">PHPBB3-12903</a>] - Remove unused method in phpBB/phpbb/extension/metadata_manager.php</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12908">PHPBB3-12908</a>] - Fix broken operator assignment in increment.php</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12909">PHPBB3-12909</a>] - Use correct lang vars in cli extension enable</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12910">PHPBB3-12910</a>] - Profile fields: Two "simple text field" in dropdown menu</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12912">PHPBB3-12912</a>] - Undefined index when adding logs from extensions</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12918">PHPBB3-12918</a>] - Functional Tests Suite does not run on its own</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12919">PHPBB3-12919</a>] - Allow using class names as module identifier for extensions</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12922">PHPBB3-12922</a>] - Posts per page in MCP should have a minimum value of zero</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12931">PHPBB3-12931</a>] - General error on user registration when domain name is not set</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12932">PHPBB3-12932</a>] - Easy support of non-gregorian calendars</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12937">PHPBB3-12937</a>] - Without config file, extract($phpbb_config_php_file->get_all()); breaks</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12938">PHPBB3-12938</a>] - Board floods "store"-directory with packed attachments</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12940">PHPBB3-12940</a>] - Unused 'use' statements in download/file.php</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12950">PHPBB3-12950</a>] - Functional tests can not be run anymore if another language is present</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12954">PHPBB3-12954</a>] - Nginx setup on travis returns wrong SCRIPT_NAME info</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12956">PHPBB3-12956</a>] - Unknown column 'field_is_contact' in 'field list'</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12964">PHPBB3-12964</a>] - Undefined $row in download/file.php</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12967">PHPBB3-12967</a>] - Undefined variable: phpbb_dispatcher in mcp_queue.php</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12970">PHPBB3-12970</a>] - chema.json is not up to date with migration files</li> + </ul> + <h4>Improvement</h4> + <ul> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-9165">PHPBB3-9165</a>] - Extend template loop to allow iteration step modification</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10073">PHPBB3-10073</a>] - Contact page</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12051">PHPBB3-12051</a>] - Optimise Composer Autoloader on Build</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12560">PHPBB3-12560</a>] - Add methods to set upload and temp paths in Plupload class</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12656">PHPBB3-12656</a>] - Translate existing CLI commands</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12663">PHPBB3-12663</a>] - Extract Command Line Interface language strings into their own file.</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12671">PHPBB3-12671</a>] - Possibility to use NOT LIKE expression</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12693">PHPBB3-12693</a>] - Add a travis test that checks file permissions</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12738">PHPBB3-12738</a>] - Move related code from functions_posting into remove_post_from_statistic()</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12778">PHPBB3-12778</a>] - The automatic updater should have an option to automatically delete removed files during update</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12828">PHPBB3-12828</a>] - Add includes/ucp/ucp_prefs.php common core event to allow additional actions before the page load</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12832">PHPBB3-12832</a>] - Add footer links to the Quick Links menu</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12836">PHPBB3-12836</a>] - [Event] - core.functions.redirect</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12841">PHPBB3-12841</a>] - Allow extensions to position new config vars in an array</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12847">PHPBB3-12847</a>] - Allow extensions to define if they can be enabled</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12857">PHPBB3-12857</a>] - Add template events overall_header_breadcrumbs_before/after</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12864">PHPBB3-12864</a>] - Have an EVENT tag after STYLESHEETS in overall_header</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12871">PHPBB3-12871</a>] - Add PHPBB_DISPLAY_LOAD_TIME constant to config.php on installation</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12872">PHPBB3-12872</a>] - Add poster_id to viewtopic_modify_post_row</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12884">PHPBB3-12884</a>] - Add core event to the function upload_attachment()</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12892">PHPBB3-12892</a>] - S_NUM_ROWS does not scale</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12896">PHPBB3-12896</a>] - Add event in acp_main to allow php checks for admin notices</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12906">PHPBB3-12906</a>] - Add rel="help" to FAQ link</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12913">PHPBB3-12913</a>] - Add more parameters to core.submit_post_end event</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12942">PHPBB3-12942</a>] - Add core.add_form_key core event</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12944">PHPBB3-12944</a>] - Add core.login_forum_box core event</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12953">PHPBB3-12953</a>] - Page title not updated when notifications are marked as read</li> + </ul> + <h4>Sub-task</h4> + <ul> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12800">PHPBB3-12800</a>] - [Event] - Create core.functions_display.display_user_activity.actives_after</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12801">PHPBB3-12801</a>] - [Event] - core.functions_posting.load_drafts_draft_list_results</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12876">PHPBB3-12876</a>] - [Event] - core.mcp_mcp_front.mcp_front_view_queue_postid_list_after</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12880">PHPBB3-12880</a>] - [Event] - core.mcp_queue_!is_topics_query_before</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12927">PHPBB3-12927</a>] - [Event] - core.mcp_queue_get_posts2_query_before</li> + </ul> + <h4>Task</h4> + <ul> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10404">PHPBB3-10404</a>] - Remove create_function from includes/acp/auth.php</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12557">PHPBB3-12557</a>] - Fix doc block errors found by Sami</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12826">PHPBB3-12826</a>] - Investigate "catch (Exception"</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12860">PHPBB3-12860</a>] - Add template events to mcp_ban.html</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12861">PHPBB3-12861</a>] - Add event before assigning the posts to the template</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12917">PHPBB3-12917</a>] - Move commit check and file executable checks to 5.3.3 build on travis</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12920">PHPBB3-12920</a>] - Create composer installable app and core packages with subtree split</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12941">PHPBB3-12941</a>] - Check for Sami documentation errors on Travis CI</li> + <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12948">PHPBB3-12948</a>] - Remove Travis CI "broken opcache on PHP 5.5.7 and 5.5.8" workaround.</li> + </ul> + + <a name="v310RC1"></a><h3>1.ii. Changes since 3.1.0-RC1</h3> <h4>Bug</h4> <ul> @@ -166,7 +291,7 @@ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12829">PHPBB3-12829</a>] - Remove check for pgsql 8.3/8.2</li> </ul> - <a name="v310b4"></a><h3>1.ii. Changes since 3.1.0-b4</h3> + <a name="v310b4"></a><h3>1.iii. Changes since 3.1.0-b4</h3> <h4>Bug</h4> <ul> @@ -286,7 +411,7 @@ </ul> - <a name="v310b3"></a><h3>1.iii. Changes since 3.1.0-b3</h3> + <a name="v310b3"></a><h3>1.iv. Changes since 3.1.0-b3</h3> <h4>Bug</h4> <ul> @@ -393,7 +518,7 @@ </ul> - <a name="v310b2"></a><h3>1.iv. Changes since 3.1.0-b2</h3> + <a name="v310b2"></a><h3>1.v. Changes since 3.1.0-b2</h3> <h4>Bug</h4> <ul> @@ -558,7 +683,7 @@ </ul> - <a name="v310b1"></a><h3>1.v. Changes since 3.1.0-b1</h3> + <a name="v310b1"></a><h3>1.vi. Changes since 3.1.0-b1</h3> <h4>Bug</h4> <ul> @@ -626,7 +751,7 @@ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12302">PHPBB3-12302</a>] - Upgrade composer.phar to 1.0.0-alpha8</li> </ul> - <a name="v310a3"></a><h3>1.vi. Changes since 3.1.0-a3</h3> + <a name="v310a3"></a><h3>1.vii. Changes since 3.1.0-a3</h3> <h4>Bug</h4> <ul> @@ -773,7 +898,7 @@ </ul> - <a name="v310a2"></a><h3>1.vii. Changes since 3.1.0-a2</h3> + <a name="v310a2"></a><h3>1.viii. Changes since 3.1.0-a2</h3> <h4>Bug</h4> <ul> @@ -881,7 +1006,7 @@ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12147">PHPBB3-12147</a>] - Remove Travis CI notification configuration</li> </ul> - <a name="v310a1"></a><h3>1.viii. Changes since 3.1.0-a1</h3> + <a name="v310a1"></a><h3>1.ix. Changes since 3.1.0-a1</h3> <h4>Bug</h4> <ul> @@ -957,7 +1082,7 @@ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11998">PHPBB3-11998</a>] - Add console / command line client environment </li> </ul> - <a name="v30x"></a><h3>1.ix. Changes since 3.0.x</h3> + <a name="v30x"></a><h3>1.x. Changes since 3.0.x</h3> <h4>Bug</h4> <ul> @@ -1638,7 +1763,7 @@ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11913">PHPBB3-11913</a>] - Apply reorganisation of download.phpbb.com to build_announcement.php</li> </ul> - <a name="v3011"></a><h3>1.x. Changes since 3.0.11</h3> + <a name="v3011"></a><h3>1.xi. Changes since 3.0.11</h3> <h4>Bug</h4> <ul> @@ -1793,7 +1918,7 @@ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11753">PHPBB3-11753</a>] - Upgrade mysql_upgrader.php schema data.</li> </ul> - <a name="v3010"></a><h3>1.xi. Changes since 3.0.10</h3> + <a name="v3010"></a><h3>1.xii. Changes since 3.0.10</h3> <h4>Bug</h4> <ul> @@ -1918,7 +2043,7 @@ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10909">PHPBB3-10909</a>] - Update Travis Test Configuration: Travis no longer supports PHP 5.3.2</li> </ul> - <a name="v309"></a><h3>1.xii. Changes since 3.0.9</h3> + <a name="v309"></a><h3>1.xiii. Changes since 3.0.9</h3> <h4>Bug</h4> <ul> @@ -2054,7 +2179,7 @@ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10480">PHPBB3-10480</a>] - Automate changelog building</li> </ul> - <a name="v308"></a><h3>1.xiii. Changes since 3.0.8</h3> + <a name="v308"></a><h3>1.xiv. Changes since 3.0.8</h3> <h4> Bug </h4> @@ -2422,7 +2547,7 @@ </ul> - <a name="v307-PL1"></a><h3>1.xiv. Changes since 3.0.7-PL1</h3> + <a name="v307-PL1"></a><h3>1.xv. Changes since 3.0.7-PL1</h3> <h4> Security </h4> <ul> @@ -2880,13 +3005,13 @@ </ul> - <a name="v307"></a><h3>1.xv. Changes since 3.0.7</h3> + <a name="v307"></a><h3>1.xvi. Changes since 3.0.7</h3> <ul> <li>[Sec] Do not expose forum content of forums with ACL entries but no actual permission in ATOM Feeds. (Bug #58595)</li> </ul> - <a name="v306"></a><h3>1.xvi. Changes since 3.0.6</h3> + <a name="v306"></a><h3>1.xvii. Changes since 3.0.6</h3> <ul> <li>[Fix] Allow ban reason and length to be selected and copied in ACP and subsilver2 MCP. (Bug #51095)</li> @@ -2990,7 +3115,7 @@ </ul> - <a name="v305"></a><h3>1.xvii. Changes since 3.0.5</h3> + <a name="v305"></a><h3>1.xviii. Changes since 3.0.5</h3> <ul> <li>[Fix] Allow whitespaces in avatar gallery names. (Bug #44955)</li> @@ -3212,7 +3337,7 @@ <li>[Feature] Send anonymous statistical information to phpBB on installation and update (optional).</li> </ul> - <a name="v304"></a><h3>1.xviii. Changes since 3.0.4</h3> + <a name="v304"></a><h3>1.xix. Changes since 3.0.4</h3> <ul> <li>[Fix] Delete user entry from ban list table upon user deletion (Bug #40015 - Patch by TerraFrost)</li> @@ -3301,7 +3426,7 @@ <li>[Sec] Only use forum id supplied for posting if global announcement detected. (Reported by nickvergessen)</li> </ul> - <a name="v303"></a><h3>1.xix. Changes since 3.0.3</h3> + <a name="v303"></a><h3>1.xx. Changes since 3.0.3</h3> <ul> <li>[Fix] Allow mixed-case template directories to be inherited (Bug #36725)</li> @@ -3333,7 +3458,7 @@ <li>[Sec] Ask for forum password if post within passworded forum quoted in private message. (Reported by nickvergessen)</li> </ul> - <a name="v302"></a><h3>1.xx. Changes since 3.0.2</h3> + <a name="v302"></a><h3>1.xxi. Changes since 3.0.2</h3> <ul> <li>[Fix] Correctly set topic starter if first post in topic removed (Bug #30575 - Patch by blueray2048)</li> @@ -3432,7 +3557,7 @@ <li>[Sec Precaution] Stricter validation of the HTTP_HOST header (Thanks to Techie-Micheal et al for pointing out possible issues in derived code)</li> </ul> - <a name="v301"></a><h3>1.xxi. Changes since 3.0.1</h3> + <a name="v301"></a><h3>1.xxii. Changes since 3.0.1</h3> <ul> <li>[Fix] Ability to set permissions on non-mysql dbms (Bug #24955)</li> @@ -3480,7 +3605,7 @@ <li>[Sec] Only allow urls gone through redirect() being used within login_box(). (thanks nookieman)</li> </ul> - <a name="v300"></a><h3>1.xxii. Changes since 3.0.0</h3> + <a name="v300"></a><h3>1.xxiii. Changes since 3.0.0</h3> <ul> <li>[Change] Validate birthdays (Bug #15004)</li> @@ -3551,7 +3676,7 @@ <li>[Fix] Find and display colliding usernames correctly when converting from one database to another (Bug #23925)</li> </ul> - <a name="v30rc8"></a><h3>1.xxiii. Changes since 3.0.RC8</h3> + <a name="v30rc8"></a><h3>1.xxiv. Changes since 3.0.RC8</h3> <ul> <li>[Fix] Cleaned usernames contain only single spaces, so "a_name" and "a__name" are treated as the same name (Bug #15634)</li> @@ -3560,7 +3685,7 @@ <li>[Fix] Call garbage_collection() within database updater to correctly close connections (affects Oracle for example)</li> </ul> - <a name="v30rc7"></a><h3>1.xxiv. Changes since 3.0.RC7</h3> + <a name="v30rc7"></a><h3>1.xxv. Changes since 3.0.RC7</h3> <ul> <li>[Fix] Fixed MSSQL related bug in the update system</li> @@ -3595,7 +3720,7 @@ <li>[Fix] No duplication of active topics (Bug #15474)</li> </ul> - <a name="v30rc6"></a><h3>1.xxv. Changes since 3.0.RC6</h3> + <a name="v30rc6"></a><h3>1.xxvi. Changes since 3.0.RC6</h3> <ul> <li>[Fix] Submitting language changes using acp_language (Bug #14736)</li> @@ -3605,7 +3730,7 @@ <li>[Fix] Able to request new password (Bug #14743)</li> </ul> - <a name="v30rc5"></a><h3>1.xxvi. Changes since 3.0.RC5</h3> + <a name="v30rc5"></a><h3>1.xxvii. Changes since 3.0.RC5</h3> <ul> <li>[Feature] Removing constant PHPBB_EMBEDDED in favor of using an exit_handler(); the constant was meant to achive this more or less.</li> @@ -3668,7 +3793,7 @@ <li>[Sec] New password hashing mechanism for storing passwords (#i42)</li> </ul> - <a name="v30rc4"></a><h3>1.xxvii. Changes since 3.0.RC4</h3> + <a name="v30rc4"></a><h3>1.xxviii. Changes since 3.0.RC4</h3> <ul> <li>[Fix] MySQL, PostgreSQL and SQLite related database fixes (Bug #13862)</li> @@ -3719,7 +3844,7 @@ <li>[Fix] odbc_autocommit causing existing result sets to be dropped (Bug #14182)</li> </ul> - <a name="v30rc3"></a><h3>1.xxviii. Changes since 3.0.RC3</h3> + <a name="v30rc3"></a><h3>1.xxix. Changes since 3.0.RC3</h3> <ul> <li>[Fix] Fixing some subsilver2 and prosilver style issues</li> @@ -3828,7 +3953,7 @@ </ul> - <a name="v30rc2"></a><h3>1.xxix. Changes since 3.0.RC2</h3> + <a name="v30rc2"></a><h3>1.xxx. Changes since 3.0.RC2</h3> <ul> <li>[Fix] Re-allow searching within the memberlist</li> @@ -3874,7 +3999,7 @@ </ul> - <a name="v30rc1"></a><h3>1.xxx. Changes since 3.0.RC1</h3> + <a name="v30rc1"></a><h3>1.xxxi. Changes since 3.0.RC1</h3> <ul> <li>[Fix] (X)HTML issues within the templates (Bug #11255, #11255)</li> diff --git a/phpBB/docs/events.md b/phpBB/docs/events.md index 044596073c..4f39e71c3c 100644 --- a/phpBB/docs/events.md +++ b/phpBB/docs/events.md @@ -879,6 +879,20 @@ ucp_agreement_terms_before * Since: 3.1.0-b3 * Purpose: Add content before the terms of agreement text at user registration +ucp_pm_viewmessage_avatar_after +=== +* Locations: + + styles/prosilver/template/ucp_pm_viewmessage.html +* Since: 3.1.0-RC3 +* Purpose: Add content right after the avatar when viewing a private message + +ucp_pm_viewmessage_avatar_before +=== +* Locations: + + styles/prosilver/template/ucp_pm_viewmessage.html +* Since: 3.1.0-RC3 +* Purpose: Add content right before the avatar when viewing a private message + ucp_pm_viewmessage_contact_fields_after === * Locations: @@ -1085,6 +1099,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_avatar_after +=== +* Locations: + + styles/prosilver/template/viewtopic_body.html + + styles/subsilver2/template/viewtopic_body.html +* Since: 3.1.0-RC3 +* Purpose: Add content right after the avatar when viewing topics + +viewtopic_body_avatar_before +=== +* Locations: + + styles/prosilver/template/viewtopic_body.html + + styles/subsilver2/template/viewtopic_body.html +* Since: 3.1.0-RC3 +* Purpose: Add content right before the avatar when viewing topics + viewtopic_body_contact_fields_after === * Locations: diff --git a/phpBB/download/file.php b/phpBB/download/file.php index d4e0f04d2b..fd94e78fee 100644 --- a/phpBB/download/file.php +++ b/phpBB/download/file.php @@ -11,10 +11,6 @@ * */ -use Symfony\Component\Config\FileLocator; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; - /** * @ignore */ @@ -143,11 +139,7 @@ if (isset($_GET['avatar'])) include($phpbb_root_path . 'common.' . $phpEx); require($phpbb_root_path . 'includes/functions_download' . '.' . $phpEx); -$download_id = request_var('id', 0); -$topic_id = $request->variable('topic_id', 0); -$post_id = $request->variable('post_id', 0); -$msg_id = $request->variable('msg_id', 0); -$archive = $request->variable('archive', '.tar'); +$attach_id = request_var('id', 0); $mode = request_var('mode', ''); $thumbnail = request_var('t', false); @@ -162,27 +154,7 @@ if (!$config['allow_attachments'] && !$config['allow_pm_attach']) trigger_error('ATTACHMENT_FUNCTIONALITY_DISABLED'); } -if ($download_id) -{ - // Attachment id (only 1 attachment) - $sql_where = 'attach_id = ' . $download_id; -} -else if ($msg_id) -{ - // Private message id (multiple attachments) - $sql_where = 'is_orphan = 0 AND in_message = 1 AND post_msg_id = ' . $msg_id; -} -else if ($post_id) -{ - // Post id (multiple attachments) - $sql_where = 'is_orphan = 0 AND in_message = 0 AND post_msg_id = ' . $post_id; -} -else if ($topic_id) -{ - // Topic id (multiple attachments) - $sql_where = 'is_orphan = 0 AND topic_id = ' . $topic_id; -} -else +if (!$attach_id) { send_status_line(404, 'Not Found'); trigger_error('NO_ATTACHMENT_SELECTED'); @@ -190,25 +162,12 @@ else $sql = 'SELECT attach_id, post_msg_id, topic_id, in_message, poster_id, is_orphan, physical_filename, real_filename, extension, mimetype, filesize, filetime FROM ' . ATTACHMENTS_TABLE . " - WHERE $sql_where"; + WHERE attach_id = $attach_id"; $result = $db->sql_query($sql); - -$attachments = $attachment_ids = array(); -while ($row = $db->sql_fetchrow($result)) -{ - $attachment_id = (int) $row['attach_id']; - - $row['physical_filename'] = utf8_basename($row['physical_filename']); - - $attachment_ids[$attachment_id] = $attachment_id; - $attachments[$attachment_id] = $row; -} +$attachment = $db->sql_fetchrow($result); $db->sql_freeresult($result); -// Make $attachment the first of the attachments we fetched. -$attachment = current($attachments); - -if (empty($attachments)) +if (!$attachment) { send_status_line(404, 'Not Found'); trigger_error('ERROR_NO_ATTACHMENT'); @@ -218,9 +177,9 @@ else if (!download_allowed()) send_status_line(403, 'Forbidden'); trigger_error($user->lang['LINKAGE_FORBIDDEN']); } -else if ($download_id) +else { - // sizeof($attachments) == 1 + $attachment['physical_filename'] = utf8_basename($attachment['physical_filename']); if (!$attachment['in_message'] && !$config['allow_attachments'] || $attachment['in_message'] && !$config['allow_pm_attach']) { @@ -265,12 +224,12 @@ else if ($download_id) else { // Attachment is in a private message. - $row['forum_id'] = false; + $post_row = array('forum_id' => false); phpbb_download_handle_pm_auth($db, $auth, $user->data['user_id'], $attachment['post_msg_id']); } $extensions = array(); - if (!extension_allowed($row['forum_id'], $attachment['extension'], $extensions)) + if (!extension_allowed($post_row['forum_id'], $attachment['extension'], $extensions)) { send_status_line(403, 'Forbidden'); trigger_error(sprintf($user->lang['EXTENSION_DISABLED_AFTER_POSTING'], $attachment['extension'])); @@ -327,142 +286,3 @@ else if ($download_id) } } } -else -{ - // sizeof($attachments) >= 1 - if ($attachment['in_message']) - { - phpbb_download_handle_pm_auth($db, $auth, $user->data['user_id'], $attachment['post_msg_id']); - } - else - { - phpbb_download_handle_forum_auth($db, $auth, $attachment['topic_id']); - } - - if (!class_exists('compress')) - { - require $phpbb_root_path . 'includes/functions_compress.' . $phpEx; - } - - if (!in_array($archive, compress::methods())) - { - $archive = '.tar'; - } - - $post_visibility = array(); - if ($msg_id) - { - $sql = 'SELECT message_subject AS attach_subject - FROM ' . PRIVMSGS_TABLE . " - WHERE msg_id = $msg_id"; - } - else if ($post_id) - { - $sql = 'SELECT post_subject AS attach_subject, forum_id, post_visibility - FROM ' . POSTS_TABLE . " - WHERE post_id = $post_id"; - } - else - { - $sql = 'SELECT post_id, post_visibility - FROM ' . POSTS_TABLE . " - WHERE topic_id = $topic_id - AND post_attachment = 1"; - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - $post_visibility[(int) $row['post_id']] = (int) $row['post_visibility']; - } - $db->sql_freeresult($result); - - $sql = 'SELECT topic_title AS attach_subject, forum_id - FROM ' . TOPICS_TABLE . " - WHERE topic_id = $topic_id"; - } - - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (empty($row)) - { - send_status_line(404, 'Not Found'); - trigger_error('ERROR_NO_ATTACHMENT'); - } - - $clean_name = phpbb_download_clean_filename($row['attach_subject']); - $suffix = '_' . (($msg_id) ? 'm' . $msg_id : (($post_id) ? 'p' . $post_id : 't' . $topic_id)) . '_' . $clean_name; - $archive_name = 'attachments' . $suffix; - - $store_name = 'att_' . time() . '_' . unique_id(); - $archive_path = "{$phpbb_root_path}store/{$store_name}{$archive}"; - - if ($archive === '.zip') - { - $compress = new compress_zip('w', $archive_path); - } - else - { - $compress = new compress_tar('w', $archive_path, $archive); - } - - $extensions = array(); - $files_added = 0; - $forum_id = ($attachment['in_message']) ? false : (int) $row['forum_id']; - $disallowed_extension = array(); - - foreach ($attachments as $attach) - { - if (!extension_allowed($forum_id, $attach['extension'], $extensions)) - { - $disallowed_extension[$attach['extension']] = $attach['extension']; - continue; - } - - if ($post_id && $row['post_visibility'] != ITEM_APPROVED && !$auth->acl_get('m_approve', $forum_id)) - { - // Attachment of a soft deleted post and the user is not allowed to see the post - continue; - } - - if ($topic_id && (!isset($post_visibility[$attach['post_msg_id']]) || $post_visibility[$attach['post_msg_id']] != ITEM_APPROVED) && !$auth->acl_get('m_approve', $forum_id)) - { - // Attachment of a soft deleted post and the user is not allowed to see the post - continue; - } - - $prefix = ''; - if ($topic_id) - { - $prefix = $attach['post_msg_id'] . '_'; - } - - $compress->add_custom_file("{$phpbb_root_path}files/{$attach['physical_filename']}", "{$prefix}{$attach['real_filename']}"); - $files_added++; - } - - $compress->close(); - - if ($files_added) - { - phpbb_increment_downloads($db, $attachment_ids); - $compress->download($store_name, $archive_name); - } - - unlink($archive_path); - - if (!$files_added && !empty($disallowed_extension)) - { - // None of the attachments had a valid extension - $disallowed_extension = implode($user->lang['COMMA_SEPARATOR'], $disallowed_extension); - send_status_line(403, 'Forbidden'); - trigger_error($user->lang('EXTENSION_DISABLED_AFTER_POSTING', $disallowed_extension)); - } - else if (!$files_added) - { - send_status_line(404, 'Not Found'); - trigger_error('ERROR_NO_ATTACHMENT'); - } - - file_gc(); -} diff --git a/phpBB/includes/acp/acp_captcha.php b/phpBB/includes/acp/acp_captcha.php index a625005bf8..fa8d8fb6a9 100644 --- a/phpBB/includes/acp/acp_captcha.php +++ b/phpBB/includes/acp/acp_captcha.php @@ -26,12 +26,11 @@ class acp_captcha function main($id, $mode) { global $db, $user, $auth, $template; - global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; + global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx, $phpbb_container; $user->add_lang('acp/board'); - include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); - $factory = new phpbb_captcha_factory(); + $factory = $phpbb_container->get('captcha.factory'); $captchas = $factory->get_captcha_types(); $selected = request_var('select_captcha', $config['captcha_plugin']); @@ -47,7 +46,7 @@ class acp_captcha // Delegate if ($configure) { - $config_captcha = phpbb_captcha_factory::get_instance($selected); + $config_captcha = $factory->get_instance($selected); $config_captcha->acp_page($id, $this); } else @@ -79,11 +78,11 @@ class acp_captcha // sanity check if (isset($captchas['available'][$selected])) { - $old_captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $old_captcha = $factory->get_instance($config['captcha_plugin']); $old_captcha->uninstall(); set_config('captcha_plugin', $selected); - $new_captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $new_captcha = $factory->get_instance($config['captcha_plugin']); $new_captcha->install(); add_log('admin', 'LOG_CONFIG_VISUAL'); @@ -114,7 +113,7 @@ class acp_captcha $captcha_select .= '<option value="' . $value . '"' . $current . ' class="disabled-option">' . $user->lang($title) . '</option>'; } - $demo_captcha = phpbb_captcha_factory::get_instance($selected); + $demo_captcha = $factory->get_instance($selected); foreach ($config_vars as $config_var => $options) { @@ -137,9 +136,9 @@ class acp_captcha */ function deliver_demo($selected) { - global $db, $user, $config; + global $db, $user, $config, $phpbb_container; - $captcha = phpbb_captcha_factory::get_instance($selected); + $captcha = $phpbb_container->get('captcha.factory')->get_instance($selected); $captcha->init(CONFIRM_REG); $captcha->execute_demo(); diff --git a/phpBB/includes/acp/acp_groups.php b/phpBB/includes/acp/acp_groups.php index f10f0b1015..edfada1bf1 100644 --- a/phpBB/includes/acp/acp_groups.php +++ b/phpBB/includes/acp/acp_groups.php @@ -331,6 +331,28 @@ class acp_groups } } + if ($request->is_set_post('avatar_delete')) + { + if (confirm_box(true)) + { + $avatar_data['id'] = substr($avatar_data['id'], 1); + $phpbb_avatar_manager->handle_avatar_delete($db, $user, $avatar_data, GROUPS_TABLE, 'group_'); + + $message = ($action == 'edit') ? 'GROUP_UPDATED' : 'GROUP_CREATED'; + trigger_error($user->lang[$message] . adm_back_link($this->u_action)); + } + else + { + confirm_box(false, $user->lang('CONFIRM_AVATAR_DELETE'), build_hidden_fields(array( + 'avatar_delete' => true, + 'i' => $id, + 'mode' => $mode, + 'g' => $group_id, + 'action' => $action)) + ); + } + } + // Did we submit? if ($update) { diff --git a/phpBB/includes/acp/acp_users.php b/phpBB/includes/acp/acp_users.php index 71880c2267..58f9643dc9 100644 --- a/phpBB/includes/acp/acp_users.php +++ b/phpBB/includes/acp/acp_users.php @@ -465,25 +465,9 @@ class acp_users trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); } - $sql_ary = array( - 'user_avatar' => '', - 'user_avatar_type' => '', - 'user_avatar_width' => 0, - 'user_avatar_height' => 0, - ); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE user_id = $user_id"; - $db->sql_query($sql); - // Delete old avatar if present $phpbb_avatar_manager = $phpbb_container->get('avatar.manager'); - $driver = $phpbb_avatar_manager->get_driver($user_row['user_avatar_type']); - if ($driver) - { - $driver->delete($user_row); - } + $phpbb_avatar_manager->handle_avatar_delete($db, $user, $phpbb_avatar_manager->clean_row($user_row, 'user'), USERS_TABLE, 'user_'); add_log('admin', 'LOG_USER_DEL_AVATAR', $user_row['username']); add_log('user', $user_id, 'LOG_USER_DEL_AVATAR_USER'); @@ -1779,29 +1763,6 @@ class acp_users trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); } } - else - { - $driver = $phpbb_avatar_manager->get_driver($avatar_data['avatar_type']); - if ($driver) - { - $driver->delete($avatar_data); - } - - // Removing the avatar - $result = array( - 'user_avatar' => '', - 'user_avatar_type' => '', - 'user_avatar_width' => 0, - 'user_avatar_height' => 0, - ); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $result) . ' - WHERE user_id = ' . (int) $user_id; - - $db->sql_query($sql); - trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); - } } else { @@ -1809,6 +1770,23 @@ class acp_users } } + // Handle deletion of avatars + if ($request->is_set_post('avatar_delete')) + { + if (!confirm_box(true)) + { + confirm_box(false, $user->lang('CONFIRM_AVATAR_DELETE'), build_hidden_fields(array( + 'avatar_delete' => true)) + ); + } + else + { + $phpbb_avatar_manager->handle_avatar_delete($db, $user, $avatar_data, USERS_TABLE, 'user_'); + + trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); + } + } + $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $user_row['user_avatar_type'])); foreach ($avatar_drivers as $current_driver) diff --git a/phpBB/includes/acp/auth.php b/phpBB/includes/acp/auth.php index 7ff3212b72..905e981cdc 100644 --- a/phpBB/includes/acp/auth.php +++ b/phpBB/includes/acp/auth.php @@ -183,7 +183,10 @@ class auth_admin extends \phpbb\auth\auth } // Defining the user-function here to save some memory - $return_acl_fill = create_function('$value', 'return ' . $acl_fill . ';'); + $return_acl_fill = function () use ($acl_fill) + { + return $acl_fill; + }; // Actually fill the gaps if (sizeof($hold_ary)) diff --git a/phpBB/includes/captcha/captcha_factory.php b/phpBB/includes/captcha/captcha_factory.php deleted file mode 100644 index ebeb695282..0000000000 --- a/phpBB/includes/captcha/captcha_factory.php +++ /dev/null @@ -1,100 +0,0 @@ -<?php -/** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* A small class for 3.0.x (no autoloader in 3.0.x) -*/ -class phpbb_captcha_factory -{ - /** - * return an instance of class $name in file $name_plugin.php - */ - static public function get_instance($name) - { - global $phpbb_root_path, $phpEx; - - $name = basename($name); - if (!class_exists($name)) - { - include($phpbb_root_path . "includes/captcha/plugins/{$name}_plugin." . $phpEx); - } - $instance = call_user_func(array($name, 'get_instance')); - return $instance; - } - - /** - * Call the garbage collector - */ - function garbage_collect($name) - { - global $phpbb_root_path, $phpEx; - - $name = basename($name); - if (!class_exists($name)) - { - include($phpbb_root_path . "includes/captcha/plugins/{$name}_plugin." . $phpEx); - } - $captcha = self::get_instance($name); - $captcha->garbage_collect(0); - } - - /** - * return a list of all discovered CAPTCHA plugins - */ - function get_captcha_types() - { - global $phpbb_root_path, $phpEx, $phpbb_extension_manager; - - $captchas = array( - 'available' => array(), - 'unavailable' => array(), - ); - - $finder = $phpbb_extension_manager->get_finder(); - $captcha_plugin_classes = $finder - ->extension_directory('/captcha') - ->suffix('_plugin') - ->core_path('includes/captcha/plugins/') - ->get_classes(); - - foreach ($captcha_plugin_classes as $class) - { - // check if this class needs to be loaded in legacy mode - $old_class = preg_replace('/^phpbb_captcha_plugins_/', '', $class); - if (file_exists($phpbb_root_path . "includes/captcha/plugins/$old_class.$phpEx") && !class_exists($old_class)) - { - include($phpbb_root_path . "includes/captcha/plugins/$old_class.$phpEx"); - $class = preg_replace('/_plugin$/', '', $old_class); - } - - if (call_user_func(array($class, 'is_available'))) - { - $captchas['available'][$class] = call_user_func(array($class, 'get_name')); - } - else - { - $captchas['unavailable'][$class] = call_user_func(array($class, 'get_name')); - } - } - - return $captchas; - } -} diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_gd_wave_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_gd_wave_plugin.php deleted file mode 100644 index b6ccabaa2e..0000000000 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_gd_wave_plugin.php +++ /dev/null @@ -1,69 +0,0 @@ -<?php -/** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Placeholder for autoload -*/ -if (!class_exists('phpbb_default_captcha', false)) -{ - include($phpbb_root_path . 'includes/captcha/plugins/captcha_abstract.' . $phpEx); -} - -class phpbb_captcha_gd_wave extends phpbb_default_captcha -{ - - function phpbb_captcha_gd_wave() - { - global $phpbb_root_path, $phpEx; - - if (!class_exists('captcha')) - { - include_once($phpbb_root_path . 'includes/captcha/captcha_gd_wave.' . $phpEx); - } - } - - static public function get_instance() - { - return new phpbb_captcha_gd_wave(); - } - - static public function is_available() - { - return @extension_loaded('gd'); - } - - static public function get_name() - { - return 'CAPTCHA_GD_3D'; - } - - function get_class_name() - { - return 'phpbb_captcha_gd_wave'; - } - - function acp_page($id, &$module) - { - global $config, $db, $template, $user; - - trigger_error($user->lang['CAPTCHA_NO_OPTIONS'] . adm_back_link($module->u_action)); - } -} diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_nogd_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_nogd_plugin.php deleted file mode 100644 index 64f788a659..0000000000 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_nogd_plugin.php +++ /dev/null @@ -1,70 +0,0 @@ -<?php -/** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Placeholder for autoload -*/ -if (!class_exists('phpbb_default_captcha', false)) -{ - include($phpbb_root_path . 'includes/captcha/plugins/captcha_abstract.' . $phpEx); -} - -class phpbb_captcha_nogd extends phpbb_default_captcha -{ - - function phpbb_captcha_nogd() - { - global $phpbb_root_path, $phpEx; - - if (!class_exists('captcha')) - { - include_once($phpbb_root_path . 'includes/captcha/captcha_non_gd.' . $phpEx); - } - } - - static public function get_instance() - { - $instance = new phpbb_captcha_nogd(); - return $instance; - } - - static public function is_available() - { - return true; - } - - static public function get_name() - { - return 'CAPTCHA_NO_GD'; - } - - function get_class_name() - { - return 'phpbb_captcha_nogd'; - } - - function acp_page($id, &$module) - { - global $user; - - trigger_error($user->lang['CAPTCHA_NO_OPTIONS'] . adm_back_link($module->u_action)); - } -} diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index cd4e19bf1d..0eac2e9417 100644 --- a/phpBB/includes/constants.php +++ b/phpBB/includes/constants.php @@ -28,7 +28,7 @@ if (!defined('IN_PHPBB')) */ // phpBB Version -define('PHPBB_VERSION', '3.1.0-RC3-dev'); +define('PHPBB_VERSION', '3.1.0-RC4-dev'); // QA-related // define('PHPBB_QA', 1); diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 4318b20b97..c838876ddd 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -1061,7 +1061,7 @@ function phpbb_timezone_select($user, $default = '', $truncate = false) foreach ($unsorted_timezones as $timezone) { $tz = new DateTimeZone($timezone); - $dt = new \phpbb\datetime($user, 'now', $tz); + $dt = $user->create_datetime('now', $tz); $offset = $dt->getOffset(); $current_time = $dt->format($user->lang['DATETIME_FORMAT'], true); $offset_string = phpbb_format_timezone_offset($offset); @@ -2540,7 +2540,7 @@ function check_link_hash($token, $link_name) */ function add_form_key($form_name) { - global $config, $template, $user; + global $config, $template, $user, $phpbb_dispatcher; $now = time(); $token_sid = ($user->data['user_id'] == ANONYMOUS && !empty($config['form_token_sid_guests'])) ? $user->session_id : ''; @@ -2551,6 +2551,27 @@ function add_form_key($form_name) 'form_token' => $token, )); + /** + * Perform additional actions on creation of the form token + * + * @event core.add_form_key + * @var string form_name The form name + * @var int now Current time timestamp + * @var string s_fields Generated hidden fields + * @var string token Form token + * @var string token_sid User session ID + * + * @since 3.1.0-RC3 + */ + $vars = array( + 'form_name', + 'now', + 's_fields', + 'token', + 'token_sid', + ); + extract($phpbb_dispatcher->trigger_event('core.add_form_key', compact($vars))); + $template->assign_vars(array( 'S_FORM_TOKEN' => $s_fields, )); @@ -2730,11 +2751,6 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa global $db, $user, $template, $auth, $phpEx, $phpbb_root_path, $config; global $request, $phpbb_container; - if (!class_exists('phpbb_captcha_factory', false)) - { - include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); - } - $err = ''; // Make sure user->setup() has been called @@ -2844,7 +2860,7 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa { case LOGIN_ERROR_ATTEMPTS: - $captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']); $captcha->init(CONFIRM_LOGIN); // $captcha->reset(); @@ -2956,7 +2972,7 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa */ function login_forum_box($forum_data) { - global $db, $phpbb_container, $request, $template, $user; + global $db, $phpbb_container, $request, $template, $user, $phpbb_dispatcher; $password = $request->variable('password', '', true); @@ -3017,6 +3033,17 @@ function login_forum_box($forum_data) $template->assign_var('LOGIN_ERROR', $user->lang['WRONG_PASSWORD']); } + /** + * Performing additional actions, load additional data on forum login + * + * @event core.login_forum_box + * @var array forum_data Array with forum data + * @var string password Password entered + * @since 3.1.0-RC3 + */ + $vars = array('forum_data', 'password'); + extract($phpbb_dispatcher->trigger_event('core.login_forum_box', compact($vars))); + page_header($user->lang['LOGIN']); $template->assign_vars(array( @@ -4881,7 +4908,7 @@ function page_header($page_title = '', $display_online_list = false, $item_id = } } - $dt = new \phpbb\datetime($user, 'now', $user->timezone); + $dt = $user->create_datetime(); $timezone_offset = 'GMT' . phpbb_format_timezone_offset($dt->getOffset()); $timezone_name = $user->timezone->getName(); if (isset($user->lang['timezones'][$timezone_name])) @@ -5041,6 +5068,20 @@ function page_header($page_title = '', $display_online_list = false, $item_id = 'SITE_LOGO_IMG' => $user->img('site_logo'), )); + // An array of http headers that phpbb will set. The following event may override these. + $http_headers = array( + // application/xhtml+xml not used because of IE + 'Content-type' => 'text/html; charset=UTF-8', + 'Cache-Control' => 'private, no-cache="set-cookie"', + 'Expires' => '0', + 'Pragma' => 'no-cache', + ); + if (!empty($user->data['is_bot'])) + { + // Let reverse proxies know we detected a bot. + $http_headers['X-PHPBB-IS-BOT'] = 'yes'; + } + /** * Execute code and/or overwrite _common_ template variables after they have been assigned. * @@ -5051,23 +5092,16 @@ function page_header($page_title = '', $display_online_list = false, $item_id = * session item, e.g. forum for * session_forum_id * @var int item_id Restrict online users to item id + * @var array http_headers HTTP headers that should be set by phpbb * * @since 3.1.0-b3 */ - $vars = array('page_title', 'display_online_list', 'item_id', 'item'); + $vars = array('page_title', 'display_online_list', 'item_id', 'item', 'http_headers'); extract($phpbb_dispatcher->trigger_event('core.page_header_after', compact($vars))); - // application/xhtml+xml not used because of IE - header('Content-type: text/html; charset=UTF-8'); - - header('Cache-Control: private, no-cache="set-cookie"'); - header('Expires: 0'); - header('Pragma: no-cache'); - - if (!empty($user->data['is_bot'])) + foreach ($http_headers as $hname => $hval) { - // Let reverse proxies know we detected a bot. - header('X-PHPBB-IS-BOT: yes'); + header((string) $hname . ': ' . (string) $hval); } return; @@ -5095,9 +5129,10 @@ function phpbb_check_and_display_sql_report(\phpbb\request\request_interface $re * @param \phpbb\config\config $config Config object * @param \phpbb\auth\auth $auth Auth object * @param \phpbb\user $user User object +* @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher * @return string */ -function phpbb_generate_debug_output(phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\auth\auth $auth, \phpbb\user $user) +function phpbb_generate_debug_output(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\auth\auth $auth, \phpbb\user $user, \phpbb\event\dispatcher_interface $phpbb_dispatcher) { $debug_info = array(); @@ -5136,6 +5171,17 @@ function phpbb_generate_debug_output(phpbb\db\driver\driver_interface $db, \phpb } } + /** + * Modify debug output information + * + * @event core.phpbb_generate_debug_output + * @var array debug_info Array of strings with debug information + * + * @since 3.1.0-RC3 + */ + $vars = array('debug_info'); + extract($phpbb_dispatcher->trigger_event('core.phpbb_generate_debug_output', compact($vars))); + return implode(' | ', $debug_info); } @@ -5174,7 +5220,7 @@ function page_footer($run_cron = true, $display_template = true, $exit_handler = phpbb_check_and_display_sql_report($request, $auth, $db); $template->assign_vars(array( - 'DEBUG_OUTPUT' => phpbb_generate_debug_output($db, $config, $auth, $user), + 'DEBUG_OUTPUT' => phpbb_generate_debug_output($db, $config, $auth, $user, $phpbb_dispatcher), 'TRANSLATION_INFO' => (!empty($user->lang['TRANSLATION_INFO'])) ? $user->lang['TRANSLATION_INFO'] : '', 'CREDIT_LINE' => $user->lang('POWERED_BY', '<a href="https://www.phpbb.com/">phpBB</a>® Forum Software © phpBB Limited'), diff --git a/phpBB/includes/functions_acp.php b/phpBB/includes/functions_acp.php index ad5a359710..d9dc11239c 100644 --- a/phpBB/includes/functions_acp.php +++ b/phpBB/includes/functions_acp.php @@ -107,12 +107,31 @@ function adm_page_header($page_title) 'S_CONTENT_FLOW_END' => ($user->lang['DIRECTION'] == 'ltr') ? 'right' : 'left', )); - // application/xhtml+xml not used because of IE - header('Content-type: text/html; charset=UTF-8'); + // An array of http headers that phpbb will set. The following event may override these. + $http_headers = array( + // application/xhtml+xml not used because of IE + 'Content-type' => 'text/html; charset=UTF-8', + 'Cache-Control' => 'private, no-cache="set-cookie"', + 'Expires' => '0', + 'Pragma' => 'no-cache', + ); - header('Cache-Control: private, no-cache="set-cookie"'); - header('Expires: 0'); - header('Pragma: no-cache'); + /** + * Execute code and/or overwrite _common_ template variables after they have been assigned. + * + * @event core.adm_page_header_after + * @var string page_title Page title + * @var array http_headers HTTP headers that should be set by phpbb + * + * @since 3.1.0-RC3 + */ + $vars = array('page_title', 'http_headers'); + extract($phpbb_dispatcher->trigger_event('core.adm_page_header_after', compact($vars))); + + foreach ($http_headers as $hname => $hval) + { + header((string) $hname . ': ' . (string) $hval); + } return; } @@ -149,7 +168,7 @@ function adm_page_footer($copyright_html = true) phpbb_check_and_display_sql_report($request, $auth, $db); $template->assign_vars(array( - 'DEBUG_OUTPUT' => phpbb_generate_debug_output($db, $config, $auth, $user), + 'DEBUG_OUTPUT' => phpbb_generate_debug_output($db, $config, $auth, $user, $phpbb_dispatcher), 'TRANSLATION_INFO' => (!empty($user->lang['TRANSLATION_INFO'])) ? $user->lang['TRANSLATION_INFO'] : '', 'S_COPYRIGHT_HTML' => $copyright_html, 'CREDIT_LINE' => $user->lang('POWERED_BY', '<a href="https://www.phpbb.com/">phpBB</a>® Forum Software © phpBB Limited'), @@ -655,3 +674,30 @@ function validate_range($value_ary, &$error) } } } + +/** +* Inserts new config display_vars into an exisiting display_vars array +* at the given position. +* +* @param array $display_vars An array of existing config display vars +* @param array $add_config_vars An array of new config display vars +* @param array $where Where to place the new config vars, +* before or after an exisiting config, as an array +* of the form: array('after' => 'config_name') or +* array('before' => 'config_name'). +* @return array The array of config display vars +*/ +function phpbb_insert_config_array($display_vars, $add_config_vars, $where) +{ + if (is_array($where) && array_key_exists(current($where), $display_vars)) + { + $position = array_search(current($where), array_keys($display_vars)) + ((key($where) == 'before') ? 0 : 1); + $display_vars = array_merge( + array_slice($display_vars, 0, $position), + $add_config_vars, + array_slice($display_vars, $position) + ); + } + + return $display_vars; +} diff --git a/phpBB/includes/functions_display.php b/phpBB/includes/functions_display.php index 62f218cf60..78137d075b 100644 --- a/phpBB/includes/functions_display.php +++ b/phpBB/includes/functions_display.php @@ -1421,44 +1421,6 @@ function get_user_rank($user_rank, $user_posts, &$rank_title, &$rank_img, &$rank } /** -* Generate a list of archive types available for compressing attachments -* -* @param string $param_key Either topic_id or post_id -* @param string $param_val The value of the topic or post id -* @param string $phpbb_root_path The root path of the phpBB installation -* @param string $phpEx The PHP file extension -* -* @return array Array containing the link and the type of compression -*/ -function phpbb_gen_download_links($param_key, $param_val, $phpbb_root_path, $phpEx) -{ - if (!class_exists('compress')) - { - require $phpbb_root_path . 'includes/functions_compress.' . $phpEx; - } - - $methods = compress::methods(); - // Sort by preferred type. - $methods = array_intersect(array('.zip', '.tar.bz2', '.tar.gz', '.tar'), $methods); - $links = array(); - - foreach ($methods as $method) - { - $exploded = explode('.', $method); - $type = array_pop($exploded); - $params = array('archive' => $method); - $params[$param_key] = $param_val; - - $links[] = array( - 'LINK' => append_sid("{$phpbb_root_path}download/file.$phpEx", $params), - 'TYPE' => $type, - ); - } - - return $links; -} - -/** * Prepare profile data */ function phpbb_show_profile($data, $user_notes_enabled = false, $warn_user_enabled = false) diff --git a/phpBB/includes/functions_download.php b/phpBB/includes/functions_download.php index 7a7efd5b34..4ff3994f4c 100644 --- a/phpBB/includes/functions_download.php +++ b/phpBB/includes/functions_download.php @@ -718,27 +718,6 @@ function phpbb_download_check_pm_auth($db, $user_id, $msg_id) } /** -* Cleans a filename of any characters that could potentially cause a problem on -* a user's filesystem. -* -* @param string $filename The filename to clean -* -* @return string The cleaned filename -*/ -function phpbb_download_clean_filename($filename) -{ - $bad_chars = array("'", "\\", ' ', '/', ':', '*', '?', '"', '<', '>', '|'); - - // rawurlencode to convert any potentially 'bad' characters that we missed - $filename = rawurlencode(str_replace($bad_chars, '_', $filename)); - - // Turn the %xx entities created by rawurlencode to _ - $filename = preg_replace("/%(\w{2})/", '_', $filename); - - return $filename; -} - -/** * Check if the browser is internet explorer version 7+ * * @param string $user_agent User agent HTTP header diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php index 3657a89aa0..045e555d05 100644 --- a/phpBB/includes/functions_messenger.php +++ b/phpBB/includes/functions_messenger.php @@ -402,17 +402,9 @@ class messenger */ function generate_message_id() { - global $config; + global $config, $request; - $domain = 'phpbb.generated'; - if ($config['server_name']) - { - $domain = $config['server_name']; - } - else if (!empty($_SERVER['SERVER_NAME'])) - { - $domain = $_SERVER['SERVER_NAME']; - } + $domain = ($config['server_name']) ?: $request->server('SERVER_NAME', 'phpbb.generated'); return md5(unique_id(time())) . '@' . $domain; } diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index fb09bc7057..624ce187b9 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -1324,18 +1324,7 @@ function delete_post($forum_id, $topic_id, $post_id, &$data, $is_soft = false, $ { delete_topics('topic_id', array($topic_id), false); - if ($data['topic_visibility'] == ITEM_APPROVED) - { - $sql_data[FORUMS_TABLE] .= 'forum_posts_approved = forum_posts_approved - 1, forum_topics_approved = forum_topics_approved - 1'; - } - else if ($data['topic_visibility'] == ITEM_UNAPPROVED || $data['post_visibility'] == ITEM_REAPPROVE) - { - $sql_data[FORUMS_TABLE] .= 'forum_posts_unapproved = forum_posts_unapproved - 1, forum_topics_unapproved = forum_topics_unapproved - 1'; - } - else if ($data['topic_visibility'] == ITEM_DELETED) - { - $sql_data[FORUMS_TABLE] .= 'forum_posts_softdeleted = forum_posts_softdeleted - 1, forum_topics_softdeleted = forum_topics_softdeleted - 1'; - } + $phpbb_content_visibility->remove_topic_from_statistic($data, $sql_data); $update_sql = update_post_information('forum', $forum_id, true); if (sizeof($update_sql)) diff --git a/phpBB/includes/functions_upload.php b/phpBB/includes/functions_upload.php index e973e6ec28..a0a67ccf3d 100644 --- a/phpBB/includes/functions_upload.php +++ b/phpBB/includes/functions_upload.php @@ -586,6 +586,7 @@ class fileupload * Upload file from users harddisk * * @param string $form_name Form name assigned to the file input field (if it is an array, the key has to be specified) + * @param \phpbb\mimetype\guesser $mimetype_guesser Mimetype guesser * @param \phpbb\plupload\plupload $plupload The plupload object * * @return object $file Object "filespec" is returned, all further operations can be done with this object @@ -743,6 +744,7 @@ class fileupload * Uploads file from given url * * @param string $upload_url URL pointing to file to upload, for example http://www.foobar.com/example.gif + * @param \phpbb\mimetype\guesser $mimetype_guesser Mimetype guesser * @return object $file Object "filespec" is returned, all further operations can be done with this object * @access public */ diff --git a/phpBB/includes/mcp/mcp_front.php b/phpBB/includes/mcp/mcp_front.php index 98773d5b0e..b4ec0092e7 100644 --- a/phpBB/includes/mcp/mcp_front.php +++ b/phpBB/includes/mcp/mcp_front.php @@ -26,6 +26,7 @@ function mcp_front_view($id, $mode, $action) { global $phpEx, $phpbb_root_path, $config; global $template, $db, $user, $auth, $module; + global $phpbb_dispatcher; // Latest 5 unapproved if ($module->loaded('queue')) @@ -80,6 +81,19 @@ function mcp_front_view($id, $mode, $action) } } + /** + * Alter list of posts and total as required + * + * @event core.mcp_front_view_queue_postid_list_after + * @var int total Number of unapproved posts + * @var array post_list List of unapproved posts + * @var array forum_list List of forums that contain the posts + * @var array forum_names Associative array with forum_id as key and it's corresponding forum_name as value + * @since 3.1.0-RC3 + */ + $vars = array('total', 'post_list', 'forum_list', 'forum_names'); + extract($phpbb_dispatcher->trigger_event('core.mcp_front_view_queue_postid_list_after', compact($vars))); + if ($total) { $sql = 'SELECT p.post_id, p.post_subject, p.post_time, p.post_attachment, p.poster_id, p.post_username, u.username, u.username_clean, u.user_colour, t.topic_id, t.topic_title, t.topic_first_post_id, p.forum_id diff --git a/phpBB/includes/mcp/mcp_main.php b/phpBB/includes/mcp/mcp_main.php index 9f6125f256..92000c6ceb 100644 --- a/phpBB/includes/mcp/mcp_main.php +++ b/phpBB/includes/mcp/mcp_main.php @@ -1114,6 +1114,7 @@ function mcp_fork_topic($topic_ids) $forum_id = request_var('f', 0); $redirect = request_var('redirect', build_url(array('action', 'quickmod'))); $additional_msg = $success_msg = ''; + $counter = array(); $s_hidden_fields = build_hidden_fields(array( 'topic_id_list' => $topic_ids, @@ -1306,9 +1307,20 @@ function mcp_fork_topic($topic_ids) 'post_edit_time' => (int) $row['post_edit_time'], 'post_edit_count' => (int) $row['post_edit_count'], 'post_edit_locked' => (int) $row['post_edit_locked'], - 'post_postcount' => 0, + 'post_postcount' => $row['post_postcount'], ); - + // Adjust post count only if the post can be incremented to the user counter + if ($row['post_postcount']) + { + if (isset($counter[$row['poster_id']])) + { + ++$counter[$row['poster_id']]; + } + else + { + $counter[$row['poster_id']] = 1; + } + } $db->sql_query('INSERT INTO ' . POSTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); $new_post_id = $db->sql_nextid(); @@ -1428,6 +1440,18 @@ function mcp_fork_topic($topic_ids) WHERE forum_id = ' . $to_forum_id; $db->sql_query($sql); + if (!empty($counter)) + { + // Do only one query per user and not a query per post. + foreach ($counter as $user_id => $count) + { + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_posts = user_posts + ' . (int) $count . ' + WHERE user_id = ' . (int) $user_id; + $db->sql_query($sql); + } + } + sync('topic', 'topic_id', $new_topic_id_list); sync('forum', 'forum_id', $to_forum_id); diff --git a/phpBB/includes/mcp/mcp_queue.php b/phpBB/includes/mcp/mcp_queue.php index 37ce3c6fc3..b7e47163a6 100644 --- a/phpBB/includes/mcp/mcp_queue.php +++ b/phpBB/includes/mcp/mcp_queue.php @@ -37,6 +37,7 @@ class mcp_queue { global $auth, $db, $user, $template, $cache, $request; global $config, $phpbb_root_path, $phpEx, $action, $phpbb_container; + global $phpbb_dispatcher; include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx); @@ -429,6 +430,29 @@ class mcp_queue OR t.topic_delete_user = 0) $limit_time_sql ORDER BY $sort_order_sql"; + + /** + * Alter sql query to get posts in queue to be accepted + * + * @event core.mcp_queue_get_posts_query_before + * @var string sql Associative array with the query to be executed + * @var array forum_list List of forums that contain the posts + * @var int visibility_const Integer with one of the possible ITEM_* constant values + * @var int topic_id If topic_id not equal to 0, the topic id to filter the posts to display + * @var string limit_time_sql String with the SQL code to limit the time interval of the post (Note: May be empty string) + * @var string sort_order_sql String with the ORDER BY SQL code used in this query + * @since 3.1.0-RC3 + */ + $vars = array( + 'sql', + 'forum_list', + 'visibility_const', + 'topic_id', + 'limit_time_sql', + 'sort_order_sql', + ); + extract($phpbb_dispatcher->trigger_event('core.mcp_queue_get_posts_query_before', compact($vars))); + $result = $db->sql_query_limit($sql, $config['topics_per_page'], $start); $i = 0; @@ -478,6 +502,29 @@ class mcp_queue AND topic_delete_user <> 0 $limit_time_sql ORDER BY $sort_order_sql"; + + /** + * Alter sql query to get information on all topics in the list of forums provided. + * + * @event core.mcp_queue_get_posts_for_topics_query_before + * @var string sql String with the query to be executed + * @var array forum_list List of forums that contain the posts + * @var int visibility_const Integer with one of the possible ITEM_* constant values + * @var int topic_id topic_id in the page request + * @var string limit_time_sql String with the SQL code to limit the time interval of the post (Note: May be empty string) + * @var string sort_order_sql String with the ORDER BY SQL code used in this query + * @since 3.1.0-RC3 + */ + $vars = array( + 'sql', + 'forum_list', + 'visibility_const', + 'topic_id', + 'limit_time_sql', + 'sort_order_sql', + ); + extract($phpbb_dispatcher->trigger_event('core.mcp_queue_get_posts_for_topics_query_before', compact($vars))); + $result = $db->sql_query_limit($sql, $config['topics_per_page'], $start); $rowset = array(); diff --git a/phpBB/includes/ucp/ucp_confirm.php b/phpBB/includes/ucp/ucp_confirm.php index bcba32cdf6..7392f8dea8 100644 --- a/phpBB/includes/ucp/ucp_confirm.php +++ b/phpBB/includes/ucp/ucp_confirm.php @@ -36,10 +36,9 @@ class ucp_confirm function main($id, $mode) { - global $db, $user, $phpbb_root_path, $config, $phpEx; + global $db, $user, $phpbb_root_path, $config, $phpEx, $phpbb_container; - include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); - $captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']); $captcha->init(request_var('type', 0)); $captcha->execute(); diff --git a/phpBB/includes/ucp/ucp_groups.php b/phpBB/includes/ucp/ucp_groups.php index e4931fbe23..b9606945b4 100644 --- a/phpBB/includes/ucp/ucp_groups.php +++ b/phpBB/includes/ucp/ucp_groups.php @@ -471,6 +471,29 @@ class ucp_groups $avatar_data = \phpbb\avatar\manager::clean_row($group_row, 'group'); } + // Handle deletion of avatars + if ($request->is_set_post('avatar_delete')) + { + if (confirm_box(true)) + { + $phpbb_avatar_manager->handle_avatar_delete($db, $user, $avatar_data, GROUPS_TABLE, 'group_'); + $cache->destroy('sql', GROUPS_TABLE); + + $message = ($action == 'edit') ? 'GROUP_UPDATED' : 'GROUP_CREATED'; + trigger_error($user->lang[$message] . $return_page); + } + else + { + confirm_box(false, $user->lang('CONFIRM_AVATAR_DELETE'), build_hidden_fields(array( + 'avatar_delete' => true, + 'i' => $id, + 'mode' => $mode, + 'g' => $group_id, + 'action' => $action)) + ); + } + } + // Did we submit? if ($update) { @@ -510,19 +533,6 @@ class ucp_groups $submit_ary = array_merge($submit_ary, $result); } } - else - { - if ($driver = $phpbb_avatar_manager->get_driver($avatar_data['avatar_type'])) - { - $driver->delete($avatar_data); - } - - // Removing the avatar - $submit_ary['avatar_type'] = ''; - $submit_ary['avatar'] = ''; - $submit_ary['avatar_width'] = 0; - $submit_ary['avatar_height'] = 0; - } // Merge any avatars errors into the primary error array $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error)); diff --git a/phpBB/includes/ucp/ucp_login_link.php b/phpBB/includes/ucp/ucp_login_link.php index a8762313fd..5ca5df00f7 100644 --- a/phpBB/includes/ucp/ucp_login_link.php +++ b/phpBB/includes/ucp/ucp_login_link.php @@ -181,7 +181,7 @@ class ucp_login_link */ protected function process_login_result($result) { - global $config, $request, $template, $user; + global $config, $request, $template, $user, $phpbb_container; $login_error = null; @@ -197,7 +197,7 @@ class ucp_login_link { case LOGIN_ERROR_ATTEMPTS: - $captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']); $captcha->init(CONFIRM_LOGIN); $template->assign_vars(array( diff --git a/phpBB/includes/ucp/ucp_pm_viewmessage.php b/phpBB/includes/ucp/ucp_pm_viewmessage.php index 94383b935f..d5a1dbae87 100644 --- a/phpBB/includes/ucp/ucp_pm_viewmessage.php +++ b/phpBB/includes/ucp/ucp_pm_viewmessage.php @@ -250,7 +250,6 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) 'U_PM_ACTION' => $url . '&mode=compose&f=' . $folder_id . '&p=' . $message_row['msg_id'], 'S_HAS_ATTACHMENTS' => (sizeof($attachments)) ? true : false, - 'S_HAS_MULTIPLE_ATTACHMENTS' => (sizeof($attachments) > 1), 'S_DISPLAY_NOTICE' => $display_notice && $message_row['message_attachment'], 'S_AUTHOR_DELETED' => ($author_id == ANONYMOUS) ? true : false, 'S_SPECIAL_FOLDER' => in_array($folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)), @@ -339,12 +338,6 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) // Display not already displayed Attachments for this post, we already parsed them. ;) if (isset($attachments) && sizeof($attachments)) { - $methods = phpbb_gen_download_links('msg_id', $msg_id, $phpbb_root_path, $phpEx); - foreach ($methods as $method) - { - $template->assign_block_vars('dl_method', $method); - } - foreach ($attachments as $attachment) { $template->assign_block_vars('attachment', array( diff --git a/phpBB/includes/ucp/ucp_profile.php b/phpBB/includes/ucp/ucp_profile.php index a315b167d7..361dc831aa 100644 --- a/phpBB/includes/ucp/ucp_profile.php +++ b/phpBB/includes/ucp/ucp_profile.php @@ -564,30 +564,6 @@ class ucp_profile trigger_error($message); } } - else - { - if ($driver = $phpbb_avatar_manager->get_driver($avatar_data['avatar_type'])) - { - $driver->delete($avatar_data); - } - - $result = array( - 'user_avatar' => '', - 'user_avatar_type' => '', - 'user_avatar_width' => 0, - 'user_avatar_height' => 0, - ); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $result) . ' - WHERE user_id = ' . (int) $user->data['user_id']; - - $db->sql_query($sql); - - meta_refresh(3, $this->u_action); - $message = $user->lang['PROFILE_UPDATED'] . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>'); - trigger_error($message); - } } else { @@ -595,6 +571,27 @@ class ucp_profile } } + // Handle deletion of avatars + if ($request->is_set_post('avatar_delete')) + { + if (!confirm_box(true)) + { + confirm_box(false, $user->lang('CONFIRM_AVATAR_DELETE'), build_hidden_fields(array( + 'avatar_delete' => true, + 'i' => $id, + 'mode' => $mode)) + ); + } + else + { + $phpbb_avatar_manager->handle_avatar_delete($db, $user, $avatar_data, USERS_TABLE, 'user_'); + + meta_refresh(3, $this->u_action); + $message = $user->lang['PROFILE_UPDATED'] . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>'); + trigger_error($message); + } + } + $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $user->data['user_avatar_type'])); foreach ($avatar_drivers as $current_driver) diff --git a/phpBB/includes/ucp/ucp_register.php b/phpBB/includes/ucp/ucp_register.php index 97934fc32d..a303197563 100644 --- a/phpBB/includes/ucp/ucp_register.php +++ b/phpBB/includes/ucp/ucp_register.php @@ -182,8 +182,7 @@ class ucp_register // The CAPTCHA kicks in here. We can't help that the information gets lost on language change. if ($config['enable_confirm']) { - include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); - $captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']); $captcha->init(CONFIRM_REG); } diff --git a/phpBB/install/convertors/convert_phpbb20.php b/phpBB/install/convertors/convert_phpbb20.php index 696075b07c..de0cccd234 100644 --- a/phpBB/install/convertors/convert_phpbb20.php +++ b/phpBB/install/convertors/convert_phpbb20.php @@ -38,7 +38,7 @@ $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms); $convertor_data = array( 'forum_name' => 'phpBB 2.0.x', 'version' => '1.0.3', - 'phpbb_version' => '3.1.0-RC2', + 'phpbb_version' => '3.1.0-RC3', 'author' => '<a href="https://www.phpbb.com/">phpBB Limited</a>', 'dbms' => $dbms, 'dbhost' => $dbhost, diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 517143792a..6a91033dbb 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -13,10 +13,6 @@ $update_start_time = time(); -use Symfony\Component\Config\FileLocator; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; - /** * @ignore */ diff --git a/phpBB/install/index.php b/phpBB/install/index.php index d443c537fa..2e497da3db 100644 --- a/phpBB/install/index.php +++ b/phpBB/install/index.php @@ -11,10 +11,6 @@ * */ -use Symfony\Component\Config\FileLocator; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; - /**#@+ * @ignore */ @@ -244,7 +240,7 @@ $sub = $request->variable('sub', ''); // Set PHP error handler to ours set_error_handler(defined('PHPBB_MSG_HANDLER') ? PHPBB_MSG_HANDLER : 'msg_handler'); -$user = new \phpbb\user(); +$user = new \phpbb\user('\phpbb\datetime'); $auth = new \phpbb\auth\auth(); // Add own hook handler, if present. :o diff --git a/phpBB/install/install_install.php b/phpBB/install/install_install.php index b82df84a00..20b211dde9 100644 --- a/phpBB/install/install_install.php +++ b/phpBB/install/install_install.php @@ -1382,7 +1382,7 @@ class install_install extends module if (@extension_loaded('gd')) { $sql_ary[] = 'UPDATE ' . $data['table_prefix'] . "config - SET config_value = 'phpbb_captcha_gd' + SET config_value = 'core.captcha.plugins.gd' WHERE config_name = 'captcha_plugin'"; $sql_ary[] = 'UPDATE ' . $data['table_prefix'] . "config diff --git a/phpBB/install/install_update.php b/phpBB/install/install_update.php index 28777a8d24..82ca0fc18d 100644 --- a/phpBB/install/install_update.php +++ b/phpBB/install/install_update.php @@ -1063,6 +1063,14 @@ class install_update extends module $transfer->write_file($file_struct['filename'], $contents); } break; + + case 'deleted': + + if ($update_mode != 'download') + { + $transfer->rename($file_struct['filename'], $file_struct['filename'] . '.bak'); + } + break; } } } diff --git a/phpBB/install/schemas/schema.json b/phpBB/install/schemas/schema.json index 1a9b9b62b7..b71b1fecbe 100644 --- a/phpBB/install/schemas/schema.json +++ b/phpBB/install/schemas/schema.json @@ -2088,16 +2088,12 @@ "UINT", 0 ], - "pf_phpbb_skype": [ - "VCHAR", - "" - ], - "pf_phpbb_twitter": [ - "VCHAR", + "pf_phpbb_interests": [ + "MTEXT", "" ], - "pf_phpbb_youtube": [ - "VCHAR", + "pf_phpbb_occupation": [ + "MTEXT", "" ], "pf_phpbb_facebook": [ @@ -2108,19 +2104,19 @@ "VCHAR", "" ], - "pf_phpbb_interests": [ - "MTEXT", + "pf_phpbb_icq": [ + "VCHAR", "" ], - "pf_phpbb_occupation": [ - "MTEXT", + "pf_phpbb_location": [ + "VCHAR", "" ], - "pf_phpbb_icq": [ + "pf_phpbb_skype": [ "VCHAR", "" ], - "pf_phpbb_location": [ + "pf_phpbb_twitter": [ "VCHAR", "" ], @@ -2136,6 +2132,10 @@ "VCHAR", "" ], + "pf_phpbb_youtube": [ + "VCHAR", + "" + ], "pf_phpbb_aol": [ "VCHAR", "" @@ -2711,8 +2711,9 @@ 0 ], "topic_first_poster_name": [ - "VCHAR_UNI", - "" + "VCHAR_UNI:255", + "", + "true_sort" ], "topic_first_poster_colour": [ "VCHAR:6", diff --git a/phpBB/install/schemas/schema_data.sql b/phpBB/install/schemas/schema_data.sql index 9cc151f728..37e1c8de50 100644 --- a/phpBB/install/schemas/schema_data.sql +++ b/phpBB/install/schemas/schema_data.sql @@ -70,7 +70,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('browser_check', '1 INSERT INTO phpbb_config (config_name, config_value) VALUES ('bump_interval', '10'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('bump_type', 'd'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('cache_gc', '7200'); -INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_plugin', 'phpbb_captcha_nogd'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_plugin', 'core.captcha.plugins.nogd'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_gd', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_gd_foreground_noise', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_gd_x_grid', '25'); @@ -273,7 +273,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('tpl_allow_php', '0 INSERT INTO phpbb_config (config_name, config_value) VALUES ('upload_icons_path', 'images/upload_icons'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('upload_path', 'files'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('use_system_cron', '0'); -INSERT INTO phpbb_config (config_name, config_value) VALUES ('version', '3.1.0-RC3-dev'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('version', '3.1.0-RC4-dev'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('warnings_expire_days', '90'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('warnings_gc', '14400'); diff --git a/phpBB/language/en/common.php b/phpBB/language/en/common.php index a58aec43cd..783faa8fad 100644 --- a/phpBB/language/en/common.php +++ b/phpBB/language/en/common.php @@ -167,6 +167,7 @@ $lang = array_merge($lang, array( 'CONFIRM_CODE_EXPLAIN' => 'Enter the code exactly as it appears. All letters are case insensitive.', 'CONFIRM_CODE_WRONG' => 'The confirmation code you entered was incorrect.', 'CONFIRM_OPERATION' => 'Are you sure you wish to carry out this operation?', + 'CONFIRM_AVATAR_DELETE' => 'Are you sure you wish to delete this avatar?', 'CONGRATULATIONS' => 'Congratulations to', 'CONNECTION_FAILED' => 'Connection failed.', 'CONNECTION_SUCCESS' => 'Connection was successful!', @@ -191,8 +192,6 @@ $lang = array_merge($lang, array( 'DISPLAY_MESSAGES' => 'Display messages from previous', 'DISPLAY_POSTS' => 'Display posts from previous', 'DISPLAY_TOPICS' => 'Display topics from previous', - 'DOWNLOAD_ALL' => 'Download all', - 'DOWNLOAD_ALL_ATTACHMENTS' => 'Download all attachments', 'DOWNLOADED' => 'Downloaded', 'DOWNLOADING_FILE' => 'Downloading file', 'DOWNLOAD_COUNTS' => array( @@ -483,7 +482,6 @@ $lang = array_merge($lang, array( 'NO_AUTH_ADMIN_USER_DIFFER' => 'You are not able to re-authenticate as a different user.', 'NO_AUTH_OPERATION' => 'You do not have the necessary permissions to complete this operation.', 'NO_AVATARS' => 'No avatars currently available', - 'NO_AVATAR_SELECTED' => 'You have not selected any avatar.', 'NO_CONNECT_TO_SMTP_HOST' => 'Could not connect to smtp host : %1$s : %2$s', 'NO_BIRTHDAYS' => 'No birthdays today', 'NO_EMAIL_MESSAGE' => 'Email message was blank.', diff --git a/phpBB/phpbb/auth/provider/db.php b/phpBB/phpbb/auth/provider/db.php index 142a47247f..722eeffa9a 100644 --- a/phpBB/phpbb/auth/provider/db.php +++ b/phpBB/phpbb/auth/provider/db.php @@ -27,6 +27,13 @@ class db extends \phpbb\auth\provider\base protected $passwords_manager; /** + * DI container + * + * @var \Symfony\Component\DependencyInjection\ContainerInterface + */ + protected $phpbb_container; + + /** * Database Authentication Constructor * * @param \phpbb\db\driver\driver_interface $db @@ -34,10 +41,11 @@ class db extends \phpbb\auth\provider\base * @param \phpbb\passwords\manager $passwords_manager * @param \phpbb\request\request $request * @param \phpbb\user $user + * @param \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container DI container * @param string $phpbb_root_path * @param string $php_ext */ - public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\passwords\manager $passwords_manager, \phpbb\request\request $request, \phpbb\user $user, $phpbb_root_path, $php_ext) + public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\passwords\manager $passwords_manager, \phpbb\request\request $request, \phpbb\user $user, \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container, $phpbb_root_path, $php_ext) { $this->db = $db; $this->config = $config; @@ -46,6 +54,7 @@ class db extends \phpbb\auth\provider\base $this->user = $user; $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; + $this->phpbb_container = $phpbb_container; } /** @@ -146,13 +155,8 @@ class db extends \phpbb\auth\provider\base // Every auth module is able to define what to do by itself... if ($show_captcha) { - // Visual Confirmation handling - if (!class_exists('phpbb_captcha_factory', false)) - { - include ($this->phpbb_root_path . 'includes/captcha/captcha_factory.' . $this->php_ext); - } - - $captcha = \phpbb_captcha_factory::get_instance($this->config['captcha_plugin']); + $captcha_factory = $this->phpbb_container->get('captcha.factory'); + $captcha = $captcha_factory->get_instance($this->config['captcha_plugin']); $captcha->init(CONFIRM_LOGIN); $vc_response = $captcha->validate($row); if ($vc_response) diff --git a/phpBB/phpbb/avatar/driver/gravatar.php b/phpBB/phpbb/avatar/driver/gravatar.php index 4aa7445d20..2082e0fd02 100644 --- a/phpBB/phpbb/avatar/driver/gravatar.php +++ b/phpBB/phpbb/avatar/driver/gravatar.php @@ -69,6 +69,11 @@ class gravatar extends \phpbb\avatar\driver\driver $row['avatar_width'] = $request->variable('avatar_gravatar_width', 0); $row['avatar_height'] = $request->variable('avatar_gravatar_height', 0); + if (empty($row['avatar'])) + { + return false; + } + if (!function_exists('validate_data')) { require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext); diff --git a/phpBB/phpbb/avatar/driver/local.php b/phpBB/phpbb/avatar/driver/local.php index ff1996854b..07b3ed59de 100644 --- a/phpBB/phpbb/avatar/driver/local.php +++ b/phpBB/phpbb/avatar/driver/local.php @@ -120,7 +120,6 @@ class local extends \phpbb\avatar\driver\driver if (empty($category) || empty($file)) { - $error[] = 'NO_AVATAR_SELECTED'; return false; } diff --git a/phpBB/phpbb/avatar/driver/remote.php b/phpBB/phpbb/avatar/driver/remote.php index 455ddebf62..1bd7f6c927 100644 --- a/phpBB/phpbb/avatar/driver/remote.php +++ b/phpBB/phpbb/avatar/driver/remote.php @@ -53,6 +53,11 @@ class remote extends \phpbb\avatar\driver\driver $width = $request->variable('avatar_remote_width', 0); $height = $request->variable('avatar_remote_height', 0); + if (empty($url)) + { + return false; + } + if (!preg_match('#^(http|https|ftp)://#i', $url)) { $url = 'http://' . $url; diff --git a/phpBB/phpbb/avatar/driver/upload.php b/phpBB/phpbb/avatar/driver/upload.php index edc5941602..003b23659f 100644 --- a/phpBB/phpbb/avatar/driver/upload.php +++ b/phpBB/phpbb/avatar/driver/upload.php @@ -27,7 +27,6 @@ class upload extends \phpbb\avatar\driver\driver * Construct a driver object * * @param \phpbb\config\config $config phpBB configuration - * @param \phpbb\request\request $request Request object * @param string $phpbb_root_path Path to the phpBB root * @param string $php_ext PHP file extension * @param \phpbb_path_helper $path_helper phpBB path helper @@ -130,7 +129,6 @@ class upload extends \phpbb\avatar\driver\driver } else { - $error[] = 'NO_AVATAR_SELECTED'; return false; } diff --git a/phpBB/phpbb/avatar/manager.php b/phpBB/phpbb/avatar/manager.php index 7cf136be2c..42ae61a9a2 100644 --- a/phpBB/phpbb/avatar/manager.php +++ b/phpBB/phpbb/avatar/manager.php @@ -41,8 +41,8 @@ class manager static protected $default_row = array( 'avatar' => '', 'avatar_type' => '', - 'avatar_width' => '', - 'avatar_height' => '', + 'avatar_width' => 0, + 'avatar_height' => 0, ); /** @@ -307,4 +307,36 @@ class manager return $error; } + + /** + * Handle deleting avatars + * + * @param \phpbb\db\driver\driver_interface $db phpBB dbal + * @param \phpbb\user $user phpBB user object + * @param array $avatar_data Cleaned user data containing the user's + * avatar data + * @param string $table Database table from which the avatar should be deleted + * @param string $prefix Prefix of user data columns in database + * @return null + */ + public function handle_avatar_delete(\phpbb\db\driver\driver_interface $db, \phpbb\user $user, $avatar_data, $table, $prefix) + { + if ($driver = $this->get_driver($avatar_data['avatar_type'])) + { + $driver->delete($avatar_data); + } + + $result = self::$default_row; + + foreach ($result as $key => $value) + { + $result[$prefix . $key] = $value; + unset($result[$key]); + } + + $sql = 'UPDATE ' . $table . ' + SET ' . $db->sql_build_array('UPDATE', $result) . ' + WHERE ' . $prefix . 'id = ' . (int) $avatar_data['id']; + $db->sql_query($sql); + } } diff --git a/phpBB/phpbb/cache/driver/base.php b/phpBB/phpbb/cache/driver/base.php index 685cdc4e57..4c20ad916d 100644 --- a/phpBB/phpbb/cache/driver/base.php +++ b/phpBB/phpbb/cache/driver/base.php @@ -15,4 +15,217 @@ namespace phpbb\cache\driver; abstract class base implements \phpbb\cache\driver\driver_interface { + var $vars = array(); + var $is_modified = false; + + var $sql_rowset = array(); + var $sql_row_pointer = array(); + var $cache_dir = ''; + + /** + * {@inheritDoc} + */ + function purge() + { + // Purge all phpbb cache files + try + { + $iterator = new \DirectoryIterator($this->cache_dir); + } + catch (\Exception $e) + { + return; + } + + foreach ($iterator as $fileInfo) + { + if ($fileInfo->isDot()) + { + continue; + } + $filename = $fileInfo->getFilename(); + if ($fileInfo->isDir()) + { + $this->remove_dir($fileInfo->getPathname()); + } + else if (strpos($filename, 'container_') === 0 || + strpos($filename, 'url_matcher') === 0 || + strpos($filename, 'sql_') === 0 || + strpos($filename, 'data_') === 0) + { + $this->remove_file($fileInfo->getPathname()); + } + } + + unset($this->vars); + unset($this->sql_rowset); + unset($this->sql_row_pointer); + + $this->vars = array(); + $this->sql_rowset = array(); + $this->sql_row_pointer = array(); + + $this->is_modified = false; + } + + /** + * {@inheritDoc} + */ + function unload() + { + $this->save(); + unset($this->vars); + unset($this->sql_rowset); + unset($this->sql_row_pointer); + + $this->vars = array(); + $this->sql_rowset = array(); + $this->sql_row_pointer = array(); + } + + /** + * {@inheritDoc} + */ + function sql_load($query) + { + // Remove extra spaces and tabs + $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); + + if (($rowset = $this->_read('sql_' . md5($query))) === false) + { + return false; + } + + $query_id = sizeof($this->sql_rowset); + $this->sql_rowset[$query_id] = $rowset; + $this->sql_row_pointer[$query_id] = 0; + + return $query_id; + } + + /** + * {@inheritDoc} + */ + function sql_exists($query_id) + { + return isset($this->sql_rowset[$query_id]); + } + + /** + * {@inheritDoc} + */ + function sql_fetchrow($query_id) + { + if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id])) + { + return $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++]; + } + + return false; + } + + /** + * {@inheritDoc} + */ + function sql_fetchfield($query_id, $field) + { + if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id])) + { + return (isset($this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field])) ? $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++][$field] : false; + } + + return false; + } + + /** + * {@inheritDoc} + */ + function sql_rowseek($rownum, $query_id) + { + if ($rownum >= sizeof($this->sql_rowset[$query_id])) + { + return false; + } + + $this->sql_row_pointer[$query_id] = $rownum; + return true; + } + + /** + * {@inheritDoc} + */ + function sql_freeresult($query_id) + { + if (!isset($this->sql_rowset[$query_id])) + { + return false; + } + + unset($this->sql_rowset[$query_id]); + unset($this->sql_row_pointer[$query_id]); + + return true; + } + + /** + * Removes/unlinks file + * + * @param string $filename Filename to remove + * @param bool $check Check file permissions + * @return bool True if the file was successfully removed, otherwise false + */ + function remove_file($filename, $check = false) + { + if (!function_exists('phpbb_is_writable')) + { + global $phpbb_root_path, $phpEx; + include($phpbb_root_path . 'includes/functions.' . $phpEx); + } + + if ($check && !phpbb_is_writable($this->cache_dir)) + { + // E_USER_ERROR - not using language entry - intended. + trigger_error('Unable to remove files within ' . $this->cache_dir . '. Please check directory permissions.', E_USER_ERROR); + } + + return @unlink($filename); + } + + /** + * Remove directory + * + * @param string $dir Directory to remove + * + * @return null + */ + protected function remove_dir($dir) + { + try + { + $iterator = new \DirectoryIterator($dir); + } + catch (\Exception $e) + { + return; + } + + foreach ($iterator as $fileInfo) + { + if ($fileInfo->isDot()) + { + continue; + } + + if ($fileInfo->isDir()) + { + $this->remove_dir($fileInfo->getPathname()); + } + else + { + $this->remove_file($fileInfo->getPathname()); + } + } + + @rmdir($dir); + } } diff --git a/phpBB/phpbb/cache/driver/file.php b/phpBB/phpbb/cache/driver/file.php index 2d538b739c..fd5bce4515 100644 --- a/phpBB/phpbb/cache/driver/file.php +++ b/phpBB/phpbb/cache/driver/file.php @@ -18,13 +18,7 @@ namespace phpbb\cache\driver; */ class file extends \phpbb\cache\driver\base { - var $vars = array(); var $var_expires = array(); - var $is_modified = false; - - var $sql_rowset = array(); - var $sql_row_pointer = array(); - var $cache_dir = ''; /** * Set cache path @@ -50,16 +44,9 @@ class file extends \phpbb\cache\driver\base */ function unload() { - $this->save(); - unset($this->vars); + parent::unload(); unset($this->var_expires); - unset($this->sql_rowset); - unset($this->sql_row_pointer); - - $this->vars = array(); $this->var_expires = array(); - $this->sql_rowset = array(); - $this->sql_row_pointer = array(); } /** @@ -166,8 +153,6 @@ class file extends \phpbb\cache\driver\base { if ($var_name[0] == '_') { - global $phpEx; - if (!$this->_exists($var_name)) { return false; @@ -203,85 +188,8 @@ class file extends \phpbb\cache\driver\base */ function purge() { - // Purge all phpbb cache files - try - { - $iterator = new \DirectoryIterator($this->cache_dir); - } - catch (\Exception $e) - { - return; - } - - foreach ($iterator as $fileInfo) - { - if ($fileInfo->isDot()) - { - continue; - } - $filename = $fileInfo->getFilename(); - if ($fileInfo->isDir()) - { - $this->remove_dir($fileInfo->getPathname()); - } - else if (strpos($filename, 'container_') === 0 || - strpos($filename, 'url_matcher') === 0 || - strpos($filename, 'sql_') === 0 || - strpos($filename, 'data_') === 0) - { - $this->remove_file($fileInfo->getPathname()); - } - } - - unset($this->vars); - unset($this->var_expires); - unset($this->sql_rowset); - unset($this->sql_row_pointer); - - $this->vars = array(); + parent::purge(); $this->var_expires = array(); - $this->sql_rowset = array(); - $this->sql_row_pointer = array(); - - $this->is_modified = false; - } - - /** - * Remove directory - * - * @param string $dir Directory to remove - * - * @return null - */ - protected function remove_dir($dir) - { - try - { - $iterator = new \DirectoryIterator($dir); - } - catch (\Exception $e) - { - return; - } - - foreach ($iterator as $fileInfo) - { - if ($fileInfo->isDot()) - { - continue; - } - - if ($fileInfo->isDir()) - { - $this->remove_dir($fileInfo->getPathname()); - } - else - { - $this->remove_file($fileInfo->getPathname()); - } - } - - @rmdir($dir); } /** @@ -392,26 +300,6 @@ class file extends \phpbb\cache\driver\base /** * {@inheritDoc} */ - function sql_load($query) - { - // Remove extra spaces and tabs - $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); - - if (($rowset = $this->_read('sql_' . md5($query))) === false) - { - return false; - } - - $query_id = sizeof($this->sql_rowset); - $this->sql_rowset[$query_id] = $rowset; - $this->sql_row_pointer[$query_id] = 0; - - return $query_id; - } - - /** - * {@inheritDoc} - */ function sql_save(\phpbb\db\driver\driver_interface $db, $query, $query_result, $ttl) { // Remove extra spaces and tabs @@ -436,70 +324,6 @@ class file extends \phpbb\cache\driver\base } /** - * {@inheritDoc} - */ - function sql_exists($query_id) - { - return isset($this->sql_rowset[$query_id]); - } - - /** - * {@inheritDoc} - */ - function sql_fetchrow($query_id) - { - if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id])) - { - return $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++]; - } - - return false; - } - - /** - * {@inheritDoc} - */ - function sql_fetchfield($query_id, $field) - { - if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id])) - { - return (isset($this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field])) ? $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++][$field] : false; - } - - return false; - } - - /** - * {@inheritDoc} - */ - function sql_rowseek($rownum, $query_id) - { - if ($rownum >= sizeof($this->sql_rowset[$query_id])) - { - return false; - } - - $this->sql_row_pointer[$query_id] = $rownum; - return true; - } - - /** - * {@inheritDoc} - */ - function sql_freeresult($query_id) - { - if (!isset($this->sql_rowset[$query_id])) - { - return false; - } - - unset($this->sql_rowset[$query_id]); - unset($this->sql_row_pointer[$query_id]); - - return true; - } - - /** * Read cached data from a specified file * * @access private @@ -760,28 +584,4 @@ class file extends \phpbb\cache\driver\base return $return_value; } - - /** - * Removes/unlinks file - * - * @param string $filename Filename to remove - * @param bool $check Check file permissions - * @return bool True if the file was successfully removed, otherwise false - */ - function remove_file($filename, $check = false) - { - if (!function_exists('phpbb_is_writable')) - { - global $phpbb_root_path, $phpEx; - include($phpbb_root_path . 'includes/functions.' . $phpEx); - } - - if ($check && !phpbb_is_writable($this->cache_dir)) - { - // E_USER_ERROR - not using language entry - intended. - trigger_error('Unable to remove files within ' . $this->cache_dir . '. Please check directory permissions.', E_USER_ERROR); - } - - return @unlink($filename); - } } diff --git a/phpBB/phpbb/cache/driver/memory.php b/phpBB/phpbb/cache/driver/memory.php index 5dee375192..56308be8da 100644 --- a/phpBB/phpbb/cache/driver/memory.php +++ b/phpBB/phpbb/cache/driver/memory.php @@ -20,13 +20,6 @@ abstract class memory extends \phpbb\cache\driver\base { var $key_prefix; - var $vars = array(); - var $is_modified = false; - - var $sql_rowset = array(); - var $sql_row_pointer = array(); - var $cache_dir = ''; - /** * Set cache path */ @@ -71,21 +64,6 @@ abstract class memory extends \phpbb\cache\driver\base /** * {@inheritDoc} */ - function unload() - { - $this->save(); - unset($this->vars); - unset($this->sql_rowset); - unset($this->sql_row_pointer); - - $this->vars = array(); - $this->sql_rowset = array(); - $this->sql_row_pointer = array(); - } - - /** - * {@inheritDoc} - */ function save() { if (!$this->is_modified) @@ -147,47 +125,6 @@ abstract class memory extends \phpbb\cache\driver\base /** * {@inheritDoc} */ - function purge() - { - // Purge all phpbb cache files - $dir = @opendir($this->cache_dir); - - if (!$dir) - { - return; - } - - while (($entry = readdir($dir)) !== false) - { - if (strpos($entry, 'container_') !== 0 && - strpos($entry, 'url_matcher') !== 0 && - strpos($entry, 'sql_') !== 0 && - strpos($entry, 'data_') !== 0 && - strpos($entry, 'ctpl_') !== 0 && - strpos($entry, 'tpl_') !== 0) - { - continue; - } - - $this->remove_file($this->cache_dir . $entry); - } - closedir($dir); - - unset($this->vars); - unset($this->sql_rowset); - unset($this->sql_row_pointer); - - $this->vars = array(); - $this->sql_rowset = array(); - $this->sql_row_pointer = array(); - - $this->is_modified = false; - } - - - /** - * {@inheritDoc} - */ function destroy($var_name, $table = '') { if ($var_name == 'sql' && !empty($table)) @@ -262,26 +199,6 @@ abstract class memory extends \phpbb\cache\driver\base /** * {@inheritDoc} */ - function sql_load($query) - { - // Remove extra spaces and tabs - $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); - $query_id = sizeof($this->sql_rowset); - - if (($result = $this->_read('sql_' . md5($query))) === false) - { - return false; - } - - $this->sql_rowset[$query_id] = $result; - $this->sql_row_pointer[$query_id] = 0; - - return $query_id; - } - - /** - * {@inheritDoc} - */ function sql_save(\phpbb\db\driver\driver_interface $db, $query, $query_result, $ttl) { // Remove extra spaces and tabs @@ -338,94 +255,6 @@ abstract class memory extends \phpbb\cache\driver\base } /** - * {@inheritDoc} - */ - function sql_exists($query_id) - { - return isset($this->sql_rowset[$query_id]); - } - - /** - * {@inheritDoc} - */ - function sql_fetchrow($query_id) - { - if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id])) - { - return $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++]; - } - - return false; - } - - /** - * {@inheritDoc} - */ - function sql_fetchfield($query_id, $field) - { - if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id])) - { - return (isset($this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field])) ? $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++][$field] : false; - } - - return false; - } - - /** - * {@inheritDoc} - */ - function sql_rowseek($rownum, $query_id) - { - if ($rownum >= sizeof($this->sql_rowset[$query_id])) - { - return false; - } - - $this->sql_row_pointer[$query_id] = $rownum; - return true; - } - - /** - * {@inheritDoc} - */ - function sql_freeresult($query_id) - { - if (!isset($this->sql_rowset[$query_id])) - { - return false; - } - - unset($this->sql_rowset[$query_id]); - unset($this->sql_row_pointer[$query_id]); - - return true; - } - - /** - * Removes/unlinks file - * - * @param string $filename Filename to remove - * @param bool $check Check file permissions - * @return bool True if the file was successfully removed, otherwise false - */ - function remove_file($filename, $check = false) - { - if (!function_exists('phpbb_is_writable')) - { - global $phpbb_root_path, $phpEx; - include($phpbb_root_path . 'includes/functions.' . $phpEx); - } - - if ($check && !phpbb_is_writable($this->cache_dir)) - { - // E_USER_ERROR - not using language entry - intended. - trigger_error('Unable to remove files within ' . $this->cache_dir . '. Please check directory permissions.', E_USER_ERROR); - } - - return @unlink($filename); - } - - /** * Check if a cache var exists * * @access protected diff --git a/phpBB/phpbb/captcha/char_cube3d.php b/phpBB/phpbb/captcha/char_cube3d.php new file mode 100644 index 0000000000..a712b16dce --- /dev/null +++ b/phpBB/phpbb/captcha/char_cube3d.php @@ -0,0 +1,277 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\captcha; + +class char_cube3d +{ + var $bitmap; + var $bitmap_width; + var $bitmap_height; + + var $basis_matrix = array(array(1, 0, 0), array(0, 1, 0), array(0, 0, 1)); + var $abs_x = array(1, 0); + var $abs_y = array(0, 1); + var $x = 0; + var $y = 1; + var $z = 2; + var $letter = ''; + + /** + */ + function __construct(&$bitmaps, $letter) + { + $this->bitmap = $bitmaps['data'][$letter]; + $this->bitmap_width = $bitmaps['width']; + $this->bitmap_height = $bitmaps['height']; + + $this->basis_matrix[0][0] = mt_rand(-600, 600); + $this->basis_matrix[0][1] = mt_rand(-600, 600); + $this->basis_matrix[0][2] = (mt_rand(0, 1) * 2000) - 1000; + $this->basis_matrix[1][0] = mt_rand(-1000, 1000); + $this->basis_matrix[1][1] = mt_rand(-1000, 1000); + $this->basis_matrix[1][2] = mt_rand(-1000, 1000); + + $this->normalize($this->basis_matrix[0]); + $this->normalize($this->basis_matrix[1]); + $this->basis_matrix[2] = $this->cross_product($this->basis_matrix[0], $this->basis_matrix[1]); + $this->normalize($this->basis_matrix[2]); + + // $this->basis_matrix[1] might not be (probably isn't) orthogonal to $basis_matrix[0] + $this->basis_matrix[1] = $this->cross_product($this->basis_matrix[0], $this->basis_matrix[2]); + $this->normalize($this->basis_matrix[1]); + + // Make sure our cube is facing into the canvas (assuming +z == in) + for ($i = 0; $i < 3; ++$i) + { + if ($this->basis_matrix[$i][2] < 0) + { + $this->basis_matrix[$i][0] *= -1; + $this->basis_matrix[$i][1] *= -1; + $this->basis_matrix[$i][2] *= -1; + } + } + + // Force our "z" basis vector to be the one with greatest absolute z value + $this->x = 0; + $this->y = 1; + $this->z = 2; + + // Swap "y" with "z" + if ($this->basis_matrix[1][2] > $this->basis_matrix[2][2]) + { + $this->z = 1; + $this->y = 2; + } + + // Swap "x" with "z" + if ($this->basis_matrix[0][2] > $this->basis_matrix[$this->z][2]) + { + $this->x = $this->z; + $this->z = 0; + } + + // Still need to determine which of $x,$y are which. + // wrong orientation if y's y-component is less than it's x-component + // likewise if x's x-component is less than it's y-component + // if they disagree, go with the one with the greater weight difference. + // rotate if positive + $weight = (abs($this->basis_matrix[$this->x][1]) - abs($this->basis_matrix[$this->x][0])) + (abs($this->basis_matrix[$this->y][0]) - abs($this->basis_matrix[$this->y][1])); + + // Swap "x" with "y" + if ($weight > 0) + { + list($this->x, $this->y) = array($this->y, $this->x); + } + + $this->abs_x = array($this->basis_matrix[$this->x][0], $this->basis_matrix[$this->x][1]); + $this->abs_y = array($this->basis_matrix[$this->y][0], $this->basis_matrix[$this->y][1]); + + if ($this->abs_x[0] < 0) + { + $this->abs_x[0] *= -1; + $this->abs_x[1] *= -1; + } + + if ($this->abs_y[1] > 0) + { + $this->abs_y[0] *= -1; + $this->abs_y[1] *= -1; + } + + $this->letter = $letter; + } + + /** + * Draw a character + */ + function drawchar($scale, $xoff, $yoff, $img, $background, $colours) + { + $width = $this->bitmap_width; + $height = $this->bitmap_height; + $bitmap = $this->bitmap; + + $colour1 = $colours[array_rand($colours)]; + $colour2 = $colours[array_rand($colours)]; + + $swapx = ($this->basis_matrix[$this->x][0] > 0); + $swapy = ($this->basis_matrix[$this->y][1] < 0); + + for ($y = 0; $y < $height; ++$y) + { + for ($x = 0; $x < $width; ++$x) + { + $xp = ($swapx) ? ($width - $x - 1) : $x; + $yp = ($swapy) ? ($height - $y - 1) : $y; + + if ($bitmap[$height - $yp - 1][$xp]) + { + $dx = $this->scale($this->abs_x, ($xp - ($swapx ? ($width / 2) : ($width / 2) - 1)) * $scale); + $dy = $this->scale($this->abs_y, ($yp - ($swapy ? ($height / 2) : ($height / 2) - 1)) * $scale); + $xo = $xoff + $dx[0] + $dy[0]; + $yo = $yoff + $dx[1] + $dy[1]; + + $origin = array(0, 0, 0); + $xvec = $this->scale($this->basis_matrix[$this->x], $scale); + $yvec = $this->scale($this->basis_matrix[$this->y], $scale); + $face_corner = $this->sum2($xvec, $yvec); + + $zvec = $this->scale($this->basis_matrix[$this->z], $scale); + $x_corner = $this->sum2($xvec, $zvec); + $y_corner = $this->sum2($yvec, $zvec); + + imagefilledpolygon($img, $this->gen_poly($xo, $yo, $origin, $xvec, $x_corner,$zvec), 4, $colour1); + imagefilledpolygon($img, $this->gen_poly($xo, $yo, $origin, $yvec, $y_corner,$zvec), 4, $colour2); + + $face = $this->gen_poly($xo, $yo, $origin, $xvec, $face_corner, $yvec); + + imagefilledpolygon($img, $face, 4, $background); + imagepolygon($img, $face, 4, $colour1); + } + } + } + } + + /* + * return a roughly acceptable range of sizes for rendering with this texttype + */ + function range() + { + return array(3, 4); + } + + /** + * Vector length + */ + function vectorlen($vector) + { + return sqrt(pow($vector[0], 2) + pow($vector[1], 2) + pow($vector[2], 2)); + } + + /** + * Normalize + */ + function normalize(&$vector, $length = 1) + { + $length = (( $length < 1) ? 1 : $length); + $length /= $this->vectorlen($vector); + $vector[0] *= $length; + $vector[1] *= $length; + $vector[2] *= $length; + } + + /** + */ + function cross_product($vector1, $vector2) + { + $retval = array(0, 0, 0); + $retval[0] = (($vector1[1] * $vector2[2]) - ($vector1[2] * $vector2[1])); + $retval[1] = -(($vector1[0] * $vector2[2]) - ($vector1[2] * $vector2[0])); + $retval[2] = (($vector1[0] * $vector2[1]) - ($vector1[1] * $vector2[0])); + + return $retval; + } + + /** + */ + function sum($vector1, $vector2) + { + return array($vector1[0] + $vector2[0], $vector1[1] + $vector2[1], $vector1[2] + $vector2[2]); + } + + /** + */ + function sum2($vector1, $vector2) + { + return array($vector1[0] + $vector2[0], $vector1[1] + $vector2[1]); + } + + /** + */ + function scale($vector, $length) + { + if (sizeof($vector) == 2) + { + return array($vector[0] * $length, $vector[1] * $length); + } + + return array($vector[0] * $length, $vector[1] * $length, $vector[2] * $length); + } + + /** + */ + function gen_poly($xoff, $yoff, &$vec1, &$vec2, &$vec3, &$vec4) + { + $poly = array(); + $poly[0] = $xoff + $vec1[0]; + $poly[1] = $yoff + $vec1[1]; + $poly[2] = $xoff + $vec2[0]; + $poly[3] = $yoff + $vec2[1]; + $poly[4] = $xoff + $vec3[0]; + $poly[5] = $yoff + $vec3[1]; + $poly[6] = $xoff + $vec4[0]; + $poly[7] = $yoff + $vec4[1]; + + return $poly; + } + + /** + * dimensions + */ + function dimensions($size) + { + $xn = $this->scale($this->basis_matrix[$this->x], -($this->bitmap_width / 2) * $size); + $xp = $this->scale($this->basis_matrix[$this->x], ($this->bitmap_width / 2) * $size); + $yn = $this->scale($this->basis_matrix[$this->y], -($this->bitmap_height / 2) * $size); + $yp = $this->scale($this->basis_matrix[$this->y], ($this->bitmap_height / 2) * $size); + + $p = array(); + $p[0] = $this->sum2($xn, $yn); + $p[1] = $this->sum2($xp, $yn); + $p[2] = $this->sum2($xp, $yp); + $p[3] = $this->sum2($xn, $yp); + + $min_x = $max_x = $p[0][0]; + $min_y = $max_y = $p[0][1]; + + for ($i = 1; $i < 4; ++$i) + { + $min_x = ($min_x > $p[$i][0]) ? $p[$i][0] : $min_x; + $min_y = ($min_y > $p[$i][1]) ? $p[$i][1] : $min_y; + $max_x = ($max_x < $p[$i][0]) ? $p[$i][0] : $max_x; + $max_y = ($max_y < $p[$i][1]) ? $p[$i][1] : $max_y; + } + + return array($min_x, $min_y, $max_x, $max_y); + } +} diff --git a/phpBB/phpbb/captcha/colour_manager.php b/phpBB/phpbb/captcha/colour_manager.php new file mode 100644 index 0000000000..6ca3c3fd2c --- /dev/null +++ b/phpBB/phpbb/captcha/colour_manager.php @@ -0,0 +1,527 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\captcha; + +class colour_manager +{ + var $img; + var $mode; + var $colours; + var $named_colours; + + /** + * Create the colour manager, link it to the image resource + */ + function __construct($img, $background = false, $mode = 'ahsv') + { + $this->img = $img; + $this->mode = $mode; + $this->colours = array(); + $this->named_colours = array(); + + if ($background !== false) + { + $bg = $this->allocate_named('background', $background); + imagefill($this->img, 0, 0, $bg); + } + } + + /** + * Lookup a named colour resource + */ + function get_resource($named_colour) + { + if (isset($this->named_colours[$named_colour])) + { + return $this->named_colours[$named_colour]; + } + + if (isset($this->named_rgb[$named_colour])) + { + return $this->allocate_named($named_colour, $this->named_rgb[$named_colour], 'rgb'); + } + + return false; + } + + /** + * Assign a name to a colour resource + */ + function name_colour($name, $resource) + { + $this->named_colours[$name] = $resource; + } + + /** + * names and allocates a colour resource + */ + function allocate_named($name, $colour, $mode = false) + { + $resource = $this->allocate($colour, $mode); + + if ($resource !== false) + { + $this->name_colour($name, $resource); + } + return $resource; + } + + /** + * allocates a specified colour into the image + */ + function allocate($colour, $mode = false) + { + if ($mode === false) + { + $mode = $this->mode; + } + + if (!is_array($colour)) + { + if (isset($this->named_rgb[$colour])) + { + return $this->allocate_named($colour, $this->named_rgb[$colour], 'rgb'); + } + + if (!is_int($colour)) + { + return false; + } + + $mode = 'rgb'; + $colour = array(255 & ($colour >> 16), 255 & ($colour >> 8), 255 & $colour); + } + + if (isset($colour['mode'])) + { + $mode = $colour['mode']; + unset($colour['mode']); + } + + if (isset($colour['random'])) + { + unset($colour['random']); + // everything else is params + return $this->random_colour($colour, $mode); + } + + $rgb = $this->model_convert($colour, $mode, 'rgb'); + $store = ($this->mode == 'rgb') ? $rgb : $this->model_convert($colour, $mode, $this->mode); + $resource = imagecolorallocate($this->img, $rgb[0], $rgb[1], $rgb[2]); + $this->colours[$resource] = $store; + + return $resource; + } + + /** + * randomly generates a colour, with optional params + */ + function random_colour($params = array(), $mode = false) + { + if ($mode === false) + { + $mode = $this->mode; + } + + switch ($mode) + { + case 'rgb': + // @TODO random rgb generation. do we intend to do this, or is it just too tedious? + break; + + case 'ahsv': + case 'hsv': + default: + + $default_params = array( + 'hue_bias' => false, // degree / 'r'/'g'/'b'/'c'/'m'/'y' /'o' + 'hue_range' => false, // if hue bias, then difference range +/- from bias + 'min_saturation' => 30, // 0 - 100 + 'max_saturation' => 80, // 0 - 100 + 'min_value' => 30, // 0 - 100 + 'max_value' => 80, // 0 - 100 + ); + + $alt = ($mode == 'ahsv') ? true : false; + $params = array_merge($default_params, $params); + + $min_hue = 0; + $max_hue = 359; + $min_saturation = max(0, $params['min_saturation']); + $max_saturation = min(100, $params['max_saturation']); + $min_value = max(0, $params['min_value']); + $max_value = min(100, $params['max_value']); + + if ($params['hue_bias'] !== false) + { + if (is_numeric($params['hue_bias'])) + { + $h = intval($params['hue_bias']) % 360; + } + else + { + switch ($params['hue_bias']) + { + case 'o': + $h = $alt ? 60 : 30; + break; + + case 'y': + $h = $alt ? 120 : 60; + break; + + case 'g': + $h = $alt ? 180 : 120; + break; + + case 'c': + $h = $alt ? 210 : 180; + break; + + case 'b': + $h = 240; + break; + + case 'm': + $h = 300; + break; + + case 'r': + default: + $h = 0; + break; + } + } + + $min_hue = $h + 360; + $max_hue = $h + 360; + + if ($params['hue_range']) + { + $min_hue -= min(180, $params['hue_range']); + $max_hue += min(180, $params['hue_range']); + } + } + + $h = mt_rand($min_hue, $max_hue); + $s = mt_rand($min_saturation, $max_saturation); + $v = mt_rand($min_value, $max_value); + + return $this->allocate(array($h, $s, $v), $mode); + + break; + } + } + + /** + */ + function colour_scheme($resource, $include_original = true) + { + $mode = 'hsv'; + + if (($pre = $this->get_resource($resource)) !== false) + { + $resource = $pre; + } + + $colour = $this->model_convert($this->colours[$resource], $this->mode, $mode); + $results = ($include_original) ? array($resource) : array(); + $colour2 = $colour3 = $colour4 = $colour; + $colour2[0] += 150; + $colour3[0] += 180; + $colour4[0] += 210; + + $results[] = $this->allocate($colour2, $mode); + $results[] = $this->allocate($colour3, $mode); + $results[] = $this->allocate($colour4, $mode); + + return $results; + } + + /** + */ + function mono_range($resource, $count = 5, $include_original = true) + { + if (is_array($resource)) + { + $results = array(); + for ($i = 0, $size = sizeof($resource); $i < $size; ++$i) + { + $results = array_merge($results, $this->mono_range($resource[$i], $count, $include_original)); + } + return $results; + } + + $mode = (in_array($this->mode, array('hsv', 'ahsv'), true) ? $this->mode : 'ahsv'); + if (($pre = $this->get_resource($resource)) !== false) + { + $resource = $pre; + } + + $colour = $this->model_convert($this->colours[$resource], $this->mode, $mode); + + $results = array(); + if ($include_original) + { + $results[] = $resource; + $count--; + } + + // This is a hard problem. I chicken out and try to maintain readability at the cost of less randomness. + + while ($count > 0) + { + $colour[1] = ($colour[1] + mt_rand(40,60)) % 99; + $colour[2] = ($colour[2] + mt_rand(40,60)); + $results[] = $this->allocate($colour, $mode); + $count--; + } + return $results; + } + + /** + * Convert from one colour model to another + */ + function model_convert($colour, $from_model, $to_model) + { + if ($from_model == $to_model) + { + return $colour; + } + + switch ($to_model) + { + case 'hsv': + + switch ($from_model) + { + case 'ahsv': + return $this->ah2h($colour); + break; + + case 'rgb': + return $this->rgb2hsv($colour); + break; + } + break; + + case 'ahsv': + + switch ($from_model) + { + case 'hsv': + return $this->h2ah($colour); + break; + + case 'rgb': + return $this->h2ah($this->rgb2hsv($colour)); + break; + } + break; + + case 'rgb': + switch ($from_model) + { + case 'hsv': + return $this->hsv2rgb($colour); + break; + + case 'ahsv': + return $this->hsv2rgb($this->ah2h($colour)); + break; + } + break; + } + return false; + } + + /** + * Slightly altered from wikipedia's algorithm + */ + function hsv2rgb($hsv) + { + $this->normalize_hue($hsv[0]); + + $h = $hsv[0]; + $s = min(1, max(0, $hsv[1] / 100)); + $v = min(1, max(0, $hsv[2] / 100)); + + // calculate hue sector + $hi = floor($hsv[0] / 60); + + // calculate opposite colour + $p = $v * (1 - $s); + + // calculate distance between hex vertices + $f = ($h / 60) - $hi; + + // coming in or going out? + if (!($hi & 1)) + { + $f = 1 - $f; + } + + // calculate adjacent colour + $q = $v * (1 - ($f * $s)); + + switch ($hi) + { + case 0: + $rgb = array($v, $q, $p); + break; + + case 1: + $rgb = array($q, $v, $p); + break; + + case 2: + $rgb = array($p, $v, $q); + break; + + case 3: + $rgb = array($p, $q, $v); + break; + + case 4: + $rgb = array($q, $p, $v); + break; + + case 5: + $rgb = array($v, $p, $q); + break; + + default: + return array(0, 0, 0); + break; + } + + return array(255 * $rgb[0], 255 * $rgb[1], 255 * $rgb[2]); + } + + /** + * (more than) Slightly altered from wikipedia's algorithm + */ + function rgb2hsv($rgb) + { + $r = min(255, max(0, $rgb[0])); + $g = min(255, max(0, $rgb[1])); + $b = min(255, max(0, $rgb[2])); + $max = max($r, $g, $b); + $min = min($r, $g, $b); + + $v = $max / 255; + $s = (!$max) ? 0 : 1 - ($min / $max); + + // if max - min is 0, we want hue to be 0 anyway. + $h = $max - $min; + + if ($h) + { + switch ($max) + { + case $g: + $h = 120 + (60 * ($b - $r) / $h); + break; + + case $b: + $h = 240 + (60 * ($r - $g) / $h); + break; + + case $r: + $h = 360 + (60 * ($g - $b) / $h); + break; + } + } + $this->normalize_hue($h); + + return array($h, $s * 100, $v * 100); + } + + /** + */ + function normalize_hue(&$hue) + { + $hue %= 360; + + if ($hue < 0) + { + $hue += 360; + } + } + + /** + * Alternate hue to hue + */ + function ah2h($ahue) + { + if (is_array($ahue)) + { + $ahue[0] = $this->ah2h($ahue[0]); + return $ahue; + } + $this->normalize_hue($ahue); + + // blue through red is already ok + if ($ahue >= 240) + { + return $ahue; + } + + // ahue green is at 180 + if ($ahue >= 180) + { + // return (240 - (2 * (240 - $ahue))); + return (2 * $ahue) - 240; // equivalent + } + + // ahue yellow is at 120 (RYB rather than RGB) + if ($ahue >= 120) + { + return $ahue - 60; + } + + return $ahue / 2; + } + + /** + * hue to Alternate hue + */ + function h2ah($hue) + { + if (is_array($hue)) + { + $hue[0] = $this->h2ah($hue[0]); + return $hue; + } + $this->normalize_hue($hue); + + // blue through red is already ok + if ($hue >= 240) + { + return $hue; + } + else if ($hue <= 60) + { + return $hue * 2; + } + else if ($hue <= 120) + { + return $hue + 60; + } + else + { + return ($hue + 240) / 2; + } + } +} diff --git a/phpBB/phpbb/captcha/factory.php b/phpBB/phpbb/captcha/factory.php new file mode 100644 index 0000000000..dd44aca8bb --- /dev/null +++ b/phpBB/phpbb/captcha/factory.php @@ -0,0 +1,88 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\captcha; + +class factory +{ + /** + * @var \Symfony\Component\DependencyInjection\ContainerInterface + */ + private $container; + + /** + * @var \phpbb\di\service_collection + */ + private $plugins; + + /** + * Constructor + * + * @param \Symfony\Component\DependencyInjection\ContainerInterface $container + * @param \phpbb\di\service_collection $plugins + */ + public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, \phpbb\di\service_collection $plugins) + { + $this->container = $container; + $this->plugins = $plugins; + } + + /** + * Return a new instance of a given plugin + * + * @param $name + * @return object + */ + public function get_instance($name) + { + return $this->container->get($name); + } + + /** + * Call the garbage collector + * + * @param string $name The name to the captcha service. + */ + function garbage_collect($name) + { + $captcha = $this->get_instance($name); + $captcha->garbage_collect(0); + } + + /** + * Return a list of all registered CAPTCHA plugins + * + * @returns array + */ + function get_captcha_types() + { + $captchas = array( + 'available' => array(), + 'unavailable' => array(), + ); + + foreach ($this->plugins as $plugin => $plugin_instance) + { + if ($plugin_instance->is_available()) + { + $captchas['available'][$plugin] = $plugin_instance->get_name(); + } + else + { + $captchas['unavailable'][$plugin] = $plugin_instance->get_name(); + } + } + + return $captchas; + } +} diff --git a/phpBB/includes/captcha/captcha_gd.php b/phpBB/phpbb/captcha/gd.php index 7e37cc33f9..652df28f8a 100644 --- a/phpBB/includes/captcha/captcha_gd.php +++ b/phpBB/phpbb/captcha/gd.php @@ -11,15 +11,9 @@ * */ -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} +namespace phpbb\captcha; -class captcha +class gd { var $width = 360; var $height = 96; @@ -1851,779 +1845,3 @@ class captcha ); } } - -class char_cube3d -{ - var $bitmap; - var $bitmap_width; - var $bitmap_height; - - var $basis_matrix = array(array(1, 0, 0), array(0, 1, 0), array(0, 0, 1)); - var $abs_x = array(1, 0); - var $abs_y = array(0, 1); - var $x = 0; - var $y = 1; - var $z = 2; - var $letter = ''; - - /** - */ - function char_cube3d(&$bitmaps, $letter) - { - $this->bitmap = $bitmaps['data'][$letter]; - $this->bitmap_width = $bitmaps['width']; - $this->bitmap_height = $bitmaps['height']; - - $this->basis_matrix[0][0] = mt_rand(-600, 600); - $this->basis_matrix[0][1] = mt_rand(-600, 600); - $this->basis_matrix[0][2] = (mt_rand(0, 1) * 2000) - 1000; - $this->basis_matrix[1][0] = mt_rand(-1000, 1000); - $this->basis_matrix[1][1] = mt_rand(-1000, 1000); - $this->basis_matrix[1][2] = mt_rand(-1000, 1000); - - $this->normalize($this->basis_matrix[0]); - $this->normalize($this->basis_matrix[1]); - $this->basis_matrix[2] = $this->cross_product($this->basis_matrix[0], $this->basis_matrix[1]); - $this->normalize($this->basis_matrix[2]); - - // $this->basis_matrix[1] might not be (probably isn't) orthogonal to $basis_matrix[0] - $this->basis_matrix[1] = $this->cross_product($this->basis_matrix[0], $this->basis_matrix[2]); - $this->normalize($this->basis_matrix[1]); - - // Make sure our cube is facing into the canvas (assuming +z == in) - for ($i = 0; $i < 3; ++$i) - { - if ($this->basis_matrix[$i][2] < 0) - { - $this->basis_matrix[$i][0] *= -1; - $this->basis_matrix[$i][1] *= -1; - $this->basis_matrix[$i][2] *= -1; - } - } - - // Force our "z" basis vector to be the one with greatest absolute z value - $this->x = 0; - $this->y = 1; - $this->z = 2; - - // Swap "y" with "z" - if ($this->basis_matrix[1][2] > $this->basis_matrix[2][2]) - { - $this->z = 1; - $this->y = 2; - } - - // Swap "x" with "z" - if ($this->basis_matrix[0][2] > $this->basis_matrix[$this->z][2]) - { - $this->x = $this->z; - $this->z = 0; - } - - // Still need to determine which of $x,$y are which. - // wrong orientation if y's y-component is less than it's x-component - // likewise if x's x-component is less than it's y-component - // if they disagree, go with the one with the greater weight difference. - // rotate if positive - $weight = (abs($this->basis_matrix[$this->x][1]) - abs($this->basis_matrix[$this->x][0])) + (abs($this->basis_matrix[$this->y][0]) - abs($this->basis_matrix[$this->y][1])); - - // Swap "x" with "y" - if ($weight > 0) - { - list($this->x, $this->y) = array($this->y, $this->x); - } - - $this->abs_x = array($this->basis_matrix[$this->x][0], $this->basis_matrix[$this->x][1]); - $this->abs_y = array($this->basis_matrix[$this->y][0], $this->basis_matrix[$this->y][1]); - - if ($this->abs_x[0] < 0) - { - $this->abs_x[0] *= -1; - $this->abs_x[1] *= -1; - } - - if ($this->abs_y[1] > 0) - { - $this->abs_y[0] *= -1; - $this->abs_y[1] *= -1; - } - - $this->letter = $letter; - } - - /** - * Draw a character - */ - function drawchar($scale, $xoff, $yoff, $img, $background, $colours) - { - $width = $this->bitmap_width; - $height = $this->bitmap_height; - $bitmap = $this->bitmap; - - $colour1 = $colours[array_rand($colours)]; - $colour2 = $colours[array_rand($colours)]; - - $swapx = ($this->basis_matrix[$this->x][0] > 0); - $swapy = ($this->basis_matrix[$this->y][1] < 0); - - for ($y = 0; $y < $height; ++$y) - { - for ($x = 0; $x < $width; ++$x) - { - $xp = ($swapx) ? ($width - $x - 1) : $x; - $yp = ($swapy) ? ($height - $y - 1) : $y; - - if ($bitmap[$height - $yp - 1][$xp]) - { - $dx = $this->scale($this->abs_x, ($xp - ($swapx ? ($width / 2) : ($width / 2) - 1)) * $scale); - $dy = $this->scale($this->abs_y, ($yp - ($swapy ? ($height / 2) : ($height / 2) - 1)) * $scale); - $xo = $xoff + $dx[0] + $dy[0]; - $yo = $yoff + $dx[1] + $dy[1]; - - $origin = array(0, 0, 0); - $xvec = $this->scale($this->basis_matrix[$this->x], $scale); - $yvec = $this->scale($this->basis_matrix[$this->y], $scale); - $face_corner = $this->sum2($xvec, $yvec); - - $zvec = $this->scale($this->basis_matrix[$this->z], $scale); - $x_corner = $this->sum2($xvec, $zvec); - $y_corner = $this->sum2($yvec, $zvec); - - imagefilledpolygon($img, $this->gen_poly($xo, $yo, $origin, $xvec, $x_corner,$zvec), 4, $colour1); - imagefilledpolygon($img, $this->gen_poly($xo, $yo, $origin, $yvec, $y_corner,$zvec), 4, $colour2); - - $face = $this->gen_poly($xo, $yo, $origin, $xvec, $face_corner, $yvec); - - imagefilledpolygon($img, $face, 4, $background); - imagepolygon($img, $face, 4, $colour1); - } - } - } - } - - /* - * return a roughly acceptable range of sizes for rendering with this texttype - */ - function range() - { - return array(3, 4); - } - - /** - * Vector length - */ - function vectorlen($vector) - { - return sqrt(pow($vector[0], 2) + pow($vector[1], 2) + pow($vector[2], 2)); - } - - /** - * Normalize - */ - function normalize(&$vector, $length = 1) - { - $length = (( $length < 1) ? 1 : $length); - $length /= $this->vectorlen($vector); - $vector[0] *= $length; - $vector[1] *= $length; - $vector[2] *= $length; - } - - /** - */ - function cross_product($vector1, $vector2) - { - $retval = array(0, 0, 0); - $retval[0] = (($vector1[1] * $vector2[2]) - ($vector1[2] * $vector2[1])); - $retval[1] = -(($vector1[0] * $vector2[2]) - ($vector1[2] * $vector2[0])); - $retval[2] = (($vector1[0] * $vector2[1]) - ($vector1[1] * $vector2[0])); - - return $retval; - } - - /** - */ - function sum($vector1, $vector2) - { - return array($vector1[0] + $vector2[0], $vector1[1] + $vector2[1], $vector1[2] + $vector2[2]); - } - - /** - */ - function sum2($vector1, $vector2) - { - return array($vector1[0] + $vector2[0], $vector1[1] + $vector2[1]); - } - - /** - */ - function scale($vector, $length) - { - if (sizeof($vector) == 2) - { - return array($vector[0] * $length, $vector[1] * $length); - } - - return array($vector[0] * $length, $vector[1] * $length, $vector[2] * $length); - } - - /** - */ - function gen_poly($xoff, $yoff, &$vec1, &$vec2, &$vec3, &$vec4) - { - $poly = array(); - $poly[0] = $xoff + $vec1[0]; - $poly[1] = $yoff + $vec1[1]; - $poly[2] = $xoff + $vec2[0]; - $poly[3] = $yoff + $vec2[1]; - $poly[4] = $xoff + $vec3[0]; - $poly[5] = $yoff + $vec3[1]; - $poly[6] = $xoff + $vec4[0]; - $poly[7] = $yoff + $vec4[1]; - - return $poly; - } - - /** - * dimensions - */ - function dimensions($size) - { - $xn = $this->scale($this->basis_matrix[$this->x], -($this->bitmap_width / 2) * $size); - $xp = $this->scale($this->basis_matrix[$this->x], ($this->bitmap_width / 2) * $size); - $yn = $this->scale($this->basis_matrix[$this->y], -($this->bitmap_height / 2) * $size); - $yp = $this->scale($this->basis_matrix[$this->y], ($this->bitmap_height / 2) * $size); - - $p = array(); - $p[0] = $this->sum2($xn, $yn); - $p[1] = $this->sum2($xp, $yn); - $p[2] = $this->sum2($xp, $yp); - $p[3] = $this->sum2($xn, $yp); - - $min_x = $max_x = $p[0][0]; - $min_y = $max_y = $p[0][1]; - - for ($i = 1; $i < 4; ++$i) - { - $min_x = ($min_x > $p[$i][0]) ? $p[$i][0] : $min_x; - $min_y = ($min_y > $p[$i][1]) ? $p[$i][1] : $min_y; - $max_x = ($max_x < $p[$i][0]) ? $p[$i][0] : $max_x; - $max_y = ($max_y < $p[$i][1]) ? $p[$i][1] : $max_y; - } - - return array($min_x, $min_y, $max_x, $max_y); - } -} - -class colour_manager -{ - var $img; - var $mode; - var $colours; - var $named_colours; - - /** - * Create the colour manager, link it to the image resource - */ - function colour_manager($img, $background = false, $mode = 'ahsv') - { - $this->img = $img; - $this->mode = $mode; - $this->colours = array(); - $this->named_colours = array(); - - if ($background !== false) - { - $bg = $this->allocate_named('background', $background); - imagefill($this->img, 0, 0, $bg); - } - } - - /** - * Lookup a named colour resource - */ - function get_resource($named_colour) - { - if (isset($this->named_colours[$named_colour])) - { - return $this->named_colours[$named_colour]; - } - - if (isset($this->named_rgb[$named_colour])) - { - return $this->allocate_named($named_colour, $this->named_rgb[$named_colour], 'rgb'); - } - - return false; - } - - /** - * Assign a name to a colour resource - */ - function name_colour($name, $resource) - { - $this->named_colours[$name] = $resource; - } - - /** - * names and allocates a colour resource - */ - function allocate_named($name, $colour, $mode = false) - { - $resource = $this->allocate($colour, $mode); - - if ($resource !== false) - { - $this->name_colour($name, $resource); - } - return $resource; - } - - /** - * allocates a specified colour into the image - */ - function allocate($colour, $mode = false) - { - if ($mode === false) - { - $mode = $this->mode; - } - - if (!is_array($colour)) - { - if (isset($this->named_rgb[$colour])) - { - return $this->allocate_named($colour, $this->named_rgb[$colour], 'rgb'); - } - - if (!is_int($colour)) - { - return false; - } - - $mode = 'rgb'; - $colour = array(255 & ($colour >> 16), 255 & ($colour >> 8), 255 & $colour); - } - - if (isset($colour['mode'])) - { - $mode = $colour['mode']; - unset($colour['mode']); - } - - if (isset($colour['random'])) - { - unset($colour['random']); - // everything else is params - return $this->random_colour($colour, $mode); - } - - $rgb = $this->model_convert($colour, $mode, 'rgb'); - $store = ($this->mode == 'rgb') ? $rgb : $this->model_convert($colour, $mode, $this->mode); - $resource = imagecolorallocate($this->img, $rgb[0], $rgb[1], $rgb[2]); - $this->colours[$resource] = $store; - - return $resource; - } - - /** - * randomly generates a colour, with optional params - */ - function random_colour($params = array(), $mode = false) - { - if ($mode === false) - { - $mode = $this->mode; - } - - switch ($mode) - { - case 'rgb': - // @TODO random rgb generation. do we intend to do this, or is it just too tedious? - break; - - case 'ahsv': - case 'hsv': - default: - - $default_params = array( - 'hue_bias' => false, // degree / 'r'/'g'/'b'/'c'/'m'/'y' /'o' - 'hue_range' => false, // if hue bias, then difference range +/- from bias - 'min_saturation' => 30, // 0 - 100 - 'max_saturation' => 80, // 0 - 100 - 'min_value' => 30, // 0 - 100 - 'max_value' => 80, // 0 - 100 - ); - - $alt = ($mode == 'ahsv') ? true : false; - $params = array_merge($default_params, $params); - - $min_hue = 0; - $max_hue = 359; - $min_saturation = max(0, $params['min_saturation']); - $max_saturation = min(100, $params['max_saturation']); - $min_value = max(0, $params['min_value']); - $max_value = min(100, $params['max_value']); - - if ($params['hue_bias'] !== false) - { - if (is_numeric($params['hue_bias'])) - { - $h = intval($params['hue_bias']) % 360; - } - else - { - switch ($params['hue_bias']) - { - case 'o': - $h = $alt ? 60 : 30; - break; - - case 'y': - $h = $alt ? 120 : 60; - break; - - case 'g': - $h = $alt ? 180 : 120; - break; - - case 'c': - $h = $alt ? 210 : 180; - break; - - case 'b': - $h = 240; - break; - - case 'm': - $h = 300; - break; - - case 'r': - default: - $h = 0; - break; - } - } - - $min_hue = $h + 360; - $max_hue = $h + 360; - - if ($params['hue_range']) - { - $min_hue -= min(180, $params['hue_range']); - $max_hue += min(180, $params['hue_range']); - } - } - - $h = mt_rand($min_hue, $max_hue); - $s = mt_rand($min_saturation, $max_saturation); - $v = mt_rand($min_value, $max_value); - - return $this->allocate(array($h, $s, $v), $mode); - - break; - } - } - - /** - */ - function colour_scheme($resource, $include_original = true) - { - $mode = 'hsv'; - - if (($pre = $this->get_resource($resource)) !== false) - { - $resource = $pre; - } - - $colour = $this->model_convert($this->colours[$resource], $this->mode, $mode); - $results = ($include_original) ? array($resource) : array(); - $colour2 = $colour3 = $colour4 = $colour; - $colour2[0] += 150; - $colour3[0] += 180; - $colour4[0] += 210; - - $results[] = $this->allocate($colour2, $mode); - $results[] = $this->allocate($colour3, $mode); - $results[] = $this->allocate($colour4, $mode); - - return $results; - } - - /** - */ - function mono_range($resource, $count = 5, $include_original = true) - { - if (is_array($resource)) - { - $results = array(); - for ($i = 0, $size = sizeof($resource); $i < $size; ++$i) - { - $results = array_merge($results, $this->mono_range($resource[$i], $count, $include_original)); - } - return $results; - } - - $mode = (in_array($this->mode, array('hsv', 'ahsv'), true) ? $this->mode : 'ahsv'); - if (($pre = $this->get_resource($resource)) !== false) - { - $resource = $pre; - } - - $colour = $this->model_convert($this->colours[$resource], $this->mode, $mode); - - $results = array(); - if ($include_original) - { - $results[] = $resource; - $count--; - } - - // This is a hard problem. I chicken out and try to maintain readability at the cost of less randomness. - - while ($count > 0) - { - $colour[1] = ($colour[1] + mt_rand(40,60)) % 99; - $colour[2] = ($colour[2] + mt_rand(40,60)); - $results[] = $this->allocate($colour, $mode); - $count--; - } - return $results; - } - - /** - * Convert from one colour model to another - */ - function model_convert($colour, $from_model, $to_model) - { - if ($from_model == $to_model) - { - return $colour; - } - - switch ($to_model) - { - case 'hsv': - - switch ($from_model) - { - case 'ahsv': - return $this->ah2h($colour); - break; - - case 'rgb': - return $this->rgb2hsv($colour); - break; - } - break; - - case 'ahsv': - - switch ($from_model) - { - case 'hsv': - return $this->h2ah($colour); - break; - - case 'rgb': - return $this->h2ah($this->rgb2hsv($colour)); - break; - } - break; - - case 'rgb': - switch ($from_model) - { - case 'hsv': - return $this->hsv2rgb($colour); - break; - - case 'ahsv': - return $this->hsv2rgb($this->ah2h($colour)); - break; - } - break; - } - return false; - } - - /** - * Slightly altered from wikipedia's algorithm - */ - function hsv2rgb($hsv) - { - $this->normalize_hue($hsv[0]); - - $h = $hsv[0]; - $s = min(1, max(0, $hsv[1] / 100)); - $v = min(1, max(0, $hsv[2] / 100)); - - // calculate hue sector - $hi = floor($hsv[0] / 60); - - // calculate opposite colour - $p = $v * (1 - $s); - - // calculate distance between hex vertices - $f = ($h / 60) - $hi; - - // coming in or going out? - if (!($hi & 1)) - { - $f = 1 - $f; - } - - // calculate adjacent colour - $q = $v * (1 - ($f * $s)); - - switch ($hi) - { - case 0: - $rgb = array($v, $q, $p); - break; - - case 1: - $rgb = array($q, $v, $p); - break; - - case 2: - $rgb = array($p, $v, $q); - break; - - case 3: - $rgb = array($p, $q, $v); - break; - - case 4: - $rgb = array($q, $p, $v); - break; - - case 5: - $rgb = array($v, $p, $q); - break; - - default: - return array(0, 0, 0); - break; - } - - return array(255 * $rgb[0], 255 * $rgb[1], 255 * $rgb[2]); - } - - /** - * (more than) Slightly altered from wikipedia's algorithm - */ - function rgb2hsv($rgb) - { - $r = min(255, max(0, $rgb[0])); - $g = min(255, max(0, $rgb[1])); - $b = min(255, max(0, $rgb[2])); - $max = max($r, $g, $b); - $min = min($r, $g, $b); - - $v = $max / 255; - $s = (!$max) ? 0 : 1 - ($min / $max); - - // if max - min is 0, we want hue to be 0 anyway. - $h = $max - $min; - - if ($h) - { - switch ($max) - { - case $g: - $h = 120 + (60 * ($b - $r) / $h); - break; - - case $b: - $h = 240 + (60 * ($r - $g) / $h); - break; - - case $r: - $h = 360 + (60 * ($g - $b) / $h); - break; - } - } - $this->normalize_hue($h); - - return array($h, $s * 100, $v * 100); - } - - /** - */ - function normalize_hue(&$hue) - { - $hue %= 360; - - if ($hue < 0) - { - $hue += 360; - } - } - - /** - * Alternate hue to hue - */ - function ah2h($ahue) - { - if (is_array($ahue)) - { - $ahue[0] = $this->ah2h($ahue[0]); - return $ahue; - } - $this->normalize_hue($ahue); - - // blue through red is already ok - if ($ahue >= 240) - { - return $ahue; - } - - // ahue green is at 180 - if ($ahue >= 180) - { - // return (240 - (2 * (240 - $ahue))); - return (2 * $ahue) - 240; // equivalent - } - - // ahue yellow is at 120 (RYB rather than RGB) - if ($ahue >= 120) - { - return $ahue - 60; - } - - return $ahue / 2; - } - - /** - * hue to Alternate hue - */ - function h2ah($hue) - { - if (is_array($hue)) - { - $hue[0] = $this->h2ah($hue[0]); - return $hue; - } - $this->normalize_hue($hue); - - // blue through red is already ok - if ($hue >= 240) - { - return $hue; - } - else if ($hue <= 60) - { - return $hue * 2; - } - else if ($hue <= 120) - { - return $hue + 60; - } - else - { - return ($hue + 240) / 2; - } - } -} diff --git a/phpBB/includes/captcha/captcha_gd_wave.php b/phpBB/phpbb/captcha/gd_wave.php index c2a4d3a31e..d48fc753a5 100644 --- a/phpBB/includes/captcha/captcha_gd_wave.php +++ b/phpBB/phpbb/captcha/gd_wave.php @@ -11,10 +11,12 @@ * */ +namespace phpbb\captcha; + /** * Wave3D CAPTCHA */ -class captcha +class gd_wave { var $width = 360; var $height = 96; diff --git a/phpBB/includes/captcha/captcha_non_gd.php b/phpBB/phpbb/captcha/non_gd.php index 91970ea7a4..3818672f17 100644 --- a/phpBB/includes/captcha/captcha_non_gd.php +++ b/phpBB/phpbb/captcha/non_gd.php @@ -11,19 +11,13 @@ * */ -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} +namespace phpbb\captcha; /** * Main non-gd captcha class * @ignore */ -class captcha +class non_gd { var $filtered_pngs; var $width = 320; @@ -32,7 +26,7 @@ class captcha /** * Define filtered pngs on init */ - function captcha() + function __construct() { // If we can we will generate a single filtered png, we avoid nastiness via emulation of some Zlib stuff $this->define_filtered_pngs(); diff --git a/phpBB/includes/captcha/plugins/captcha_abstract.php b/phpBB/phpbb/captcha/plugins/captcha_abstract.php index 8e1e61bdb7..24ed7f939d 100644 --- a/phpBB/includes/captcha/plugins/captcha_abstract.php +++ b/phpBB/phpbb/captcha/plugins/captcha_abstract.php @@ -11,18 +11,12 @@ * */ -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} +namespace phpbb\captcha\plugins; /** * This class holds the code shared by the two default 3.0.x CAPTCHAs. */ -class phpbb_captcha_plugins_captcha_abstract +abstract class captcha_abstract { var $confirm_id; var $confirm_code; @@ -33,6 +27,11 @@ class phpbb_captcha_plugins_captcha_abstract var $solved = 0; var $captcha_vars = false; + /** + * @var string name of the service. + */ + protected $service_name; + function init($type) { global $config, $db, $user; @@ -65,7 +64,8 @@ class phpbb_captcha_plugins_captcha_abstract // compute $seed % 0x7fffffff $this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff); - $captcha = new captcha(); + $generator = $this->get_generator_class(); + $captcha = new $generator(); define('IMAGE_OUTPUT', 1); $captcha->execute($this->code, $this->seed); } @@ -80,7 +80,8 @@ class phpbb_captcha_plugins_captcha_abstract return false; } } - $captcha = new captcha(); + $generator = $this->get_generator_class(); + $captcha = new $generator(); define('IMAGE_OUTPUT', 1); $captcha->execute($this->code, $this->seed); } @@ -130,7 +131,7 @@ class phpbb_captcha_plugins_captcha_abstract // acp_captcha has a delivery function; let's use it $template->assign_vars(array( - 'CONFIRM_IMAGE' => append_sid($phpbb_admin_path . 'index.' . $phpEx, 'captcha_demo=1&mode=visual&i=' . $id . '&select_captcha=' . $this->get_class_name()) . $variables, + 'CONFIRM_IMAGE' => append_sid($phpbb_admin_path . 'index.' . $phpEx, 'captcha_demo=1&mode=visual&i=' . $id . '&select_captcha=' . $this->get_service_name()) . $variables, 'CONFIRM_ID' => $this->confirm_id, )); @@ -364,11 +365,26 @@ class phpbb_captcha_plugins_captcha_abstract return false; } -} + /** + * @return string the name of the service corresponding to the plugin + */ + function get_service_name() + { + return $this->service_name; + } -/** -* Old class name for legacy use. The new class name is auto loadable. -*/ -class phpbb_default_captcha extends phpbb_captcha_plugins_captcha_abstract -{ + /** + * Set the name of the plugin + * + * @param string $name + */ + public function set_name($name) + { + $this->service_name = $name; + } + + /** + * @return string the name of the class used to generate the captcha + */ + abstract function get_generator_class(); } diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_gd_plugin.php b/phpBB/phpbb/captcha/plugins/gd.php index 8dbd458ede..f6200b5b2f 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_gd_plugin.php +++ b/phpBB/phpbb/captcha/plugins/gd.php @@ -11,25 +11,10 @@ * */ -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Placeholder for autoload -*/ -if (!class_exists('phpbb_default_captcha', false)) -{ - include($phpbb_root_path . 'includes/captcha/plugins/captcha_abstract.' . $phpEx); -} +namespace phpbb\captcha\plugins; -class phpbb_captcha_gd extends phpbb_default_captcha +class gd extends captcha_abstract { - var $captcha_vars = array( 'captcha_gd_x_grid' => 'CAPTCHA_GD_X_GRID', 'captcha_gd_y_grid' => 'CAPTCHA_GD_Y_GRID', @@ -40,25 +25,17 @@ class phpbb_captcha_gd extends phpbb_default_captcha 'captcha_gd_fonts' => 'CAPTCHA_GD_FONTS', ); - function phpbb_captcha_gd() + public function is_available() { - global $phpbb_root_path, $phpEx; - - if (!class_exists('captcha')) - { - include($phpbb_root_path . 'includes/captcha/captcha_gd.' . $phpEx); - } - } - - static public function get_instance() - { - $instance = new phpbb_captcha_gd(); - return $instance; + return @extension_loaded('gd'); } - static public function is_available() + /** + * @return string the name of the class used to generate the captcha + */ + function get_generator_class() { - return @extension_loaded('gd'); + return '\\phpbb\\captcha\\gd'; } /** @@ -69,16 +46,11 @@ class phpbb_captcha_gd extends phpbb_default_captcha return true; } - static public function get_name() + public function get_name() { return 'CAPTCHA_GD'; } - function get_class_name() - { - return 'phpbb_captcha_gd'; - } - function acp_page($id, &$module) { global $db, $user, $auth, $template; @@ -129,7 +101,7 @@ class phpbb_captcha_gd extends phpbb_default_captcha $template->assign_vars(array( 'CAPTCHA_PREVIEW' => $this->get_demo_template($id), - 'CAPTCHA_NAME' => $this->get_class_name(), + 'CAPTCHA_NAME' => $this->get_service_name(), 'U_ACTION' => $module->u_action, )); } diff --git a/phpBB/phpbb/captcha/plugins/gd_wave.php b/phpBB/phpbb/captcha/plugins/gd_wave.php new file mode 100644 index 0000000000..e1d44df778 --- /dev/null +++ b/phpBB/phpbb/captcha/plugins/gd_wave.php @@ -0,0 +1,42 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\captcha\plugins; + +class gd_wave extends captcha_abstract +{ + public function is_available() + { + return @extension_loaded('gd'); + } + + public function get_name() + { + return 'CAPTCHA_GD_3D'; + } + + /** + * @return string the name of the class used to generate the captcha + */ + function get_generator_class() + { + return '\\phpbb\\captcha\\gd_wave'; + } + + function acp_page($id, &$module) + { + global $config, $db, $template, $user; + + trigger_error($user->lang['CAPTCHA_NO_OPTIONS'] . adm_back_link($module->u_action)); + } +} diff --git a/phpBB/phpbb/captcha/plugins/nogd.php b/phpBB/phpbb/captcha/plugins/nogd.php new file mode 100644 index 0000000000..6845e5935c --- /dev/null +++ b/phpBB/phpbb/captcha/plugins/nogd.php @@ -0,0 +1,42 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\captcha\plugins; + +class nogd extends captcha_abstract +{ + public function is_available() + { + return true; + } + + public function get_name() + { + return 'CAPTCHA_NO_GD'; + } + + /** + * @return string the name of the class used to generate the captcha + */ + function get_generator_class() + { + return '\\phpbb\\captcha\\non_gd'; + } + + function acp_page($id, &$module) + { + global $user; + + trigger_error($user->lang['CAPTCHA_NO_OPTIONS'] . adm_back_link($module->u_action)); + } +} diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/phpbb/captcha/plugins/qa.php index 5a44755365..a7ba994cc3 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ b/phpBB/phpbb/captcha/plugins/qa.php @@ -11,25 +11,13 @@ * */ -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -global $table_prefix; - -define('CAPTCHA_QUESTIONS_TABLE', $table_prefix . 'captcha_questions'); -define('CAPTCHA_ANSWERS_TABLE', $table_prefix . 'captcha_answers'); -define('CAPTCHA_QA_CONFIRM_TABLE', $table_prefix . 'qa_confirm'); +namespace phpbb\captcha\plugins; /** * And now to something completely different. Let's make a captcha without extending the abstract class. * QA CAPTCHA sample implementation */ -class phpbb_captcha_qa +class qa { var $confirm_id; var $answer; @@ -42,6 +30,29 @@ class phpbb_captcha_qa // dirty trick: 0 is false, but can still encode that the captcha is not yet validated var $solved = 0; + protected $table_captcha_questions; + protected $table_captcha_answers; + protected $table_qa_confirm; + + /** + * @var string name of the service. + */ + protected $service_name; + + /** + * Constructor + * + * @param string $table_captcha_questions + * @param string $table_captcha_answers + * @param string $table_qa_confirm + */ + function __construct($table_captcha_questions, $table_captcha_answers, $table_qa_confirm) + { + $this->table_captcha_questions = $table_captcha_questions; + $this->table_captcha_answers = $table_captcha_answers; + $this->table_qa_confirm = $table_qa_confirm; + } + /** * @param int $type as per the CAPTCHA API docs, the type */ @@ -62,7 +73,7 @@ class phpbb_captcha_qa // we need all defined questions - shouldn't be too many, so we can just grab them // try the user's lang first $sql = 'SELECT question_id - FROM ' . CAPTCHA_QUESTIONS_TABLE . " + FROM ' . $this->table_captcha_questions . " WHERE lang_iso = '" . $db->sql_escape($user->lang_name) . "'"; $result = $db->sql_query($sql, 3600); @@ -78,7 +89,7 @@ class phpbb_captcha_qa $this->question_lang = $config['default_lang']; $sql = 'SELECT question_id - FROM ' . CAPTCHA_QUESTIONS_TABLE . " + FROM ' . $this->table_captcha_questions . " WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; $result = $db->sql_query($sql, 7200); @@ -98,44 +109,34 @@ class phpbb_captcha_qa } /** - * API function - */ - static public function get_instance() - { - $instance = new phpbb_captcha_qa(); - - return $instance; - } - - /** * See if the captcha has created its tables. */ - static public function is_installed() + public function is_installed() { global $db; $db_tool = new \phpbb\db\tools($db); - return $db_tool->sql_table_exists(CAPTCHA_QUESTIONS_TABLE); + return $db_tool->sql_table_exists($this->table_captcha_questions); } /** * API function - for the captcha to be available, it must have installed itself and there has to be at least one question in the board's default lang */ - static public function is_available() + public function is_available() { global $config, $db, $phpbb_root_path, $phpEx, $user; // load language file for pretty display in the ACP dropdown $user->add_lang('captcha_qa'); - if (!self::is_installed()) + if (!$this->is_installed()) { return false; } $sql = 'SELECT COUNT(question_id) AS question_count - FROM ' . CAPTCHA_QUESTIONS_TABLE . " + FROM ' . $this->table_captcha_questions . " WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); @@ -161,11 +162,21 @@ class phpbb_captcha_qa } /** - * API function + * @return string the name of the service corresponding to the plugin + */ + function get_service_name() + { + return $this->service_name; + } + + /** + * Set the name of the plugin + * + * @param string $name */ - function get_class_name() + public function set_name($name) { - return 'phpbb_captcha_qa'; + $this->service_name = $name; } /** @@ -216,7 +227,7 @@ class phpbb_captcha_qa if ($this->is_available()) { $sql = 'SELECT question_text - FROM ' . CAPTCHA_QUESTIONS_TABLE . " + FROM ' . $this->table_captcha_questions . " WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; $result = $db->sql_query_limit($sql, 1); if ($row = $db->sql_fetchrow($result)) @@ -255,7 +266,7 @@ class phpbb_captcha_qa global $db, $config; $sql = 'SELECT c.confirm_id - FROM ' . CAPTCHA_QA_CONFIRM_TABLE . ' c + FROM ' . $this->table_qa_confirm . ' c LEFT JOIN ' . SESSIONS_TABLE . ' s ON (c.session_id = s.session_id) WHERE s.session_id IS NULL' . @@ -274,7 +285,7 @@ class phpbb_captcha_qa if (sizeof($sql_in)) { - $sql = 'DELETE FROM ' . CAPTCHA_QA_CONFIRM_TABLE . ' + $sql = 'DELETE FROM ' . $this->table_qa_confirm . ' WHERE ' . $db->sql_in_set('confirm_id', $sql_in); $db->sql_query($sql); } @@ -299,12 +310,12 @@ class phpbb_captcha_qa $db_tool = new \phpbb\db\tools($db); - $tables = array(CAPTCHA_QUESTIONS_TABLE, CAPTCHA_ANSWERS_TABLE, CAPTCHA_QA_CONFIRM_TABLE); + $tables = array($this->table_captcha_questions, $this->table_captcha_answers, $this->table_qa_confirm); $schemas = array( - CAPTCHA_QUESTIONS_TABLE => array ( + $this->table_captcha_questions => array ( 'COLUMNS' => array( - 'question_id' => array('UINT', Null, 'auto_increment'), + 'question_id' => array('UINT', null, 'auto_increment'), 'strict' => array('BOOL', 0), 'lang_id' => array('UINT', 0), 'lang_iso' => array('VCHAR:30', ''), @@ -315,7 +326,7 @@ class phpbb_captcha_qa 'lang' => array('INDEX', 'lang_iso'), ), ), - CAPTCHA_ANSWERS_TABLE => array ( + $this->table_captcha_answers => array ( 'COLUMNS' => array( 'question_id' => array('UINT', 0), 'answer_text' => array('STEXT_UNI', ''), @@ -324,7 +335,7 @@ class phpbb_captcha_qa 'qid' => array('INDEX', 'question_id'), ), ), - CAPTCHA_QA_CONFIRM_TABLE => array ( + $this->table_qa_confirm => array ( 'COLUMNS' => array( 'session_id' => array('CHAR:32', ''), 'confirm_id' => array('CHAR:32', ''), @@ -408,7 +419,7 @@ class phpbb_captcha_qa $this->confirm_id = md5(unique_id($user->ip)); $this->question = (int) array_rand($this->question_ids); - $sql = 'INSERT INTO ' . CAPTCHA_QA_CONFIRM_TABLE . ' ' . $db->sql_build_array('INSERT', array( + $sql = 'INSERT INTO ' . $this->table_qa_confirm . ' ' . $db->sql_build_array('INSERT', array( 'confirm_id' => (string) $this->confirm_id, 'session_id' => (string) $user->session_id, 'lang_iso' => (string) $this->question_lang, @@ -435,7 +446,7 @@ class phpbb_captcha_qa $this->question = (int) array_rand($this->question_ids); $this->solved = 0; - $sql = 'UPDATE ' . CAPTCHA_QA_CONFIRM_TABLE . ' + $sql = 'UPDATE ' . $this->table_qa_confirm . ' SET question_id = ' . (int) $this->question . " WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' AND session_id = '" . $db->sql_escape($user->session_id) . "'"; @@ -455,7 +466,7 @@ class phpbb_captcha_qa $this->question = (int) array_rand($this->question_ids); $this->solved = 0; - $sql = 'UPDATE ' . CAPTCHA_QA_CONFIRM_TABLE . ' + $sql = 'UPDATE ' . $this->table_qa_confirm . ' SET question_id = ' . (int) $this->question . ", attempts = attempts + 1 WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' @@ -474,7 +485,7 @@ class phpbb_captcha_qa global $db, $user; $sql = 'SELECT confirm_id - FROM ' . CAPTCHA_QA_CONFIRM_TABLE . " + FROM ' . $this->table_qa_confirm . " WHERE session_id = '" . $db->sql_escape($user->session_id) . "' AND lang_iso = '" . $db->sql_escape($this->question_lang) . "' @@ -504,7 +515,7 @@ class phpbb_captcha_qa } $sql = 'SELECT con.question_id, attempts, question_text, strict - FROM ' . CAPTCHA_QA_CONFIRM_TABLE . ' con, ' . CAPTCHA_QUESTIONS_TABLE . " qes + FROM ' . $this->table_qa_confirm . ' con, ' . $this->table_captcha_questions . " qes WHERE con.question_id = qes.question_id AND confirm_id = '" . $db->sql_escape($this->confirm_id) . "' AND session_id = '" . $db->sql_escape($user->session_id) . "' @@ -538,7 +549,7 @@ class phpbb_captcha_qa $answer = ($this->question_strict) ? utf8_normalize_nfc(request_var('qa_answer', '', true)) : utf8_clean_string(utf8_normalize_nfc(request_var('qa_answer', '', true))); $sql = 'SELECT answer_text - FROM ' . CAPTCHA_ANSWERS_TABLE . ' + FROM ' . $this->table_captcha_answers . ' WHERE question_id = ' . (int) $this->question; $result = $db->sql_query($sql); @@ -573,7 +584,7 @@ class phpbb_captcha_qa { global $db, $user; - $sql = 'DELETE FROM ' . CAPTCHA_QA_CONFIRM_TABLE . " + $sql = 'DELETE FROM ' . $this->table_qa_confirm . " WHERE session_id = '" . $db->sql_escape($user->session_id) . "' AND confirm_type = " . (int) $this->type; $db->sql_query($sql); @@ -621,12 +632,12 @@ class phpbb_captcha_qa $action = request_var('action', ''); // we have two pages, so users might want to navigate from one to the other - $list_url = $module->u_action . "&configure=1&select_captcha=" . $this->get_class_name(); + $list_url = $module->u_action . "&configure=1&select_captcha=" . $this->get_service_name(); $template->assign_vars(array( 'U_ACTION' => $module->u_action, 'QUESTION_ID' => $question_id , - 'CLASS' => $this->get_class_name(), + 'CLASS' => $this->get_service_name(), )); // show the list? @@ -636,7 +647,7 @@ class phpbb_captcha_qa } else if ($question_id && $action == 'delete') { - if ($this->get_class_name() !== $config['captcha_plugin'] || !$this->acp_is_last($question_id)) + if ($this->get_service_name() !== $config['captcha_plugin'] || !$this->acp_is_last($question_id)) { if (confirm_box(true)) { @@ -650,7 +661,7 @@ class phpbb_captcha_qa 'question_id' => $question_id, 'action' => $action, 'configure' => 1, - 'select_captcha' => $this->get_class_name(), + 'select_captcha' => $this->get_service_name(), )) ); } @@ -750,7 +761,7 @@ class phpbb_captcha_qa global $db, $template; $sql = 'SELECT * - FROM ' . CAPTCHA_QUESTIONS_TABLE; + FROM ' . $this->table_captcha_questions; $result = $db->sql_query($sql); $template->assign_vars(array( @@ -759,7 +770,7 @@ class phpbb_captcha_qa while ($row = $db->sql_fetchrow($result)) { - $url = $module->u_action . "&question_id={$row['question_id']}&configure=1&select_captcha=" . $this->get_class_name() . '&'; + $url = $module->u_action . "&question_id={$row['question_id']}&configure=1&select_captcha=" . $this->get_service_name() . '&'; $template->assign_block_vars('questions', array( 'QUESTION_TEXT' => $row['question_text'], @@ -782,7 +793,7 @@ class phpbb_captcha_qa if ($question_id) { $sql = 'SELECT * - FROM ' . CAPTCHA_QUESTIONS_TABLE . ' + FROM ' . $this->table_captcha_questions . ' WHERE question_id = ' . $question_id; $result = $db->sql_query($sql); $question = $db->sql_fetchrow($result); @@ -796,7 +807,7 @@ class phpbb_captcha_qa $question['answers'] = array(); $sql = 'SELECT * - FROM ' . CAPTCHA_ANSWERS_TABLE . ' + FROM ' . $this->table_captcha_answers . ' WHERE question_id = ' . $question_id; $result = $db->sql_query($sql); @@ -835,7 +846,7 @@ class phpbb_captcha_qa global $db, $cache; // easier to delete all answers than to figure out which to update - $sql = 'DELETE FROM ' . CAPTCHA_ANSWERS_TABLE . " WHERE question_id = $question_id"; + $sql = 'DELETE FROM ' . $this->table_captcha_answers . " WHERE question_id = $question_id"; $db->sql_query($sql); $langs = $this->get_languages(); @@ -843,14 +854,14 @@ class phpbb_captcha_qa $question_ary['lang_id'] = $langs[$question_ary['lang_iso']]['id']; unset($question_ary['answers']); - $sql = 'UPDATE ' . CAPTCHA_QUESTIONS_TABLE . ' + $sql = 'UPDATE ' . $this->table_captcha_questions . ' SET ' . $db->sql_build_array('UPDATE', $question_ary) . " WHERE question_id = $question_id"; $db->sql_query($sql); $this->acp_insert_answers($data, $question_id); - $cache->destroy('sql', CAPTCHA_QUESTIONS_TABLE); + $cache->destroy('sql', $this->table_captcha_questions); } /** @@ -867,14 +878,14 @@ class phpbb_captcha_qa $question_ary['lang_id'] = $langs[$data['lang_iso']]['id']; unset($question_ary['answers']); - $sql = 'INSERT INTO ' . CAPTCHA_QUESTIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $question_ary); + $sql = 'INSERT INTO ' . $this->table_captcha_questions . ' ' . $db->sql_build_array('INSERT', $question_ary); $db->sql_query($sql); $question_id = $db->sql_nextid(); $this->acp_insert_answers($data, $question_id); - $cache->destroy('sql', CAPTCHA_QUESTIONS_TABLE); + $cache->destroy('sql', $this->table_captcha_questions); } /** @@ -892,11 +903,11 @@ class phpbb_captcha_qa 'answer_text' => $answer, ); - $sql = 'INSERT INTO ' . CAPTCHA_ANSWERS_TABLE . ' ' . $db->sql_build_array('INSERT', $answer_ary); + $sql = 'INSERT INTO ' . $this->table_captcha_answers . ' ' . $db->sql_build_array('INSERT', $answer_ary); $db->sql_query($sql); } - $cache->destroy('sql', CAPTCHA_ANSWERS_TABLE); + $cache->destroy('sql', $this->table_captcha_answers); } /** @@ -906,7 +917,7 @@ class phpbb_captcha_qa { global $db, $cache; - $tables = array(CAPTCHA_QUESTIONS_TABLE, CAPTCHA_ANSWERS_TABLE); + $tables = array($this->table_captcha_questions, $this->table_captcha_answers); foreach ($tables as $table) { @@ -981,7 +992,7 @@ class phpbb_captcha_qa if ($question_id) { $sql = 'SELECT question_id - FROM ' . CAPTCHA_QUESTIONS_TABLE . " + FROM ' . $this->table_captcha_questions . " WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "' AND question_id <> " . (int) $question_id; $result = $db->sql_query_limit($sql, 1); diff --git a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php b/phpBB/phpbb/captcha/plugins/recaptcha.php index 12cc49ef9b..ea446d7bc3 100644 --- a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php +++ b/phpBB/phpbb/captcha/plugins/recaptcha.php @@ -11,21 +11,9 @@ * */ -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -if (!class_exists('phpbb_default_captcha', false)) -{ - // we need the classic captcha code for tracking solutions and attempts - include($phpbb_root_path . 'includes/captcha/plugins/captcha_abstract.' . $phpEx); -} +namespace phpbb\captcha\plugins; -class phpbb_recaptcha extends phpbb_default_captcha +class recaptcha extends captcha_abstract { var $recaptcha_server = 'http://www.google.com/recaptcha/api'; var $recaptcha_server_secure = 'https://www.google.com/recaptcha/api'; // class constants :( @@ -55,13 +43,7 @@ class phpbb_recaptcha extends phpbb_default_captcha $this->response = request_var('recaptcha_response_field', ''); } - static public function get_instance() - { - $instance = new phpbb_recaptcha(); - return $instance; - } - - static public function is_available() + public function is_available() { global $config, $user; $user->add_lang('captcha_recaptcha'); @@ -81,9 +63,12 @@ class phpbb_recaptcha extends phpbb_default_captcha return 'CAPTCHA_RECAPTCHA'; } - function get_class_name() + /** + * This function is implemented because required by the upper class, but is never used for reCaptcha. + */ + function get_generator_class() { - return 'phpbb_recaptcha'; + throw new \Exception('No generator class given.'); } function acp_page($id, &$module) @@ -131,7 +116,7 @@ class phpbb_recaptcha extends phpbb_default_captcha $template->assign_vars(array( 'CAPTCHA_PREVIEW' => $this->get_demo_template($id), - 'CAPTCHA_NAME' => $this->get_class_name(), + 'CAPTCHA_NAME' => $this->get_service_name(), 'U_ACTION' => $module->u_action, )); diff --git a/phpBB/phpbb/config_php_file.php b/phpBB/phpbb/config_php_file.php index 1a562e470d..7445e7df22 100644 --- a/phpBB/phpbb/config_php_file.php +++ b/phpBB/phpbb/config_php_file.php @@ -71,59 +71,44 @@ class config_php_file /** * Returns an associative array containing the variables defined by the config file. * - * @return bool|array Return the content of the config file or false if the file does not exists. + * @return array Return the content of the config file or an empty array if the file does not exists. */ public function get_all() { - if (!$this->load_config_file()) - { - return false; - } + $this->load_config_file(); return $this->config_data; } /** - * Return the value of a variable defined into the config.php file and false if the variable does not exist. + * Return the value of a variable defined into the config.php file or null if the variable does not exist. * * @param string $variable The name of the variable - * @return mixed + * @return mixed Value of the variable or null if the variable is not defined. */ public function get($variable) { - if (!$this->load_config_file()) - { - return false; - } + $this->load_config_file(); - return isset($this->config_data[$variable]) ? $this->config_data[$variable] : false; + return isset($this->config_data[$variable]) ? $this->config_data[$variable] : null; } /** * Load the config file and store the information. * - * @return bool True if the file was correctly loaded, false otherwise. + * @return null */ protected function load_config_file() { - if (!$this->config_loaded) + if (!$this->config_loaded && file_exists($this->config_file)) { - if (file_exists($this->config_file)) - { - $this->defined_vars = get_defined_vars(); + $this->defined_vars = get_defined_vars(); - require($this->config_file); - $this->config_data = array_diff_key(get_defined_vars(), $this->defined_vars); + require($this->config_file); + $this->config_data = array_diff_key(get_defined_vars(), $this->defined_vars); - $this->config_loaded = true; - } - else - { - return false; - } + $this->config_loaded = true; } - - return true; } /** diff --git a/phpBB/phpbb/content_visibility.php b/phpBB/phpbb/content_visibility.php index da4405d676..8bd537586e 100644 --- a/phpBB/phpbb/content_visibility.php +++ b/phpBB/phpbb/content_visibility.php @@ -570,7 +570,7 @@ class content_visibility * Add post to topic and forum statistics * * @param $data array Contains information from the topics table about given topic - * @param $sql_data array Populated with the SQL changes, may be empty at call time + * @param &$sql_data array Populated with the SQL changes, may be empty at call time * @return null */ public function add_post_to_statistic($data, &$sql_data) @@ -591,7 +591,7 @@ class content_visibility * Remove post from topic and forum statistics * * @param $data array Contains information from the topics table about given topic - * @param $sql_data array Populated with the SQL changes, may be empty at call time + * @param &$sql_data array Populated with the SQL changes, may be empty at call time * @return null */ public function remove_post_from_statistic($data, &$sql_data) @@ -623,64 +623,29 @@ class content_visibility /** * Remove topic from forum statistics * - * @param $topic_id int The topic to act on - * @param $forum_id int Forum where the topic is found - * @param $topic_row array Contains information from the topic, may be empty at call time - * @param $sql_data array Populated with the SQL changes, may be empty at call time + * @param $data array Post and topic data + * @param &$sql_data array Populated with the SQL changes, may be empty at call time * @return null */ - public function remove_topic_from_statistic($topic_id, $forum_id, &$topic_row, &$sql_data) + public function remove_topic_from_statistic($data, &$sql_data) { - // Do we need to grab some topic informations? - if (!sizeof($topic_row)) + if ($data['topic_visibility'] == ITEM_APPROVED) { - $sql = 'SELECT topic_type, topic_posts_approved, topic_posts_unapproved, topic_posts_softdeleted, topic_visibility - FROM ' . $this->topics_table . ' - WHERE topic_id = ' . (int) $topic_id; - $result = $this->db->sql_query($sql); - $topic_row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - } - - // If this is an edited topic or the first post the topic gets completely disapproved later on... - $sql_data[$this->forums_table] = (($sql_data[$this->forums_table]) ? $sql_data[$this->forums_table] . ', ' : '') . 'forum_topics_approved = forum_topics_approved - 1'; - $sql_data[$this->forums_table] .= ', forum_posts_approved = forum_posts_approved - ' . $topic_row['topic_posts_approved']; - $sql_data[$this->forums_table] .= ', forum_posts_unapproved = forum_posts_unapproved - ' . $topic_row['topic_posts_unapproved']; - $sql_data[$this->forums_table] .= ', forum_posts_softdeleted = forum_posts_softdeleted - ' . $topic_row['topic_posts_softdeleted']; + $sql_data[FORUMS_TABLE] .= 'forum_posts_approved = forum_posts_approved - 1, forum_topics_approved = forum_topics_approved - 1'; - $this->config->increment('num_topics', -1, false); - $this->config->increment('num_posts', $topic_row['topic_posts_approved'] * (-1), false); - - // Get user post count information - $sql = 'SELECT poster_id, COUNT(post_id) AS num_posts - FROM ' . $this->posts_table . ' - WHERE topic_id = ' . (int) $topic_id . ' - AND post_postcount = 1 - AND post_visibility = ' . ITEM_APPROVED . ' - GROUP BY poster_id'; - $result = $this->db->sql_query($sql); - - $postcounts = array(); - while ($row = $this->db->sql_fetchrow($result)) + if ($data['post_postcount']) + { + $sql_data[$this->users_table] = ((!empty($sql_data[$this->users_table])) ? $sql_data[$this->users_table] . ', ' : '') . 'user_posts = user_posts - 1'; + } + } + else if ($data['topic_visibility'] == ITEM_UNAPPROVED || $data['post_visibility'] == ITEM_REAPPROVE) { - $postcounts[(int) $row['num_posts']][] = (int) $row['poster_id']; + $sql_data[FORUMS_TABLE] .= 'forum_posts_unapproved = forum_posts_unapproved - 1, forum_topics_unapproved = forum_topics_unapproved - 1'; } - $this->db->sql_freeresult($result); - - // Decrement users post count - foreach ($postcounts as $num_posts => $poster_ids) + else if ($data['topic_visibility'] == ITEM_DELETED) { - $sql = 'UPDATE ' . $this->users_table . ' - SET user_posts = 0 - WHERE user_posts < ' . $num_posts . ' - AND ' . $this->db->sql_in_set('user_id', $poster_ids); - $this->db->sql_query($sql); - - $sql = 'UPDATE ' . $this->users_table . ' - SET user_posts = user_posts - ' . $num_posts . ' - WHERE user_posts >= ' . $num_posts . ' - AND ' . $this->db->sql_in_set('user_id', $poster_ids); - $this->db->sql_query($sql); + $sql_data[FORUMS_TABLE] .= 'forum_posts_softdeleted = forum_posts_softdeleted - 1, forum_topics_softdeleted = forum_topics_softdeleted - 1'; } + } } diff --git a/phpBB/phpbb/controller/resolver.php b/phpBB/phpbb/controller/resolver.php index efab34b701..948a6a218c 100644 --- a/phpBB/phpbb/controller/resolver.php +++ b/phpBB/phpbb/controller/resolver.php @@ -41,6 +41,12 @@ class resolver implements ControllerResolverInterface protected $template; /** + * Request type cast helper object + * @var \phpbb\request\type_cast_helper + */ + protected $type_cast_helper; + + /** * phpBB root path * @var string */ @@ -59,6 +65,7 @@ class resolver implements ControllerResolverInterface $this->user = $user; $this->container = $container; $this->template = $template; + $this->type_cast_helper = new \phpbb\request\type_cast_helper(); $this->phpbb_root_path = $phpbb_root_path; } @@ -138,7 +145,16 @@ class resolver implements ControllerResolverInterface { if (array_key_exists($param->name, $attributes)) { - $arguments[] = $attributes[$param->name]; + if (is_string($attributes[$param->name])) + { + $value = $attributes[$param->name]; + $this->type_cast_helper->set_var($value, $attributes[$param->name], 'string', true, false); + $arguments[] = $value; + } + else + { + $arguments[] = $attributes[$param->name]; + } } else if ($param->getClass() && $param->getClass()->isInstance($request)) { diff --git a/phpBB/phpbb/db/driver/driver.php b/phpBB/phpbb/db/driver/driver.php index 3e9110d8bc..9fc04d47a1 100644 --- a/phpBB/phpbb/db/driver/driver.php +++ b/phpBB/phpbb/db/driver/driver.php @@ -372,6 +372,17 @@ abstract class driver implements driver_interface /** * {@inheritDoc} */ + function sql_not_like_expression($expression) + { + $expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression); + $expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression); + + return $this->_sql_not_like_expression('NOT LIKE \'' . $this->sql_escape($expression) . '\''); + } + + /** + * {@inheritDoc} + */ public function sql_case($condition, $action_true, $action_false = false) { $sql_case = 'CASE WHEN ' . $condition; diff --git a/phpBB/phpbb/db/driver/driver_interface.php b/phpBB/phpbb/db/driver/driver_interface.php index 6722d059a5..8b487c5d42 100644 --- a/phpBB/phpbb/db/driver/driver_interface.php +++ b/phpBB/phpbb/db/driver/driver_interface.php @@ -419,6 +419,16 @@ interface driver_interface public function sql_like_expression($expression); /** + * Correctly adjust NOT LIKE expression for special characters + * Some DBMS are handling them in a different way + * + * @param string $expression The expression to use. Every wildcard is + * escaped, except $this->any_char and $this->one_char + * @return string A SQL statement like: "NOT LIKE 'bertie_%'" + */ + public function sql_not_like_expression($expression); + + /** * Explain queries * * @param string $mode Available modes: display, start, stop, diff --git a/phpBB/phpbb/db/driver/factory.php b/phpBB/phpbb/db/driver/factory.php index f0fa18051b..fb3a826254 100644 --- a/phpBB/phpbb/db/driver/factory.php +++ b/phpBB/phpbb/db/driver/factory.php @@ -420,6 +420,14 @@ class factory implements driver_interface /** * {@inheritdoc} */ + public function sql_not_like_expression($expression) + { + return $this->get_driver()->sql_not_like_expression($expression); + } + + /** + * {@inheritdoc} + */ public function sql_report($mode, $query = '') { return $this->get_driver()->sql_report($mode, $query); diff --git a/phpBB/phpbb/db/driver/mssql.php b/phpBB/phpbb/db/driver/mssql.php index 268463a151..f9ea884ce2 100644 --- a/phpBB/phpbb/db/driver/mssql.php +++ b/phpBB/phpbb/db/driver/mssql.php @@ -351,6 +351,15 @@ class mssql extends \phpbb\db\driver\driver } /** + * Build NOT LIKE expression + * @access private + */ + function _sql_not_like_expression($expression) + { + return $expression . " ESCAPE '\\'"; + } + + /** * return sql error array * @access private */ diff --git a/phpBB/phpbb/db/driver/mssql_base.php b/phpBB/phpbb/db/driver/mssql_base.php index e7101903b8..514df9eaca 100644 --- a/phpBB/phpbb/db/driver/mssql_base.php +++ b/phpBB/phpbb/db/driver/mssql_base.php @@ -52,6 +52,15 @@ abstract class mssql_base extends \phpbb\db\driver\driver } /** + * Build NOT LIKE expression + * @access private + */ + function _sql_not_like_expression($expression) + { + return $expression . " ESCAPE '\\'"; + } + + /** * Build db-specific query data * @access private */ diff --git a/phpBB/phpbb/db/driver/mysql_base.php b/phpBB/phpbb/db/driver/mysql_base.php index e7c9b63f20..5e0b359134 100644 --- a/phpBB/phpbb/db/driver/mysql_base.php +++ b/phpBB/phpbb/db/driver/mysql_base.php @@ -112,6 +112,15 @@ abstract class mysql_base extends \phpbb\db\driver\driver } /** + * Build NOT LIKE expression + * @access private + */ + function _sql_not_like_expression($expression) + { + return $expression; + } + + /** * Build db-specific query data * @access private */ diff --git a/phpBB/phpbb/db/driver/oracle.php b/phpBB/phpbb/db/driver/oracle.php index d1a186f1ba..6dcab5dd7d 100644 --- a/phpBB/phpbb/db/driver/oracle.php +++ b/phpBB/phpbb/db/driver/oracle.php @@ -645,6 +645,15 @@ class oracle extends \phpbb\db\driver\driver return $expression . " ESCAPE '\\'"; } + /** + * Build NOT LIKE expression + * @access private + */ + function _sql_not_like_expression($expression) + { + return $expression . " ESCAPE '\\'"; + } + function _sql_custom_build($stage, $data) { return $data; diff --git a/phpBB/phpbb/db/driver/postgres.php b/phpBB/phpbb/db/driver/postgres.php index 83e9fa51f6..a3b9aa4c6b 100644 --- a/phpBB/phpbb/db/driver/postgres.php +++ b/phpBB/phpbb/db/driver/postgres.php @@ -371,6 +371,15 @@ class postgres extends \phpbb\db\driver\driver } /** + * Build NOT LIKE expression + * @access private + */ + function _sql_not_like_expression($expression) + { + return $expression; + } + + /** * {@inheritDoc} */ function cast_expr_to_bigint($expression) diff --git a/phpBB/phpbb/db/driver/sqlite.php b/phpBB/phpbb/db/driver/sqlite.php index 2112e5ba2f..d5da0e2438 100644 --- a/phpBB/phpbb/db/driver/sqlite.php +++ b/phpBB/phpbb/db/driver/sqlite.php @@ -277,7 +277,7 @@ class sqlite extends \phpbb\db\driver\driver */ function sql_like_expression($expression) { - // Unlike LIKE, GLOB is case sensitive (unfortunatly). SQLite users need to live with it! + // Unlike LIKE, GLOB is unfortunately case sensitive. // 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); @@ -288,6 +288,23 @@ class sqlite extends \phpbb\db\driver\driver } /** + * {@inheritDoc} + * + * For SQLite an underscore is a not-known character... + */ + function sql_not_like_expression($expression) + { + // Unlike NOT LIKE, NOT GLOB is unfortunately case sensitive. + // 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 'NOT GLOB \'' . $this->sql_escape($expression) . '\''; + } + + /** * return sql error array * @access private */ diff --git a/phpBB/phpbb/db/driver/sqlite3.php b/phpBB/phpbb/db/driver/sqlite3.php index 0922229e0a..4e3e0d3329 100644 --- a/phpBB/phpbb/db/driver/sqlite3.php +++ b/phpBB/phpbb/db/driver/sqlite3.php @@ -260,11 +260,11 @@ class sqlite3 extends \phpbb\db\driver\driver /** * {@inheritDoc} * - * For SQLite an underscore is a not-known character... + * For SQLite an underscore is an unknown character. */ public function sql_like_expression($expression) { - // Unlike LIKE, GLOB is case sensitive (unfortunatly). SQLite users need to live with it! + // Unlike LIKE, GLOB is unfortunately case sensitive. // 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); @@ -275,6 +275,23 @@ class sqlite3 extends \phpbb\db\driver\driver } /** + * {@inheritDoc} + * + * For SQLite an underscore is an unknown character. + */ + public function sql_not_like_expression($expression) + { + // Unlike NOT LIKE, NOT GLOB is unfortunately case sensitive + // 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 'NOT GLOB \'' . $this->sql_escape($expression) . '\''; + } + + /** * return sql error array * * @return array diff --git a/phpBB/phpbb/db/migration/data/v310/captcha_plugins.php b/phpBB/phpbb/db/migration/data/v310/captcha_plugins.php new file mode 100644 index 0000000000..13071e9891 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v310/captcha_plugins.php @@ -0,0 +1,44 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v310; + +class captcha_plugins extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v310\rc2', + ); + } + + public function update_data() + { + $captcha_plugin = $this->config['captcha_plugin']; + if (strpos($this->config['captcha_plugin'], 'phpbb_captcha_') === 0) + { + $captcha_plugin = substr($this->config['captcha_plugin'], strlen('phpbb_captcha_')); + } + + return array( + array('if', array( + (is_file($this->phpbb_root_path . 'phpbb/captcha/plugins/' . $captcha_plugin . '.' . $this->php_ext)), + array('config.update', array('captcha_plugin', 'core.captcha.plugins.' . $captcha_plugin)), + )), + array('if', array( + (!is_file($this->phpbb_root_path . 'phpbb/captcha/plugins/' . $captcha_plugin . '.' . $this->php_ext)), + array('config.update', array('captcha_plugin', 'core.captcha.plugins.nogd')), + )), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v310/profilefield_facebook.php b/phpBB/phpbb/db/migration/data/v310/profilefield_facebook.php index 5964e7a997..7324b893cc 100644 --- a/phpBB/phpbb/db/migration/data/v310/profilefield_facebook.php +++ b/phpBB/phpbb/db/migration/data/v310/profilefield_facebook.php @@ -18,8 +18,9 @@ class profilefield_facebook extends \phpbb\db\migration\profilefield_base_migrat static public function depends_on() { return array( - '\phpbb\db\migration\data\v310\profilefield_types', + '\phpbb\db\migration\data\v310\profilefield_contact_field', '\phpbb\db\migration\data\v310\profilefield_show_novalue', + '\phpbb\db\migration\data\v310\profilefield_types', ); } diff --git a/phpBB/phpbb/db/migration/data/v310/profilefield_googleplus.php b/phpBB/phpbb/db/migration/data/v310/profilefield_googleplus.php index 9bef0a4c0b..3b0963fc19 100644 --- a/phpBB/phpbb/db/migration/data/v310/profilefield_googleplus.php +++ b/phpBB/phpbb/db/migration/data/v310/profilefield_googleplus.php @@ -18,8 +18,9 @@ class profilefield_googleplus extends \phpbb\db\migration\profilefield_base_migr static public function depends_on() { return array( - '\phpbb\db\migration\data\v310\profilefield_types', + '\phpbb\db\migration\data\v310\profilefield_contact_field', '\phpbb\db\migration\data\v310\profilefield_show_novalue', + '\phpbb\db\migration\data\v310\profilefield_types', ); } diff --git a/phpBB/phpbb/db/migration/data/v310/profilefield_skype.php b/phpBB/phpbb/db/migration/data/v310/profilefield_skype.php index 9a5de9d0eb..0dbe9041bb 100644 --- a/phpBB/phpbb/db/migration/data/v310/profilefield_skype.php +++ b/phpBB/phpbb/db/migration/data/v310/profilefield_skype.php @@ -18,8 +18,9 @@ class profilefield_skype extends \phpbb\db\migration\profilefield_base_migration static public function depends_on() { return array( - '\phpbb\db\migration\data\v310\profilefield_types', + '\phpbb\db\migration\data\v310\profilefield_contact_field', '\phpbb\db\migration\data\v310\profilefield_show_novalue', + '\phpbb\db\migration\data\v310\profilefield_types', ); } diff --git a/phpBB/phpbb/db/migration/data/v310/profilefield_twitter.php b/phpBB/phpbb/db/migration/data/v310/profilefield_twitter.php index 68d038f609..850e096439 100644 --- a/phpBB/phpbb/db/migration/data/v310/profilefield_twitter.php +++ b/phpBB/phpbb/db/migration/data/v310/profilefield_twitter.php @@ -18,8 +18,9 @@ class profilefield_twitter extends \phpbb\db\migration\profilefield_base_migrati static public function depends_on() { return array( - '\phpbb\db\migration\data\v310\profilefield_types', + '\phpbb\db\migration\data\v310\profilefield_contact_field', '\phpbb\db\migration\data\v310\profilefield_show_novalue', + '\phpbb\db\migration\data\v310\profilefield_types', ); } diff --git a/phpBB/phpbb/db/migration/data/v310/profilefield_youtube.php b/phpBB/phpbb/db/migration/data/v310/profilefield_youtube.php index bb90c0aa5c..40a569d2a2 100644 --- a/phpBB/phpbb/db/migration/data/v310/profilefield_youtube.php +++ b/phpBB/phpbb/db/migration/data/v310/profilefield_youtube.php @@ -18,8 +18,9 @@ class profilefield_youtube extends \phpbb\db\migration\profilefield_base_migrati static public function depends_on() { return array( - '\phpbb\db\migration\data\v310\profilefield_types', + '\phpbb\db\migration\data\v310\profilefield_contact_field', '\phpbb\db\migration\data\v310\profilefield_show_novalue', + '\phpbb\db\migration\data\v310\profilefield_types', ); } diff --git a/phpBB/phpbb/db/migration/data/v310/rc3.php b/phpBB/phpbb/db/migration/data/v310/rc3.php new file mode 100644 index 0000000000..0e6a452251 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v310/rc3.php @@ -0,0 +1,35 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v310; + +class rc3 extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v310\rc2', + '\phpbb\db\migration\data\v310\captcha_plugins', + '\phpbb\db\migration\data\v310\rename_too_long_indexes', + '\phpbb\db\migration\data\v310\search_type', + '\phpbb\db\migration\data\v310\topic_sort_username', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.1.0-RC3')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v310/soft_delete_mod_convert.php b/phpBB/phpbb/db/migration/data/v310/soft_delete_mod_convert.php index f5970e74b2..58845b88ec 100644 --- a/phpBB/phpbb/db/migration/data/v310/soft_delete_mod_convert.php +++ b/phpBB/phpbb/db/migration/data/v310/soft_delete_mod_convert.php @@ -119,8 +119,9 @@ class soft_delete_mod_convert extends \phpbb\db\migration\migration { return new \phpbb\content_visibility( new \phpbb\auth\auth(), + $this->config, $this->db, - new \phpbb\user(), + new \phpbb\user('\phpbb\datetime'), $this->phpbb_root_path, $this->php_ext, $this->table_prefix . 'forums', diff --git a/phpBB/phpbb/db/migration/data/v310/topic_sort_username.php b/phpBB/phpbb/db/migration/data/v310/topic_sort_username.php new file mode 100644 index 0000000000..527da20590 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v310/topic_sort_username.php @@ -0,0 +1,44 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v310; + +class topic_sort_username extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array('\phpbb\db\migration\data\v310\dev'); + } + + public function update_schema() + { + return array( + 'change_columns' => array( + $this->table_prefix . 'topics' => array( + 'topic_first_poster_name' => array('VCHAR_UNI:255', '', 'true_sort'), + ), + ), + ); + } + + public function revert_schema() + { + return array( + 'change_columns' => array( + $this->table_prefix . 'topics' => array( + 'topic_first_poster_name' => array('VCHAR_UNI:255', ''), + ), + ), + ); + } +} diff --git a/phpBB/phpbb/db/tools.php b/phpBB/phpbb/db/tools.php index 5d93eb8246..3567570137 100644 --- a/phpBB/phpbb/db/tools.php +++ b/phpBB/phpbb/db/tools.php @@ -1816,7 +1816,8 @@ class tools $old_return_statements = $this->return_statements; $this->return_statements = true; - $indexes = $this->mssql_get_existing_indexes($table_name, $column_name); + $indexes = $this->get_existing_indexes($table_name, $column_name); + $indexes = array_merge($indexes, $this->get_existing_indexes($table_name, $column_name, true)); // Drop any indexes $recreate_indexes = array(); @@ -2038,7 +2039,7 @@ class tools break; case 'oracle': - $statements[] = 'ALTER TABLE ' . $table_name . 'add CONSTRAINT pk_' . $table_name . ' PRIMARY KEY (' . implode(', ', $column) . ')'; + $statements[] = 'ALTER TABLE ' . $table_name . ' add CONSTRAINT pk_' . $table_name . ' PRIMARY KEY (' . implode(', ', $column) . ')'; break; case 'sqlite': @@ -2274,10 +2275,23 @@ class tools } /** + * Removes table_name from the index_name if it is at the beginning + * + * @param $table_name + * @param $index_name + * @return string + */ + protected function strip_table_name_from_index_name($table_name, $index_name) + { + return (strpos(strtoupper($index_name), strtoupper($table_name)) === 0) ? substr($index_name, strlen($table_name) + 1) : $index_name; + } + + /** * Change column type (not name!) */ function sql_column_change($table_name, $column_name, $column_data, $inline = false) { + $original_column_data = $column_data; $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data); $statements = array(); @@ -2289,12 +2303,14 @@ class tools $old_return_statements = $this->return_statements; $this->return_statements = true; - $indexes = $this->mssql_get_existing_indexes($table_name, $column_name); + $indexes = $this->get_existing_indexes($table_name, $column_name); + $unique_indexes = $this->get_existing_indexes($table_name, $column_name, true); // Drop any indexes - if (!empty($indexes)) + if (!empty($indexes) || !empty($unique_indexes)) { - foreach ($indexes as $index_name => $index_data) + $drop_indexes = array_merge(array_keys($indexes), array_keys($unique_indexes)); + foreach ($drop_indexes as $index_name) { $result = $this->sql_index_drop($table_name, $index_name); $statements = array_merge($statements, $result); @@ -2324,6 +2340,16 @@ class tools } } + if (!empty($unique_indexes)) + { + // Recreate unique indexes after we changed the column + foreach ($unique_indexes as $index_name => $index_data) + { + $result = $this->sql_create_unique_index($table_name, $index_name, $index_data); + $statements = array_merge($statements, $result); + } + } + $this->return_statements = $old_return_statements; break; @@ -2333,7 +2359,69 @@ class tools break; case 'oracle': - $statements[] = 'ALTER TABLE ' . $table_name . ' MODIFY ' . $column_name . ' ' . $column_data['column_type_sql']; + // We need the data here + $old_return_statements = $this->return_statements; + $this->return_statements = true; + + // Get list of existing indexes + $indexes = $this->get_existing_indexes($table_name, $column_name); + $unique_indexes = $this->get_existing_indexes($table_name, $column_name, true); + + // Drop any indexes + if (!empty($indexes) || !empty($unique_indexes)) + { + $drop_indexes = array_merge(array_keys($indexes), array_keys($unique_indexes)); + foreach ($drop_indexes as $index_name) + { + $result = $this->sql_index_drop($table_name, $this->strip_table_name_from_index_name($table_name, $index_name)); + $statements = array_merge($statements, $result); + } + } + + $temp_column_name = 'temp_' . substr(md5($column_name), 0, 25); + // Add a temporary table with the new type + $result = $this->sql_column_add($table_name, $temp_column_name, $original_column_data); + $statements = array_merge($statements, $result); + + // Copy the data to the new column + $statements[] = 'UPDATE ' . $table_name . ' SET ' . $temp_column_name . ' = ' . $column_name; + + // Drop the original column + $result = $this->sql_column_remove($table_name, $column_name); + $statements = array_merge($statements, $result); + + // Recreate the original column with the new type + $result = $this->sql_column_add($table_name, $column_name, $original_column_data); + $statements = array_merge($statements, $result); + + if (!empty($indexes)) + { + // Recreate indexes after we changed the column + foreach ($indexes as $index_name => $index_data) + { + $result = $this->sql_create_index($table_name, $this->strip_table_name_from_index_name($table_name, $index_name), $index_data); + $statements = array_merge($statements, $result); + } + } + + if (!empty($unique_indexes)) + { + // Recreate unique indexes after we changed the column + foreach ($unique_indexes as $index_name => $index_data) + { + $result = $this->sql_create_unique_index($table_name, $this->strip_table_name_from_index_name($table_name, $index_name), $index_data); + $statements = array_merge($statements, $result); + } + } + + // Copy the data to the original column + $statements[] = 'UPDATE ' . $table_name . ' SET ' . $column_name . ' = ' . $temp_column_name; + + // Drop the temporary column again + $result = $this->sql_column_remove($table_name, $temp_column_name); + $statements = array_merge($statements, $result); + + $this->return_statements = $old_return_statements; break; case 'postgres': @@ -2517,45 +2605,78 @@ class tools * * @param string $table_name * @param string $column_name + * @param bool $unique Should we get unique indexes or normal ones * @return array Array with Index name => columns */ - protected function mssql_get_existing_indexes($table_name, $column_name) + public function get_existing_indexes($table_name, $column_name, $unique = false) { - $existing_indexes = array(); - if ($this->mssql_is_sql_server_2000()) + switch ($this->sql_layer) { - // http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx - // Deprecated in SQL Server 2005 - $sql = "SELECT DISTINCT ix.name AS phpbb_index_name - FROM sysindexes ix - INNER JOIN sysindexkeys ixc - ON ixc.id = ix.id - AND ixc.indid = ix.indid - INNER JOIN syscolumns cols - ON cols.colid = ixc.colid - AND cols.id = ix.id - WHERE ix.id = object_id('{$table_name}') - AND cols.name = '{$column_name}'"; + case 'mysql_40': + case 'mysql_41': + case 'postgres': + case 'sqlite': + case 'sqlite3': + // Not supported + throw new \Exception('DBMS is not supported'); + break; } - else + + $sql = ''; + $existing_indexes = array(); + + switch ($this->sql_layer) { - $sql = "SELECT DISTINCT ix.name AS phpbb_index_name - FROM sys.indexes ix - INNER JOIN sys.index_columns ixc - ON ixc.object_id = ix.object_id - AND ixc.index_id = ix.index_id - INNER JOIN sys.columns cols - ON cols.column_id = ixc.column_id - AND cols.object_id = ix.object_id - WHERE ix.object_id = object_id('{$table_name}') - AND cols.name = '{$column_name}'"; + case 'mssql': + case 'mssqlnative': + if ($this->mssql_is_sql_server_2000()) + { + // http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx + // Deprecated in SQL Server 2005 + $sql = "SELECT DISTINCT ix.name AS phpbb_index_name + FROM sysindexes ix + INNER JOIN sysindexkeys ixc + ON ixc.id = ix.id + AND ixc.indid = ix.indid + INNER JOIN syscolumns cols + ON cols.colid = ixc.colid + AND cols.id = ix.id + WHERE ix.id = object_id('{$table_name}') + AND cols.name = '{$column_name}' + AND INDEXPROPERTY(ix.id, ix.name, 'IsUnique') = " . ($unique) ? '1' : '0'; + } + else + { + $sql = "SELECT DISTINCT ix.name AS phpbb_index_name + FROM sys.indexes ix + INNER JOIN sys.index_columns ixc + ON ixc.object_id = ix.object_id + AND ixc.index_id = ix.index_id + INNER JOIN sys.columns cols + ON cols.column_id = ixc.column_id + AND cols.object_id = ix.object_id + WHERE ix.object_id = object_id('{$table_name}') + AND cols.name = '{$column_name}' + AND ix.is_unique = " . ($unique) ? '1' : '0'; + } + break; + + case 'oracle': + $sql = "SELECT ix.index_name AS phpbb_index_name, ix.uniqueness AS is_unique + FROM all_ind_columns ixc, all_indexes ix + WHERE ix.index_name = ixc.index_name + AND ixc.table_name = '" . strtoupper($table_name) . "' + AND ixc.column_name = '" . strtoupper($column_name) . "'"; + break; } $result = $this->db->sql_query($sql); - $existing_indexes = array(); while ($row = $this->db->sql_fetchrow($result)) { - $existing_indexes[$row['phpbb_index_name']] = array(); + if (!isset($row['is_unique']) || ($unique && $row['is_unique'] == 'UNIQUE') || (!$unique && $row['is_unique'] == 'NONUNIQUE')) + { + $existing_indexes[$row['phpbb_index_name']] = array(); + } } $this->db->sql_freeresult($result); @@ -2564,35 +2685,47 @@ class tools return array(); } - if ($this->mssql_is_sql_server_2000()) - { - $sql = "SELECT DISTINCT ix.name AS phpbb_index_name, cols.name AS phpbb_column_name - FROM sysindexes ix - INNER JOIN sysindexkeys ixc - ON ixc.id = ix.id - AND ixc.indid = ix.indid - INNER JOIN syscolumns cols - ON cols.colid = ixc.colid - AND cols.id = ix.id - WHERE ix.id = object_id('{$table_name}') - AND " . $this->db->sql_in_set('ix.name', array_keys($existing_indexes)); - } - else + switch ($this->sql_layer) { - $sql = "SELECT DISTINCT ix.name AS phpbb_index_name, cols.name AS phpbb_column_name - FROM sys.indexes ix - INNER JOIN sys.index_columns ixc - ON ixc.object_id = ix.object_id - AND ixc.index_id = ix.index_id - INNER JOIN sys.columns cols - ON cols.column_id = ixc.column_id - AND cols.object_id = ix.object_id - WHERE ix.object_id = object_id('{$table_name}') - AND " . $this->db->sql_in_set('ix.name', array_keys($existing_indexes)); + case 'mssql': + case 'mssqlnative': + if ($this->mssql_is_sql_server_2000()) + { + $sql = "SELECT DISTINCT ix.name AS phpbb_index_name, cols.name AS phpbb_column_name + FROM sysindexes ix + INNER JOIN sysindexkeys ixc + ON ixc.id = ix.id + AND ixc.indid = ix.indid + INNER JOIN syscolumns cols + ON cols.colid = ixc.colid + AND cols.id = ix.id + WHERE ix.id = object_id('{$table_name}') + AND " . $this->db->sql_in_set('ix.name', array_keys($existing_indexes)); + } + else + { + $sql = "SELECT DISTINCT ix.name AS phpbb_index_name, cols.name AS phpbb_column_name + FROM sys.indexes ix + INNER JOIN sys.index_columns ixc + ON ixc.object_id = ix.object_id + AND ixc.index_id = ix.index_id + INNER JOIN sys.columns cols + ON cols.column_id = ixc.column_id + AND cols.object_id = ix.object_id + WHERE ix.object_id = object_id('{$table_name}') + AND " . $this->db->sql_in_set('ix.name', array_keys($existing_indexes)); + } + break; + + case 'oracle': + $sql = "SELECT index_name AS phpbb_index_name, column_name AS phpbb_column_name + FROM all_ind_columns + WHERE table_name = '" . strtoupper($table_name) . "' + AND " . $this->db->sql_in_set('index_name', array_keys($existing_indexes)); + break; } $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) { $existing_indexes[$row['phpbb_index_name']][] = $row['phpbb_column_name']; diff --git a/phpBB/phpbb/mimetype/content_guesser.php b/phpBB/phpbb/mimetype/content_guesser.php index 9c83e8dd73..f3ad7f5f41 100644 --- a/phpBB/phpbb/mimetype/content_guesser.php +++ b/phpBB/phpbb/mimetype/content_guesser.php @@ -20,7 +20,7 @@ class content_guesser extends guesser_base */ public function is_supported() { - return function_exists('mime_content_type'); + return function_exists('mime_content_type') && is_callable('mime_content_type'); } /** diff --git a/phpBB/phpbb/notification/type/approve_post.php b/phpBB/phpbb/notification/type/approve_post.php index 0aad19d6bf..22c9076adc 100644 --- a/phpBB/phpbb/notification/type/approve_post.php +++ b/phpBB/phpbb/notification/type/approve_post.php @@ -81,14 +81,7 @@ class approve_post extends \phpbb\notification\type\post $users = array(); $users[$post['poster_id']] = array(''); - $auth_read = $this->auth->acl_get_list(array_keys($users), 'f_read', $post['forum_id']); - - if (empty($auth_read)) - { - return array(); - } - - return $this->check_user_notification_options($auth_read[$post['forum_id']]['f_read'], array_merge($options, array( + return $this->get_authorised_recipients(array_keys($users), $post['forum_id'], array_merge($options, array( 'item_type' => self::$notification_option['id'], ))); } diff --git a/phpBB/phpbb/notification/type/approve_topic.php b/phpBB/phpbb/notification/type/approve_topic.php index e649f3920e..77e53a0064 100644 --- a/phpBB/phpbb/notification/type/approve_topic.php +++ b/phpBB/phpbb/notification/type/approve_topic.php @@ -81,14 +81,7 @@ class approve_topic extends \phpbb\notification\type\topic $users = array(); $users[$post['poster_id']] = array(''); - $auth_read = $this->auth->acl_get_list(array_keys($users), 'f_read', $post['forum_id']); - - if (empty($auth_read)) - { - return array(); - } - - return $this->check_user_notification_options($auth_read[$post['forum_id']]['f_read'], array_merge($options, array( + return $this->get_authorised_recipients(array_keys($users), $post['forum_id'], array_merge($options, array( 'item_type' => self::$notification_option['id'], ))); } diff --git a/phpBB/phpbb/notification/type/base.php b/phpBB/phpbb/notification/type/base.php index a11ad76db9..4ead06071e 100644 --- a/phpBB/phpbb/notification/type/base.php +++ b/phpBB/phpbb/notification/type/base.php @@ -533,4 +533,37 @@ abstract class base implements \phpbb\notification\type\type_interface WHERE ' . $where; $this->db->sql_query($sql); } + + /** + * Get a list of users that are authorised to receive notifications + * + * @param array $users Array of users that have subscribed to a notification + * @param int $forum_id Forum ID of the forum + * @param array $options Array of notification options + * @param bool $sort Whether the users array should be sorted. Default: false + * @return array Array of users that are authorised recipients + */ + protected function get_authorised_recipients($users, $forum_id, $options, $sort = false) + { + if (empty($users)) + { + return array(); + } + + $users = array_unique($users); + + if ($sort) + { + sort($users); + } + + $auth_read = $this->auth->acl_get_list($users, 'f_read', $forum_id); + + if (empty($auth_read)) + { + return array(); + } + + return $this->check_user_notification_options($auth_read[$forum_id]['f_read'], $options); + } } diff --git a/phpBB/phpbb/notification/type/bookmark.php b/phpBB/phpbb/notification/type/bookmark.php index c83288cfb8..21180b3b53 100644 --- a/phpBB/phpbb/notification/type/bookmark.php +++ b/phpBB/phpbb/notification/type/bookmark.php @@ -83,21 +83,13 @@ class bookmark extends \phpbb\notification\type\post } $this->db->sql_freeresult($result); - if (empty($users)) - { - return array(); - } - sort($users); + $notify_users = $this->get_authorised_recipients($users, $post['forum_id'], $options, true); - $auth_read = $this->auth->acl_get_list($users, 'f_read', $post['forum_id']); - - if (empty($auth_read)) + if (empty($notify_users)) { return array(); } - $notify_users = $this->check_user_notification_options($auth_read[$post['forum_id']]['f_read'], $options); - // Try to find the users who already have been notified about replies and have not read the topic since and just update their notifications $update_notifications = array(); $sql = 'SELECT n.* diff --git a/phpBB/phpbb/notification/type/post.php b/phpBB/phpbb/notification/type/post.php index 357176ec35..1eba4a6a88 100644 --- a/phpBB/phpbb/notification/type/post.php +++ b/phpBB/phpbb/notification/type/post.php @@ -123,23 +123,13 @@ class post extends \phpbb\notification\type\base } $this->db->sql_freeresult($result); - if (empty($users)) - { - return array(); - } + $notify_users = $this->get_authorised_recipients($users, $post['forum_id'], $options, true); - $users = array_unique($users); - sort($users); - - $auth_read = $this->auth->acl_get_list($users, 'f_read', $post['forum_id']); - - if (empty($auth_read)) + if (empty($notify_users)) { return array(); } - $notify_users = $this->check_user_notification_options($auth_read[$post['forum_id']]['f_read'], $options); - // Try to find the users who already have been notified about replies and have not read the topic since and just update their notifications $update_notifications = array(); $sql = 'SELECT n.* diff --git a/phpBB/phpbb/notification/type/quote.php b/phpBB/phpbb/notification/type/quote.php index 6e672e6fbd..5c3c822ec2 100644 --- a/phpBB/phpbb/notification/type/quote.php +++ b/phpBB/phpbb/notification/type/quote.php @@ -102,22 +102,7 @@ class quote extends \phpbb\notification\type\post } $this->db->sql_freeresult($result); - if (empty($users)) - { - return array(); - } - sort($users); - - $auth_read = $this->auth->acl_get_list($users, 'f_read', $post['forum_id']); - - if (empty($auth_read)) - { - return array(); - } - - $notify_users = $this->check_user_notification_options($auth_read[$post['forum_id']]['f_read'], $options); - - return $notify_users; + return $this->get_authorised_recipients($users, $post['forum_id'], $options, true); } /** diff --git a/phpBB/phpbb/notification/type/topic.php b/phpBB/phpbb/notification/type/topic.php index 289e45bedb..af199fb765 100644 --- a/phpBB/phpbb/notification/type/topic.php +++ b/phpBB/phpbb/notification/type/topic.php @@ -111,19 +111,7 @@ class topic extends \phpbb\notification\type\base } $this->db->sql_freeresult($result); - if (empty($users)) - { - return array(); - } - - $auth_read = $this->auth->acl_get_list($users, 'f_read', $topic['forum_id']); - - if (empty($auth_read)) - { - return array(); - } - - return $this->check_user_notification_options($auth_read[$topic['forum_id']]['f_read'], $options); + return $this->get_authorised_recipients($users, $topic['forum_id'], $options); } /** diff --git a/phpBB/phpbb/profilefields/type/type_googleplus.php b/phpBB/phpbb/profilefields/type/type_googleplus.php index 887baa3de1..e6729b1935 100644 --- a/phpBB/phpbb/profilefields/type/type_googleplus.php +++ b/phpBB/phpbb/profilefields/type/type_googleplus.php @@ -40,7 +40,7 @@ class type_googleplus extends type_string 'field_length' => 20, 'field_minlen' => 3, 'field_maxlen' => 255, - 'field_validation' => '[\w]+', + 'field_validation' => '(?:(?!\.{2,})([^<>=+]))+', 'field_novalue' => '', 'field_default_value' => '', ); diff --git a/phpBB/phpbb/session.php b/phpBB/phpbb/session.php index 5a0d7c0031..7d564742af 100644 --- a/phpBB/phpbb/session.php +++ b/phpBB/phpbb/session.php @@ -962,7 +962,7 @@ class session */ function session_gc() { - global $db, $config, $phpbb_root_path, $phpEx; + global $db, $config, $phpbb_root_path, $phpEx, $phpbb_container; $batch_size = 10; @@ -1022,11 +1022,7 @@ class session } // only called from CRON; should be a safe workaround until the infrastructure gets going - if (!class_exists('phpbb_captcha_factory', false)) - { - include($phpbb_root_path . "includes/captcha/captcha_factory." . $phpEx); - } - $captcha_factory = new \phpbb_captcha_factory(); + $captcha_factory = $phpbb_container->get('captcha.factory'); $captcha_factory->garbage_collect($config['captcha_plugin']); $sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . ' diff --git a/phpBB/phpbb/user.php b/phpBB/phpbb/user.php index 4e90044395..ea98034434 100644 --- a/phpBB/phpbb/user.php +++ b/phpBB/phpbb/user.php @@ -31,6 +31,11 @@ class user extends \phpbb\session */ public $timezone; + /** + * @var string Class name of datetime object + */ + protected $datetime; + var $lang_name = false; var $lang_id = false; var $lang_path; @@ -42,12 +47,14 @@ class user extends \phpbb\session /** * Constructor to set the lang path + * @param string $datetime_class Class name of datetime class */ - function __construct() + function __construct($datetime_class) { global $phpbb_root_path; $this->lang_path = $phpbb_root_path . 'language/'; + $this->datetime = $datetime_class; } /** @@ -727,7 +734,7 @@ class user extends \phpbb\session public function create_datetime($time = 'now', \DateTimeZone $timezone = null) { $timezone = $timezone ?: $this->timezone; - return new \phpbb\datetime($this, $time, $timezone); + return new $this->datetime($this, $time, $timezone); } /** diff --git a/phpBB/posting.php b/phpBB/posting.php index 6638caa94b..4c3d012ca5 100644 --- a/phpBB/posting.php +++ b/phpBB/posting.php @@ -241,8 +241,7 @@ $user->setup(array('posting', 'mcp', 'viewtopic'), $post_data['forum_style']); if ($config['enable_post_confirm'] && !$user->data['is_registered']) { - include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); - $captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']); $captcha->init(CONFIRM_POST); } diff --git a/phpBB/report.php b/phpBB/report.php index 3684c2162f..fd6fab6645 100644 --- a/phpBB/report.php +++ b/phpBB/report.php @@ -151,8 +151,7 @@ else if ($config['enable_post_confirm'] && !$user->data['is_registered']) { - include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); - $captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']); $captcha->init(CONFIRM_REPORT); } diff --git a/phpBB/styles/prosilver/style.cfg b/phpBB/styles/prosilver/style.cfg index 520b1f0e98..aea59021d6 100644 --- a/phpBB/styles/prosilver/style.cfg +++ b/phpBB/styles/prosilver/style.cfg @@ -21,8 +21,8 @@ # General Information about this style name = prosilver copyright = © phpBB Limited, 2007 -style_version = 3.1.0-RC2 -phpbb_version = 3.1.0-RC2 +style_version = 3.1.0-RC3 +phpbb_version = 3.1.0-RC3 # Defining a different template bitfield # template_bitfield = lNg= diff --git a/phpBB/styles/prosilver/template/ajax.js b/phpBB/styles/prosilver/template/ajax.js index 649a384418..63efe5f8ae 100644 --- a/phpBB/styles/prosilver/template/ajax.js +++ b/phpBB/styles/prosilver/template/ajax.js @@ -134,6 +134,11 @@ phpbb.markNotifications = function(el, unreadCount) { if (!unreadCount) { $('#mark_all_notifications').remove(); } + + // Update page title + $('title').text( + (unreadCount ? '(' + unreadCount + ')' : '') + $('title').text().replace(/(\(([0-9])\))/, '') + ); }; // This callback finds the post from the delete link, and removes it. diff --git a/phpBB/styles/prosilver/template/ucp_avatar_options.html b/phpBB/styles/prosilver/template/ucp_avatar_options.html index ca077fdf5b..2cf9488ed0 100644 --- a/phpBB/styles/prosilver/template/ucp_avatar_options.html +++ b/phpBB/styles/prosilver/template/ucp_avatar_options.html @@ -17,7 +17,6 @@ <dl> <dt><label>{L_AVATAR_TYPE}{L_COLON}</label></dt> <dd><select name="avatar_driver" id="avatar_driver" data-togglable-settings="true"> - <option value="">{L_NO_AVATAR}</option> <!-- BEGIN avatar_drivers --> <option value="{avatar_drivers.DRIVER}"<!-- IF avatar_drivers.SELECTED --> selected="selected"<!-- ENDIF --> data-toggle-setting="#avatar_option_{avatar_drivers.DRIVER}">{avatar_drivers.L_TITLE}</option> <!-- END avatar_drivers --> diff --git a/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html b/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html index 489c1c901a..941541c582 100644 --- a/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html +++ b/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html @@ -18,7 +18,14 @@ <div class="inner"> <dl class="postprofile" id="profile{MESSAGE_ID}"> - <dt class="<!-- IF RANK_TITLE or RANK_IMG -->has-profile-rank<!-- ELSE -->no-profile-rank<!-- ENDIF -->"><!-- IF AUTHOR_AVATAR --><a href="{U_MESSAGE_AUTHOR}" class="avatar">{AUTHOR_AVATAR}</a><!-- ENDIF -->{MESSAGE_AUTHOR_FULL}</dt> + <dt class="<!-- IF RANK_TITLE or RANK_IMG -->has-profile-rank<!-- ELSE -->no-profile-rank<!-- ENDIF --> <!-- IF AUTHOR_AVATAR -->has-avatar<!-- ELSE -->no-avatar<!-- ENDIF -->"> + <div class="avatar-container"> + <!-- EVENT ucp_pm_viewmessage_avatar_before --> + <!-- IF AUTHOR_AVATAR --><a href="{U_MESSAGE_AUTHOR}" class="avatar">{AUTHOR_AVATAR}</a><!-- ENDIF --> + <!-- EVENT ucp_pm_viewmessage_avatar_after --> + </div> + {MESSAGE_AUTHOR_FULL} + </dt> <!-- IF RANK_TITLE or RANK_IMG --><dd class="profile-rank">{RANK_TITLE}<!-- IF RANK_TITLE and RANK_IMG --><br /><!-- ENDIF -->{RANK_IMG}</dd><!-- ENDIF --> @@ -106,16 +113,6 @@ <dl class="attachbox"> <dt> {L_ATTACHMENTS} - <!-- IF S_HAS_MULTIPLE_ATTACHMENTS --> - <div class="dl_links"> - <strong>{L_DOWNLOAD_ALL}{L_COLON}</strong> - <ul> - <!-- BEGIN dl_method --> - <li>[ <a href="{dl_method.LINK}">{dl_method.TYPE}</a> ]</li> - <!-- END dl_method --> - </ul> - </div> - <!-- ENDIF --> </dt> <!-- BEGIN attachment --> <dd>{attachment.DISPLAY_ATTACHMENT}</dd> diff --git a/phpBB/styles/prosilver/template/viewtopic_body.html b/phpBB/styles/prosilver/template/viewtopic_body.html index b764979f97..ac9c9a362a 100644 --- a/phpBB/styles/prosilver/template/viewtopic_body.html +++ b/phpBB/styles/prosilver/template/viewtopic_body.html @@ -124,10 +124,14 @@ <div class="inner"> <dl class="postprofile" id="profile{postrow.POST_ID}"<!-- IF postrow.S_POST_HIDDEN --> style="display: none;"<!-- ENDIF -->> - <dt class="<!-- IF postrow.RANK_TITLE or postrow.RANK_IMG -->has-profile-rank<!-- ELSE -->no-profile-rank<!-- ENDIF -->"> - <!-- IF postrow.POSTER_AVATAR --> - <!-- IF postrow.U_POST_AUTHOR --><a href="{postrow.U_POST_AUTHOR}" class="avatar">{postrow.POSTER_AVATAR}</a><!-- ELSE --><span class="avatar">{postrow.POSTER_AVATAR}</span><!-- ENDIF --> - <!-- ENDIF --> + <dt class="<!-- IF postrow.RANK_TITLE or postrow.RANK_IMG -->has-profile-rank<!-- ELSE -->no-profile-rank<!-- ENDIF --> <!-- IF postrow.POSTER_AVATAR -->has-avatar<!-- ELSE -->no-avatar<!-- ENDIF -->"> + <div class="avatar-container"> + <!-- EVENT viewtopic_body_avatar_before --> + <!-- IF postrow.POSTER_AVATAR --> + <!-- IF postrow.U_POST_AUTHOR --><a href="{postrow.U_POST_AUTHOR}" class="avatar">{postrow.POSTER_AVATAR}</a><!-- ELSE --><span class="avatar">{postrow.POSTER_AVATAR}</span><!-- ENDIF --> + <!-- ENDIF --> + <!-- EVENT viewtopic_body_avatar_after --> + </div> <!-- IF not postrow.U_POST_AUTHOR --><strong>{postrow.POST_AUTHOR_FULL}</strong><!-- ELSE -->{postrow.POST_AUTHOR_FULL}<!-- ENDIF --> </dt> @@ -274,16 +278,6 @@ <dl class="attachbox"> <dt> {L_ATTACHMENTS} - <!-- IF postrow.S_MULTIPLE_ATTACHMENTS --> - <div class="dl_links"> - <strong>{L_DOWNLOAD_ALL}{L_COLON}</strong> - <ul> - <!-- BEGIN dl_method --> - <li>[ <a href="{postrow.dl_method.LINK}">{postrow.dl_method.TYPE}</a> ]</li> - <!-- END dl_method --> - </ul> - </div> - <!-- ENDIF --> </dt> <!-- BEGIN attachment --> <dd>{postrow.attachment.DISPLAY_ATTACHMENT}</dd> diff --git a/phpBB/styles/prosilver/template/viewtopic_topic_tools.html b/phpBB/styles/prosilver/template/viewtopic_topic_tools.html index 2a34ebd446..83904bf63d 100644 --- a/phpBB/styles/prosilver/template/viewtopic_topic_tools.html +++ b/phpBB/styles/prosilver/template/viewtopic_topic_tools.html @@ -18,18 +18,6 @@ <!-- IF U_BUMP_TOPIC --><li class="small-icon icon-bump"><a href="{U_BUMP_TOPIC}" title="{L_BUMP_TOPIC}" data-ajax="true">{L_BUMP_TOPIC}</a></li><!-- ENDIF --> <!-- IF U_EMAIL_TOPIC --><li class="small-icon icon-sendemail"><a href="{U_EMAIL_TOPIC}" title="{L_EMAIL_TOPIC}">{L_EMAIL_TOPIC}</a></li><!-- ENDIF --> <!-- IF U_PRINT_TOPIC --><li class="small-icon icon-print"><a href="{U_PRINT_TOPIC}" title="{L_PRINT_TOPIC}" accesskey="p">{L_PRINT_TOPIC}</a></li><!-- ENDIF --> - <!-- IF S_HAS_ATTACHMENTS --> - <li class="small-icon icon-download"> - <a class="dropdown-toggle-submenu" href="{U_DOWNLOAD_ALL_ATTACHMENTS}" title="{L_DOWNLOAD_ALL_ATTACHMENTS}">{L_DOWNLOAD_ALL_ATTACHMENTS}</a> - <ul class="dropdown-submenu hidden"> - <li> - <!-- BEGIN dl_method --> - <a href="{dl_method.LINK}">{dl_method.TYPE}</a><!-- IF not dl_method.S_LAST_ROW --> • <!-- ENDIF --> - <!-- END dl_method --> - </li> - </ul> - </li> - <!-- ENDIF --> <!-- EVENT viewtopic_topic_tools_after --> </ul> </div> diff --git a/phpBB/styles/prosilver/theme/bidi.css b/phpBB/styles/prosilver/theme/bidi.css index d3594cc5bd..0d98fe7a66 100644 --- a/phpBB/styles/prosilver/theme/bidi.css +++ b/phpBB/styles/prosilver/theme/bidi.css @@ -112,6 +112,15 @@ text-align: right; } +.rtl .dropdown-contents > li { + padding-left: 15px; + padding-right: 0; +} + +.rtl .dropdown-nonscroll > li { + padding-left: 0; +} + .rtl .dropdown li li { padding-left: 0; padding-right: 18px; @@ -332,12 +341,8 @@ li.breadcrumbs span:first-child > a { .rtl .skiplink { /* invisible skip link, used for accessibility */ - position: relative; - width: 1px; - height: 1px; - overflow: hidden; - display: block; left: 0; + right: -999px; } .rtl a.feed-icon-forum { @@ -586,6 +591,10 @@ li.breadcrumbs span:first-child > a { margin-right: 8px; } +.rtl .postprofile .avatar { + float: right; +} + .rtl .online { background-position: 0 0; } @@ -601,8 +610,8 @@ li.breadcrumbs span:first-child > a { /* Rollover buttons Based on: http://wellstyled.com/css-nopreload-rollovers.html ----------------------------------------*/ -.rtl .icon-button.dropdown-select { - padding-left: 26px; +.rtl .dropdown-select { + padding-left: 24px; padding-right: 8px; } @@ -612,7 +621,12 @@ li.breadcrumbs span:first-child > a { margin-right: 2px; } -.dropdown-select:after { +.rtl .dropdown-select.icon-button:before { + margin-left: 4px; + margin-right: 0; +} + +.rtl .dropdown-select:after { border-left: 0; border-right-style: solid; border-right-width: 1px; @@ -915,16 +929,6 @@ li.breadcrumbs span:first-child > a { float: left; } -/* Jumpbox */ -.rtl fieldset.jumpbox { - text-align: left; -} - -.rtl fieldset.quickmod { - float: left; - text-align: left; -} - /* Posting page styles ----------------------------------------*/ @@ -1078,8 +1082,11 @@ li.breadcrumbs span:first-child > a { border-width: 0 0 1px 0; } + .rtl .postprofile dt, .rtl .postprofile dd.profile-rank, .rtl .search .postprofile dd { + margin: 0; + } + .rtl .postprofile .avatar { - float: right; margin-left: 5px; margin-right: 0; } diff --git a/phpBB/styles/prosilver/theme/colours.css b/phpBB/styles/prosilver/theme/colours.css index 82542c8d86..df27467cf8 100644 --- a/phpBB/styles/prosilver/theme/colours.css +++ b/phpBB/styles/prosilver/theme/colours.css @@ -610,7 +610,7 @@ Colours and backgrounds for buttons.css color: #D31141; } -.dropdown-select, .dropdown-select:visited { +.dropdown-select { color: #536482; } diff --git a/phpBB/styles/prosilver/theme/common.css b/phpBB/styles/prosilver/theme/common.css index 54d81406e8..45cb88890d 100644 --- a/phpBB/styles/prosilver/theme/common.css +++ b/phpBB/styles/prosilver/theme/common.css @@ -305,12 +305,6 @@ ol ol ul, ol ul ul, ul ol ul, ul ul ul { border-radius: 7px; } -.inner:after { - content: ''; - clear: both; - display: block; -} - .rowbg { margin: 5px 5px 2px 5px; } @@ -326,12 +320,6 @@ ul.linklist { margin: 0; } -ul.linklist:after { - content: ''; - display: block; - clear: both; -} - #cp-main .panel { padding: 5px 10px; } @@ -856,12 +844,6 @@ fieldset.fields1 dl.pmlist dd.recipients { margin-top: 2em; } -.action-bar:after { - clear: both; - content: ''; - display: block; -} - /* Pagination ---------------------------------------- */ .pagination { @@ -1130,6 +1112,20 @@ form > p.post-notice strong { background: transparent; } +/* Inner box-model clearing */ +.inner:after, +ul.linklist:after, +.action-bar:after, +.notification_text:after, +.tabs-container:after, +#tabs > ul:after, +#minitabs > ul:after, +.postprofile .avatar-container:after { + clear: both; + content: ''; + display: block; +} + .hidden { display: none; } @@ -1285,12 +1281,6 @@ form > p.post-notice strong { margin-left: 58px; } -.notification_text:after { - content: ''; - clear: both; - display: block; -} - /* Navbar specific list items ----------------------------------------*/ diff --git a/phpBB/styles/prosilver/theme/content.css b/phpBB/styles/prosilver/theme/content.css index a014f57d47..8b84545a2c 100644 --- a/phpBB/styles/prosilver/theme/content.css +++ b/phpBB/styles/prosilver/theme/content.css @@ -710,15 +710,22 @@ fieldset.polls dd div { margin-bottom: 10px; } +/* Post-profile avatars */ +.postprofile .has-avatar .avatar-container { + margin-bottom: 3px; + overflow: hidden; +} + .postprofile .avatar { display: block; - border: none; - margin-bottom: 3px; + float: left; + max-width: 100%; } .postprofile .avatar img { - max-width: 90%; + display: block; height: auto !important; + max-width: 100%; } dd.profile-warnings { diff --git a/phpBB/styles/prosilver/theme/cp.css b/phpBB/styles/prosilver/theme/cp.css index 5149a16ec9..d3699c3012 100644 --- a/phpBB/styles/prosilver/theme/cp.css +++ b/phpBB/styles/prosilver/theme/cp.css @@ -96,12 +96,6 @@ ul.cplist { margin-bottom: 0px; } -.tabs-container:after { - clear: both; - content: ''; - display: block; -} - /* CP tabs shared ----------------------------------------*/ #tabs, #minitabs { @@ -115,12 +109,6 @@ ul.cplist { position: relative; } -#tabs > ul:after, #minitabs > ul:after { - clear: both; - content: ''; - display: block; -} - #tabs .tab, #minitabs .tab { display: inline-block; float: left; diff --git a/phpBB/styles/prosilver/theme/images/icon_print.gif b/phpBB/styles/prosilver/theme/images/icon_print.gif Binary files differindex e464e304ea..e464e304ea 100755..100644 --- a/phpBB/styles/prosilver/theme/images/icon_print.gif +++ b/phpBB/styles/prosilver/theme/images/icon_print.gif diff --git a/phpBB/styles/prosilver/theme/responsive.css b/phpBB/styles/prosilver/theme/responsive.css index 241b4d132e..3ef0044621 100644 --- a/phpBB/styles/prosilver/theme/responsive.css +++ b/phpBB/styles/prosilver/theme/responsive.css @@ -424,16 +424,22 @@ fieldset.polls dd.resultbar, fieldset.polls dd.poll_option_percent { margin: 0; } +.postprofile .has-avatar .avatar-container { + margin: 0; + overflow: inherit; +} + +.postprofile .avatar-container:after { + clear: none; +} + .postprofile .avatar { - display: block; - float: left; margin-right: 5px; } .postprofile .avatar img { width: auto !important; height: auto !important; - display: block; max-height: 32px; } @@ -460,12 +466,6 @@ p.rightside { margin-bottom: 0; } -fieldset.quickmod { - width: auto; - float: none; - text-align: center; -} - fieldset.display-options label { display: block; clear: both; @@ -503,14 +503,11 @@ fieldset.display-actions { margin: 0; } - .action-bar > .pagination, fieldset.jumpbox { - text-align: center; - } - .action-bar > .pagination { float: none; clear: both; padding-bottom: 1px; + text-align: center; } .action-bar > .pagination li.page-jump { diff --git a/phpBB/styles/prosilver/theme/tweaks.css b/phpBB/styles/prosilver/theme/tweaks.css index ea0c66d20a..851b3a6bb6 100644 --- a/phpBB/styles/prosilver/theme/tweaks.css +++ b/phpBB/styles/prosilver/theme/tweaks.css @@ -71,3 +71,8 @@ dd.option { .header-avatar img { height: 20px; } + +/* IE8 often can't handle max-width in %, so we use px instead */ +.postprofile .avatar img { + max-width: 150px; +} diff --git a/phpBB/styles/subsilver2/style.cfg b/phpBB/styles/subsilver2/style.cfg index 633acf66e0..3ef3154742 100644 --- a/phpBB/styles/subsilver2/style.cfg +++ b/phpBB/styles/subsilver2/style.cfg @@ -21,8 +21,8 @@ # General Information about this style name = subsilver2 copyright = © 2005 phpBB Limited -style_version = 3.1.0-RC2 -phpbb_version = 3.1.0-RC2 +style_version = 3.1.0-RC3 +phpbb_version = 3.1.0-RC3 # Defining a different template bitfield # template_bitfield = lNg= diff --git a/phpBB/styles/subsilver2/template/ucp_groups_manage.html b/phpBB/styles/subsilver2/template/ucp_groups_manage.html index 55c1c20528..09d59c8ec0 100644 --- a/phpBB/styles/subsilver2/template/ucp_groups_manage.html +++ b/phpBB/styles/subsilver2/template/ucp_groups_manage.html @@ -78,7 +78,6 @@ <td class="row1" width="35%"><b class="genmed">{L_AVATAR_TYPE}{L_COLON}</b></td> <td class="row2"> <select name="avatar_driver" id="avatar_driver"> - <option value="">{L_NO_AVATAR}</option> <!-- BEGIN avatar_drivers --> <option value="{avatar_drivers.DRIVER}"<!-- IF avatar_drivers.SELECTED --> selected="selected"<!-- ENDIF -->>{avatar_drivers.L_TITLE}</option> <!-- END avatar_drivers --> diff --git a/phpBB/styles/subsilver2/template/ucp_profile_avatar.html b/phpBB/styles/subsilver2/template/ucp_profile_avatar.html index fc52c149c6..8b1e8cffac 100644 --- a/phpBB/styles/subsilver2/template/ucp_profile_avatar.html +++ b/phpBB/styles/subsilver2/template/ucp_profile_avatar.html @@ -28,7 +28,6 @@ <td class="row1" width="35%"><b class="genmed">{L_AVATAR_TYPE}{L_COLON}</b></td> <td class="row2"> <select name="avatar_driver" id="avatar_driver" data-togglable-settings="true"> - <option value="">{L_NO_AVATAR}</option> <!-- BEGIN avatar_drivers --> <option value="{avatar_drivers.DRIVER}"<!-- IF avatar_drivers.SELECTED --> selected="selected"<!-- ENDIF --> data-toggle-setting=".avatar_option_{avatar_drivers.DRIVER}">{avatar_drivers.L_TITLE}</option> <!-- END avatar_drivers --> diff --git a/phpBB/styles/subsilver2/template/viewtopic_body.html b/phpBB/styles/subsilver2/template/viewtopic_body.html index c69be83a1e..0f34b50950 100644 --- a/phpBB/styles/subsilver2/template/viewtopic_body.html +++ b/phpBB/styles/subsilver2/template/viewtopic_body.html @@ -192,11 +192,15 @@ <td>{postrow.RANK_IMG}</td> </tr> <!-- ENDIF --> + + <!-- EVENT viewtopic_body_avatar_before --> <!-- IF postrow.POSTER_AVATAR --> <tr> <td>{postrow.POSTER_AVATAR}</td> </tr> <!-- ENDIF --> + <!-- EVENT viewtopic_body_avatar_after --> + <!-- IF not (postrow.ONLINE_IMG or postrow.RANK_TITLE or postrow.RANK_IMG or postrow.POSTER_AVATAR) --> <tr> <td></td> diff --git a/phpBB/viewtopic.php b/phpBB/viewtopic.php index 1fdce5a6c3..8d7ab5323d 100644 --- a/phpBB/viewtopic.php +++ b/phpBB/viewtopic.php @@ -539,8 +539,8 @@ $s_quickmod_action = append_sid( $quickmod_array = array( // 'key' => array('LANG_KEY', $userHasPermissions), - 'lock' => array('LOCK_TOPIC', ($topic_data['topic_status'] == ITEM_UNLOCKED) && ($auth->acl_get('m_lock', $forum_id) || ($auth->acl_get('f_user_lock', $forum_id) && $user->data['is_registered'] && $user->data['user_id'] == $topic_data['topic_poster'] && $topic_data['topic_status'] == ITEM_UNLOCKED))), - 'unlock' => array('UNLOCK_TOPIC', ($topic_data['topic_status'] != ITEM_UNLOCKED) && ($auth->acl_get('m_lock', $forum_id) || ($auth->acl_get('f_user_lock', $forum_id) && $user->data['is_registered'] && $user->data['user_id'] == $topic_data['topic_poster'] && $topic_data['topic_status'] == ITEM_UNLOCKED))), + 'lock' => array('LOCK_TOPIC', ($topic_data['topic_status'] == ITEM_UNLOCKED) && ($auth->acl_get('m_lock', $forum_id) || ($auth->acl_get('f_user_lock', $forum_id) && $user->data['is_registered'] && $user->data['user_id'] == $topic_data['topic_poster']))), + 'unlock' => array('UNLOCK_TOPIC', ($topic_data['topic_status'] != ITEM_UNLOCKED) && ($auth->acl_get('m_lock', $forum_id))), 'delete_topic' => array('DELETE_TOPIC', ($auth->acl_get('m_delete', $forum_id) || (($topic_data['topic_visibility'] != ITEM_DELETED) && $auth->acl_get('m_softdelete', $forum_id)))), 'restore_topic' => array('RESTORE_TOPIC', (($topic_data['topic_visibility'] == ITEM_DELETED) && $auth->acl_get('m_approve', $forum_id))), 'move' => array('MOVE_TOPIC', $auth->acl_get('m_move', $forum_id) && $topic_data['topic_status'] != ITEM_MOVED), @@ -1392,17 +1392,6 @@ if (sizeof($attach_list)) } } -$methods = phpbb_gen_download_links('topic_id', $topic_id, $phpbb_root_path, $phpEx); -foreach ($methods as $method) -{ - $template->assign_block_vars('dl_method', $method); -} - -$template->assign_vars(array( - 'S_HAS_ATTACHMENTS' => $topic_data['topic_attachment'], - 'U_DOWNLOAD_ALL_ATTACHMENTS' => $methods[0]['LINK'], -)); - // Instantiate BBCode if need be if ($bbcode_bitfield !== '') { @@ -1420,6 +1409,7 @@ $i_total = sizeof($rowset) - 1; $prev_post_id = ''; $template->assign_vars(array( + 'S_HAS_ATTACHMENTS' => $topic_data['topic_attachment'], 'S_NUM_POSTS' => sizeof($post_list)) ); @@ -1918,12 +1908,6 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) 'DISPLAY_ATTACHMENT' => $attachment) ); } - - $methods = phpbb_gen_download_links('post_id', $row['post_id'], $phpbb_root_path, $phpEx); - foreach ($methods as $method) - { - $template->assign_block_vars('postrow.dl_method', $method); - } } $current_row_number = $i; |