From 9915ed52551b9b11e2cfcadabcb758ab05c6db6b Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 15 Mar 2012 16:07:14 +0100 Subject: [PATCH 001/443] =?UTF-8?q?[ticket/8743]=20Include=20poster=C2=B4s?= =?UTF-8?q?=20name=20in=20mail=20notifications?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PHPBB3-8743 --- phpBB/includes/functions_posting.php | 6 ++++-- phpBB/language/en/email/forum_notify.txt | 2 +- phpBB/language/en/email/newtopic_notify.txt | 2 +- phpBB/language/en/email/topic_notify.txt | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index 77d92e26e2..be3aa844fe 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -1160,7 +1160,7 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id /** * User Notification */ -function user_notification($mode, $subject, $topic_title, $forum_name, $forum_id, $topic_id, $post_id) +function user_notification($mode, $subject, $topic_title, $forum_name, $forum_id, $topic_id, $post_id, $author_name = '') { global $db, $user, $config, $phpbb_root_path, $phpEx, $auth; @@ -1323,6 +1323,7 @@ function user_notification($mode, $subject, $topic_title, $forum_name, $forum_id 'USERNAME' => htmlspecialchars_decode($addr['name']), 'TOPIC_TITLE' => htmlspecialchars_decode($topic_title), 'FORUM_NAME' => htmlspecialchars_decode($forum_name), + 'AUTHOR_NAME' => htmlspecialchars_decode($author_name), 'U_FORUM' => generate_board_url() . "/viewforum.$phpEx?f=$forum_id", 'U_TOPIC' => generate_board_url() . "/viewtopic.$phpEx?f=$forum_id&t=$topic_id", @@ -2585,7 +2586,8 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u // Send Notifications if (($mode == 'reply' || $mode == 'quote' || $mode == 'post') && $post_approval) { - user_notification($mode, $subject, $data['topic_title'], $data['forum_name'], $data['forum_id'], $data['topic_id'], $data['post_id']); + $username = ($username) ? $username : $user->data['username']; + user_notification($mode, $subject, $data['topic_title'], $data['forum_name'], $data['forum_id'], $data['topic_id'], $data['post_id'], $username); } $params = $add_anchor = ''; diff --git a/phpBB/language/en/email/forum_notify.txt b/phpBB/language/en/email/forum_notify.txt index fae5a83885..490780a0a6 100644 --- a/phpBB/language/en/email/forum_notify.txt +++ b/phpBB/language/en/email/forum_notify.txt @@ -2,7 +2,7 @@ Subject: Forum post notification - "{FORUM_NAME}" Hello {USERNAME}, -You are receiving this notification because you are watching the forum, "{FORUM_NAME}" at "{SITENAME}". This forum has received a new reply to the topic "{TOPIC_TITLE}" since your last visit. You can use the following link to view the last unread reply, no more notifications will be sent until you visit the topic. +You are receiving this notification because you are watching the forum, "{FORUM_NAME}" at "{SITENAME}". This forum has received a new reply to the topic "{TOPIC_TITLE}" by {AUTHOR_NAME} since your last visit. You can use the following link to view the last unread reply, no more notifications will be sent until you visit the topic. {U_NEWEST_POST} diff --git a/phpBB/language/en/email/newtopic_notify.txt b/phpBB/language/en/email/newtopic_notify.txt index 529bbf0f8f..eda1370938 100644 --- a/phpBB/language/en/email/newtopic_notify.txt +++ b/phpBB/language/en/email/newtopic_notify.txt @@ -2,7 +2,7 @@ Subject: New topic notification - "{FORUM_NAME}" Hello {USERNAME}, -You are receiving this notification because you are watching the forum, "{FORUM_NAME}" at "{SITENAME}". This forum has received a new topic since your last visit, "{TOPIC_TITLE}". You can use the following link to view the forum, no more notifications will be sent until you visit the forum. +You are receiving this notification because you are watching the forum, "{FORUM_NAME}" at "{SITENAME}". This forum has received a new topic by {AUTHOR_NAME} since your last visit, "{TOPIC_TITLE}". You can use the following link to view the forum, no more notifications will be sent until you visit the forum. {U_FORUM} diff --git a/phpBB/language/en/email/topic_notify.txt b/phpBB/language/en/email/topic_notify.txt index 99587b28e0..fcfbcc2abd 100644 --- a/phpBB/language/en/email/topic_notify.txt +++ b/phpBB/language/en/email/topic_notify.txt @@ -2,7 +2,7 @@ Subject: Topic reply notification - "{TOPIC_TITLE}" Hello {USERNAME}, -You are receiving this notification because you are watching the topic, "{TOPIC_TITLE}" at "{SITENAME}". This topic has received a reply since your last visit. You can use the following link to view the replies made, no more notifications will be sent until you visit the topic. +You are receiving this notification because you are watching the topic, "{TOPIC_TITLE}" at "{SITENAME}". This topic has received a reply by {AUTHOR_NAME} since your last visit. You can use the following link to view the replies made, no more notifications will be sent until you visit the topic. If you want to view the newest post made since your last visit, click the following link: {U_NEWEST_POST} From 328d4f1820c372e6ae9ee6af60afb5e53a2f015e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adonais=20Romero=20Gonz=C3=A1lez?= Date: Thu, 5 Apr 2012 18:41:27 -0500 Subject: [PATCH 002/443] [ticket/10661] Added   to enumerated recipients (prosilver) Added missing   to enumerated recipients after IF statements to see if it is a group or not (to_recipient.IS_GROUP and bcc_recipient.ISGROUP), in posting_editor template in prosilver style. PHPBB3-10661 --- phpBB/styles/prosilver/template/posting_editor.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phpBB/styles/prosilver/template/posting_editor.html b/phpBB/styles/prosilver/template/posting_editor.html index 5f7fb8408e..fc98a95a17 100644 --- a/phpBB/styles/prosilver/template/posting_editor.html +++ b/phpBB/styles/prosilver/template/posting_editor.html @@ -17,7 +17,7 @@
- {to_recipient.NAME} {to_recipient.NAME_FULL}  + {to_recipient.NAME}{to_recipient.NAME_FULL}   
@@ -29,7 +29,7 @@
- {bcc_recipient.NAME}{bcc_recipient.NAME_FULL}  + {bcc_recipient.NAME}{bcc_recipient.NAME_FULL}   
@@ -50,7 +50,7 @@
- {to_recipient.NAME}{to_recipient.NAME_FULL}  + {to_recipient.NAME}{to_recipient.NAME_FULL}   
From 421fc8d94db1b6a89518cbcc3f3141625eefff25 Mon Sep 17 00:00:00 2001 From: Callum Macrae Date: Tue, 10 Apr 2012 11:25:06 +0100 Subject: [PATCH 003/443] [ticket/10776] Fixed errors in docs/README.html. PHPBB3-10776 --- phpBB/docs/README.html | 77 +++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/phpBB/docs/README.html b/phpBB/docs/README.html index aa60d7dd25..d54b9d920f 100644 --- a/phpBB/docs/README.html +++ b/phpBB/docs/README.html @@ -41,7 +41,7 @@ -

Thank you for downloading phpBB3. This README will guide through the basics of installation and operation of phpBB3. Please ensure you read this and the accompanying documentation fully before proceeding with the installation.

+

Thank you for downloading phpBB3. This README will guide you through the basics of installation and operation of phpBB3. Please ensure you read this and the accompanying documentation fully before proceeding with the installation.

Readme

@@ -62,12 +62,12 @@
  • Getting help with phpBB3
    1. Documentation
    2. -
    3. Community Forums
    4. +
    5. Community forums
    6. Internet Relay Chat
  • Status of this version
  • -
  • Reporting Bugs +
  • Reporting bugs
    1. Security related bugs
    @@ -91,11 +91,11 @@
    -

    Installation, update and conversion instructions can be found in the INSTALL document contained in this distribution. If you are intending to convert from a previous phpBB 2.0.x installation we highly recommend you backup any existing data before proceeding!

    +

    Installation, update and conversion instructions can be found in the INSTALL document in this directory. If you are intending on converting from a phpBB 2.0.x installation we highly recommend that you backup any existing data before proceeding!

    Users of phpBB3 Beta versions cannot directly update.

    -

    Please note that we won't support the following installation types:

    +

    Please note that we don't support the following installation types:

    • Updates from phpBB3 Beta versions to phpBB3 RC1 and higher
    • Conversions from phpBB 2.0.x to phpBB3 Beta versions
    • @@ -107,7 +107,7 @@
      • Updates from phpBB3 RC1 to the latest version
      • Conversions from phpBB 2.0.x to the latest version
      • -
      • New installations of phpBB3 - always only the latest released version
      • +
      • New installations of phpBB3 - only the latest released version
    @@ -134,33 +134,33 @@

    http://www.phpbb.com/downloads/

    -

    This is the official location for all supported language sets. If you download a package from a 3rd party site you do so with the understanding that we cannot offer support. So please, do not ask for help in these cases!

    +

    This is the official location for all supported language sets. If you download a package from a 3rd party site you do so with the understanding that we cannot offer support. Please do not ask for support if you download a language pack from a 3rd party site.

    -

    Installation of these packages is straightforward, simply download the required language pack and unarchive it into the languages/ folder. Please ensure you retain the directory structure when doing this! Once uploaded go to the Admin->System->Language Packs and install the now appeared new language pack. To install the style imageset you should download the imageset for your language and unarchive the file/s into the relevant imageset directory (styles/prosilver/imageset or styles/subsilver2/imageset), again you must retain the directory structure. Once installed the imageset will become immediately available.

    +

    Installation of these packages is straightforward; simply download the required language pack and unarchive it into the languages/ folder. Please ensure you retain the directory structure when doing this! Once uploaded go to the Admin->System->Language Packs and install the new language pack, which will have been automatically detected. To install the style imageset you should download the imageset for your language and unarchive the file/s into the relevant imageset directory (styles/prosilver/imageset or styles/subsilver2/imageset). Again, you must retain the directory structure. Once installed the imageset will immediately become available.

    If your language is not available please visit our forums where you will find a topic listing translations currently available or in preparation. This topic also gives you information should you wish to volunteer to translate a language not currently listed.

    2.ii. Styles

    -

    Although phpBB Group are rather proud of the included styles we realise that it may not be to everyones tastes. Therefore phpBB3 allows styles to be switched with relative ease. Firstly you need to locate and download a style you like. We maintain such a site at

    +

    Although phpBB Group are rather proud of the included styles we realise that it may not be to everyones tastes. Therefore phpBB3 allows other styles to be used with relative ease. First, you need to locate and download a style you like. We maintain such a site at

    http://www.phpbb.com/styles/

    -

    Please note that 3rd party styles downloaded for versions of phpBB2 will not work in phpBB3.

    +

    Please note that styles for phpBB2 will not work with phpBB3.

    -

    Once you have downloaded a style the usual next step is to unarchive (or upload the unarchived contents of) the package into your styles/ directory. You then need to visit Administration -> Styles, you should see the new style available, click install and it will become available for all your users.

    +

    Once you have downloaded a style, the next step is to unarchive (or upload the unarchived contents of) the package into your styles/ directory. You then need to visit Administration -> Styles. You should see the new style, click install and it will become available for all your users.

    -

    Please note that if you create your own style or modify existing ones, please remember to enable the "Recompile stale style components" setting within the Admin->General->Load Settings screen. This setting allows the cache to detect changes made to the style and automatically refresh it. If this setting is disabled, you will not see your changes taking effect.

    +

    Please note that if you create your own style or modify existing ones, you should enable the "Recompile stale style components" setting within the Admin->General->Load Settings screen. This setting allows the cache to detect changes made to the style and automatically refresh it. If this setting is disabled, you will not see your changes taking effect without manually refreshing the style components.

    2.iii. Modifications

    -

    Although not officially supported by phpBB Group, phpBB has a thriving modification scene. These third party modifications to the standard phpBB extend its capabilities still further and can be found at:

    +

    Although the modifications themselves are not officially supported by phpBB Group, phpBB has a thriving modification scene. These add features to phpBB, and can be found at:

    http://www.phpbb.com/mods/

    -

    Please remember that any bugs or other issues that occur after you have added any modification should NOT be reported to the bug tracker (see below). First remove the modification and see if the problem is resolved.

    +

    Please remember that any bugs or other issues that may occur as a result of installing a modification should NOT be reported to the bug tracker (see below). First remove the modification, and then see if that has fixed the problem.

    -

    Also remember that any modifications which modify the database in any way may render upgrading your forum to future versions more difficult unless we state otherwise. With all this said many users have and continue to utilise many of the mods already available with great success.

    +

    Also remember that any modifications which modify the database in any way may make upgrading your forum to future versions more difficult. However, many users have and continue to utilise many of the mods already available with great success.

    @@ -178,27 +178,27 @@
    -

    phpBB3 can seem a little daunting to new users in places, particularly with regard the permission system. The first thing you should do is check the FAQ which covers a few basic getting started questions. If you need additional help there are several places you should look.

    +

    phpBB3 can sometimes seem a little daunting to new users, particularly with regards to the permission system. The first thing you should do is check the FAQ, which covers a few basic getting started questions. If you need additional help there are several places you can find it.

    3.i. phpBB3 Documentation

    -

    A comprehensive documentation is now available online and can be accessed from the following location:

    +

    Comprehensive documentation is now available on the phpBB website:

    http://www.phpbb.com/support/documentation/3.0/

    -

    This covers everything from installation through setting permissions and managing users.

    +

    This covers everything from installation to setting permissions and managing users.

    3.ii. Community Forums

    -

    phpBB Group maintains a thriving community where a number of people have generously decided to donate their time to help support users. This site can be found at:

    +

    phpBB Group maintains a thriving community where a number of people generously donate their time to help support users. This site can be found at:

    -

    http://www.phpbb.com/

    +

    http://www.phpbb.com/community/

    -

    If you do seek help via our forums please be sure to do a Search before posting. This may well save both you and us time and allow the developer, moderator and support groups to spend more time responding to people with unknown issues and problems. Please also remember that phpBB is an entirely volunteer effort, no one receives any compensation for the time they give, this includes moderators as well as developers. So please be respectful and mindful when awaiting responses.

    +

    If you do seek help via our forums please be sure to do a search before posting to make sure; if someone has experienced the issue before, then you may find that your question has already been answered. Please remember that phpBB is entirely staffed by volunteers, no one receives any compensation for the time they give, including moderators as well as developers; please be respectful and mindful when awaiting responses and receiving support.

    3.iii Internet Relay Chat

    -

    Another place you may find help is our IRC channel. This operates on the Freenode IRC network, irc.freenode.net and the channel is #phpbb and can be accessed by any good IRC client such as mIRC, XChat, etc. Again, please do not abuse this service and be respectful of other users.

    +

    Another place you can find help is our IRC channel, which you can find on the Freenode IRC network, irc.freenode.net in #phpbb. It can be accessed by any IRC client such as mIRC, XChat, etc. Again, please do not abuse this service and be respectful of other users.

    @@ -216,13 +216,13 @@
    -

    This is the third stable release of phpBB. The 3.0.x line is essentially feature frozen, with only point releases seeing fixes for bugs and security issues, though feature alterations and minor feature additions may be done if deemed absolutely required. Our next major release will be phpBB 3.2 and the planning phase has begun (the unstable development version is 3.1). Please do not post questions asking when 3.2 will be available, no release date has been set.

    +

    This is the third stable release of phpBB. The 3.0.x line is essentially feature frozen, with releases only containing fixes for bugs and security issues, though feature alterations and minor feature additions may be done if deemed absolutely required. Our next major release will be phpBB 3.1, which is currently under development. Please do not post questions asking when any future releases will be released; they will be released when they are finished.

    -

    For those interested in the development of phpBB should keep an eye on the community forums to see how things are progressing:

    +

    Those interested in the development of phpBB should keep an eye on the forums on the development site, Area51, to see how things are progressing and to help out if you wish:

    http://area51.phpbb.com/phpBB/

    -

    Please note that this forum should NOT be used to obtain support for or ask questions about phpBB 2.0.x or phpBB 3.0.x, the main community forums are the place for this. Any such posts will be locked and go unanswered.

    +

    Please note that these forums should NOT be used to obtain support, as the main community forums are the place for this. Any such posts will be locked and go unanswered.

    @@ -240,20 +240,19 @@
    -

    The phpBB Group uses a bug tracking system to store, list and manage all reported bugs, it can be found at the location listed below. Please DO NOT post bug reports to our forums, they will be locked. In addition please DO NOT use the bug tracker for support requests. Posting such a request will only see you directed to the support forums (while taking time away from working on real bugs).

    +

    The phpBB Group uses a bug tracking system to manage all reported bugs, which can be found at the location listed below. Please DO NOT post bug reports to our forums, they will be locked. In addition please DO NOT use the bug tracker for support requests. Posting such a request will only see you directed to the support forums (while taking time away from working on real bugs).

    http://tracker.phpbb.com/

    While we very much appreciate receiving bug reports (the more reports the more stable phpBB will be) we ask you carry out a few steps before adding new entries:

      -
    • Firstly determine if your bug is reproduceable, how to determine this depends on the bug in question. Only if the bug is reproduceable it is likely to be a problem with phpBB3 (or in some way connected). If something cannot be reproduced it may turn out to have been your hosting provider working on something, a user doing something silly, etc. Bug reports for non-reproduceable events can slow down our attempts to fix real, reproduceable issues

    • -
    • Next please read or search through the existing bug reports to see if your bug (or one very similar to it) is already listed. If it is please add to that existing bug rather than creating a new duplicate entry (all this does is slow us down).

    • -
    • Check the forums (use search!) to see if people have discussed anything that sounds similar to what you are seeing. However, as noted above please DO NOT post your particular bug to the forum unless it's non-reproduceable or you are sure it's related to something you have done rather phpBB3

    • -
    • If no existing bug exists then please feel free to add it
    • +
    • First determine if your bug is reproducible. How to determine this depends on the bug in question. If the bug is reproduceable it is likely to be a problem with phpBB3 (or in some way connected). If it cannot, then it is most likely not a bug in phpBB.

    • +
    • Next please read or search through the existing bug reports to see whether we already know about the bug you found. If there is already a ticket, then please add to that existing bug rather than creating a new duplicate entry (all this does is slow us down).

    • +
    • If no existing bug exists then please add it
    -

    If you do post a new bug (i.e. one that isn't already listed in the bug tracker) firstly make sure you have logged in (your username and password are the same as for the community forums) then please include the following details:

    +

    If you do post a new bug, make sure you are logged in (your username and password are the same as for the community forums) then please include the following details in your bug report:

    • Your server type/version, e.g. Apache 1.3.28, IIS 4, Sambar, etc.
    • @@ -263,9 +262,9 @@

      The relevant database type/version is listed within the administration control panel

      -

      Please also be as detailed as you can in your report, if possible list the steps required to duplicate the problem. If you have a patch that fixes the issue, please attach it to the ticket or submit a pull request on GitHub.

      +

      Please be as detailed as you can in your report, and if possible, list the steps required to duplicate the problem. If you have a patch that fixes the issue, please attach it to the ticket or submit a pull request to our repository on GitHub.

      -

      Once a bug has been submitted you will be emailed any follow up comments added to it. Please if you are requested to supply additional information, do so! It is frustrating for us to receive bug reports, ask for additional information but get nothing. In these cases we have a policy of closing the bug, which may leave a very real problem in place. Obviously we would rather not have this situation arise.

      +

      Once a bug has been submitted you will be emailed any follow up comments added to it. If you are requested to supply additional information, please do so! It is frustrating for us to receive bug reports, ask for additional information but get nothing. If we cannot replicate the bug we may close the ticket, which could leave the bug in phpBB. Obviously we would rather not have this situation arise.

      5.i. Security related bugs

      @@ -289,11 +288,11 @@
      -

      This list is not complete but does represent those bugs which may effect users on a wider scale. Other bugs listed in the tracker have typically been shown to be limited to certain setups or methods of installation, updating and/or conversions.

      +

      This list is by no means complete but does represent those bugs which may effect users on a wider scale. Other bugs listed in the tracker have typically been shown to be limited to certain setups or methods of installation, updating and/or conversions.

        -
      • Conversions may fail to complete on large boards under some hosts
      • -
      • Updates may fail to complete on large update sets under some hosts
      • +
      • Conversions may fail to complete on large boards under some hosts.
      • +
      • Updates may fail to complete on large update sets under some hosts.
      • Smilies placed directly after bbcode tags will not get parsed. Smilies always need to be separated by spaces.
      @@ -313,9 +312,9 @@
      -

      phpBB is no longer supported on PHP3 due to several compatibility issues and we recommend that you upgrade to the latest stable release of PHP5 to run phpBB. The minimum version required is PHP 4.3.3.

      +

      phpBB is no longer supported on PHP3 due to several compatibility issues and we recommend that you upgrade to the latest stable release of PHP5 to run phpBB. The minimum version required is PHP 4.3.3. The minimum version that will be required for phpBB 3.1 is PHP 5.3.2.

      -

      Please remember that running any application on a developmental version of PHP can lead to strange/unexpected results which may appear to be bugs in the application (which may not be true). Therefore we recommend you upgrade to the newest stable version of PHP before running phpBB3. If you are running a developmental version of PHP please check any bugs you find on a system running a stable release before submitting.

      +

      Please remember that running any application on a development (unstable, e.g. a beta release) version of PHP can lead to strange/unexpected results which may appear to be bugs in the application. Therefore, we recommend you upgrade to the newest stable version of PHP before running phpBB3. If you are running a development version of PHP please check any bugs you find on a system running a stable release before submitting.

      This board has been developed and tested under Linux and Windows (amongst others) running Apache using MySQL 3.23, 4.x, 5.x, MSSQL Server 2000, PostgreSQL 7.x, Oracle 8, SQLite and Firebird. Versions of PHP used range from 4.3.3 to 6.0.0-dev without problem.

      @@ -339,7 +338,7 @@
      -

      This application is opensource software released under the GNU General Public License v2. Please see source code and the docs directory for more details. This package and its contents are Copyright (c) phpBB Group, All Rights Reserved.

      +

      This application is open source software released under the GNU General Public License v2. Please see source code and the docs directory for more details. This package and its contents are Copyright © phpBB Group, All Rights Reserved.

      From 8a2063090c382445835e64fb95ad3aebd777e146 Mon Sep 17 00:00:00 2001 From: Callum Macrae Date: Thu, 12 Apr 2012 20:53:27 +0100 Subject: [PATCH 004/443] [ticket/10776] Fixed a couple language changes in docs/README.html. PHPBB3-10776 --- phpBB/docs/README.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phpBB/docs/README.html b/phpBB/docs/README.html index d54b9d920f..0b5709a7c7 100644 --- a/phpBB/docs/README.html +++ b/phpBB/docs/README.html @@ -136,7 +136,7 @@

      This is the official location for all supported language sets. If you download a package from a 3rd party site you do so with the understanding that we cannot offer support. Please do not ask for support if you download a language pack from a 3rd party site.

      -

      Installation of these packages is straightforward; simply download the required language pack and unarchive it into the languages/ folder. Please ensure you retain the directory structure when doing this! Once uploaded go to the Admin->System->Language Packs and install the new language pack, which will have been automatically detected. To install the style imageset you should download the imageset for your language and unarchive the file/s into the relevant imageset directory (styles/prosilver/imageset or styles/subsilver2/imageset). Again, you must retain the directory structure. Once installed the imageset will immediately become available.

      +

      Installation of these packages is straightforward; simply download the required language pack and extract it into the languages/ folder. Please ensure you retain the directory structure when doing this! Once uploaded go to the Admin->System->Language Packs and install the new language pack, which will have been automatically detected. To install the style imageset you should download the imageset for your language and extract the file/s into the relevant imageset directory (styles/prosilver/imageset or styles/subsilver2/imageset). Again, you must retain the directory structure. Once installed the imageset will immediately become available.

      If your language is not available please visit our forums where you will find a topic listing translations currently available or in preparation. This topic also gives you information should you wish to volunteer to translate a language not currently listed.

      @@ -148,7 +148,7 @@

      Please note that styles for phpBB2 will not work with phpBB3.

      -

      Once you have downloaded a style, the next step is to unarchive (or upload the unarchived contents of) the package into your styles/ directory. You then need to visit Administration -> Styles. You should see the new style, click install and it will become available for all your users.

      +

      Once you have downloaded a style, the next step is to extract (or upload the extracted contents of) the package into your styles/ directory. You then need to visit Administration -> Styles. You should see the new style, click install and it will become available for all your users.

      Please note that if you create your own style or modify existing ones, you should enable the "Recompile stale style components" setting within the Admin->General->Load Settings screen. This setting allows the cache to detect changes made to the style and automatically refresh it. If this setting is disabled, you will not see your changes taking effect without manually refreshing the style components.

      @@ -194,7 +194,7 @@

      http://www.phpbb.com/community/

      -

      If you do seek help via our forums please be sure to do a search before posting to make sure; if someone has experienced the issue before, then you may find that your question has already been answered. Please remember that phpBB is entirely staffed by volunteers, no one receives any compensation for the time they give, including moderators as well as developers; please be respectful and mindful when awaiting responses and receiving support.

      +

      If you do seek help via our forums please be sure to do a search before posting; if someone has experienced the issue before, then you may find that your question has already been answered. Please remember that phpBB is entirely staffed by volunteers, no one receives any compensation for the time they give, including moderators as well as developers; please be respectful and mindful when awaiting responses and receiving support.

      3.iii Internet Relay Chat

      From a9cf558af7fc08539e15ceca1e889e087c815c8d Mon Sep 17 00:00:00 2001 From: Sajaki Date: Sat, 28 Apr 2012 10:43:43 +0200 Subject: [PATCH 005/443] [ticket/10854] sql server drop default constraint when dropping column drops default columns with T-SQL before attempting drop column to avoids sql exception. This is a huge annoyance in UMIL scripts running under sql server. --- phpBB/includes/db/db_tools.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index c6dd23e6bd..f63ff18cbe 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -1819,6 +1819,22 @@ class phpbb_db_tools case 'mssql': case 'mssqlnative': + // remove default cosntraints first + // http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx + $statements[] = "DECLARE @drop_default_name VARCHAR(100), @cmd VARCHAR(1000) + SET @drop_default_name = + (SELECT so.name FROM sysobjects so + JOIN sysconstraints sc ON so.id = sc.constid + WHERE object_name(so.parent_obj) = '{$table_name}' + AND so.xtype = 'D' + AND sc.colid = (SELECT colid FROM syscolumns + WHERE id = object_id('{$table_name}') + AND name = '{$column_name}')) + IF @drop_default_name <> '' + BEGIN + SET @cmd = 'ALTER TABLE [{$table_name}] DROP CONSTRAINT [' + @drop_default_name + ']' + EXEC(@cmd) + END"; $statements[] = 'ALTER TABLE [' . $table_name . '] DROP COLUMN [' . $column_name . ']'; break; From d578eff712b6376e3568965afec7054bff317127 Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Tue, 28 Feb 2012 06:18:24 -0600 Subject: [PATCH 006/443] [ticket/10678] Add better support for Firebird, Oracle, and MSSQL Allow ODBC connections for Firebird Capitalize fixture tables and columns for Firebird On database drop failure, drop all tables Provide cleanup utilities for databases that cannot be dropped PHPBB3-10678 --- tests/RUNNING_TESTS.txt | 19 ++++ .../phpbb_database_connection_helper.php | 24 ++++ .../phpbb_database_test_case.php | 27 +++++ ...phpbb_database_test_connection_manager.php | 106 +++++++++++++++++- 4 files changed, 171 insertions(+), 5 deletions(-) create mode 100644 tests/test_framework/phpbb_database_connection_helper.php diff --git a/tests/RUNNING_TESTS.txt b/tests/RUNNING_TESTS.txt index 59197acc0f..705fb28d07 100644 --- a/tests/RUNNING_TESTS.txt +++ b/tests/RUNNING_TESTS.txt @@ -43,6 +43,25 @@ will run phpunit with the same parameters as in the shown test_config.php file: PHPBB_TEST_DBNAME='database' PHPBB_TEST_DBUSER='user' \ PHPBB_TEST_DBPASSWD='password' phpunit +Special Database Cases +---------------------- +In order to run tests on some of the databases that we support, it will be +necessary to provide a custom DSN string in test_config.php. This is only needed for +MSSQL 2000+ (PHP module), MSSQL via ODBC, and Firebird when PDO_Firebird does not work +on your system (https://bugs.php.net/bug.php?id=61183). The variable must be named $custom_dsn. + +Examples: +Firebird using http://www.firebirdsql.org/en/odbc-driver/ +$custom_dsn = "Driver={Firebird/InterBase(r) driver};dbname=$dbhost:$dbname"; + +MSSQL +$custom_dsn = "Driver={SQL Server Native Client 10.0};Server=$dbhost;Database=$dbname"; + +The other fields in test_config.php should be filled out as you would normally to connect +to that database in phpBB. + +Additionally, you will need to be running the DbUnit fork from https://github.com/phpbb/dbunit/tree/phpbb. + Running ======= diff --git a/tests/test_framework/phpbb_database_connection_helper.php b/tests/test_framework/phpbb_database_connection_helper.php new file mode 100644 index 0000000000..e1c50655ed --- /dev/null +++ b/tests/test_framework/phpbb_database_connection_helper.php @@ -0,0 +1,24 @@ +driver = $dbms; + $this->version = (double)$version; + + parent::__construct($dsn, $user, $pass); + } +} \ No newline at end of file diff --git a/tests/test_framework/phpbb_database_test_case.php b/tests/test_framework/phpbb_database_test_case.php index e742b543b0..0e5518fef8 100644 --- a/tests/test_framework/phpbb_database_test_case.php +++ b/tests/test_framework/phpbb_database_test_case.php @@ -28,6 +28,28 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test ); } + public function createXMLDataSet($path) + { + $db_config = $this->get_database_config(); + + //Firebird requires table and column names to be uppercase + if($db_config['dbms'] == 'firebird') + { + $xml_data = file_get_contents($path); + $xml_data = preg_replace_callback('/(?:())/', 'phpbb_database_test_case::to_upper', $xml_data); + $xml_data = preg_replace_callback('/(?:())([a-z_]+)(?:(<\/column>))/', 'phpbb_database_test_case::to_upper', $xml_data); + + $temp = tmpfile(); + fwrite($temp, $xml_data); + fseek($temp, 0); + + $meta_data = stream_get_meta_data($temp); + $path = $meta_data['uri']; + } + + return parent::createXMLDataSet($path); + } + public function get_test_case_helpers() { if (!$this->test_case_helpers) @@ -106,4 +128,9 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test { return new phpbb_database_test_connection_manager($config); } + + public static function to_upper($matches) + { + return $matches[1] . strtoupper($matches[2]) . $matches[3]; + } } diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index c734c90a1a..328d90fca9 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -8,6 +8,7 @@ */ require_once dirname(__FILE__) . '/../../phpBB/includes/functions_install.php'; +require_once 'phpbb_database_connection_helper.php'; class phpbb_database_test_connection_manager { @@ -83,9 +84,37 @@ class phpbb_database_test_connection_manager break; } + //These require different connection strings on the phpBB side than they do in PDO + //so you must provide a DSN string for ODBC separately + if($this->config['dbms'] == 'mssql' || $this->config['dbms'] == 'firebird') + { + if(!empty($this->config['custom_dsn'])) + { + $dsn = 'odbc:' . $this->config['custom_dsn']; + } + } + try { - $this->pdo = new PDO($dsn, $this->config['dbuser'], $this->config['dbpasswd']); + switch($this->config['dbms']) + { + case 'mssql': + case 'mssql_odbc': + $this->pdo = new phpbb_database_connection_ODBC_PDO_wrapper('mssql', 0, $dsn, $this->config['dbuser'], $this->config['dbpasswd']); + break; + + case 'firebird': + if(!empty($this->config['custom_dsn'])) + { + $this->pdo = new phpbb_database_connection_ODBC_PDO_wrapper('firebird', 0, $dsn, $this->config['dbuser'], $this->config['dbpasswd']); + break; + } + //Fall through if they're using the firebird PDO driver and not the generic ODBC driver + + default: + $this->pdo = new PDO($dsn, $this->config['dbuser'], $this->config['dbpasswd']); + break; + } } catch (PDOException $e) { @@ -93,8 +122,7 @@ class phpbb_database_test_connection_manager throw new Exception("Unable do connect to $cleaned_dsn using PDO with error: {$e->getMessage()}"); } - // good for debug - // $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } /** @@ -125,12 +153,41 @@ class phpbb_database_test_connection_manager } break; + case 'firebird': + $this->connect(); + // Drop all of the tables + foreach ($this->get_tables() as $table) + { + $this->pdo->exec('DROP TABLE ' . $table); + } + $this->purge_extras(); + break; + + case 'oracle': + $this->connect(); + // Drop all of the tables + foreach ($this->get_tables() as $table) + { + $this->pdo->exec('DROP TABLE ' . $table . ' CASCADE CONSTRAINTS'); + } + $this->purge_extras(); + break; + default: $this->connect(false); try { $this->pdo->exec('DROP DATABASE ' . $this->config['dbname']); + + try + { + $this->pdo->exec('CREATE DATABASE ' . $this->config['dbname']); + } + catch (PDOException $e) + { + throw new Exception("Unable to re-create database: {$e->getMessage()}"); + } } catch (PDOException $e) { @@ -139,9 +196,8 @@ class phpbb_database_test_connection_manager { $this->pdo->exec('DROP TABLE ' . $table); } + $this->purge_extras(); } - - $this->pdo->exec('CREATE DATABASE ' . $this->config['dbname']); break; } } @@ -317,4 +373,44 @@ class phpbb_database_test_connection_manager throw new Exception($message); } } + + /** + * Removes extra objects from a database. This is for cases where dropping the database fails. + */ + public function purge_extras() + { + $this->ensure_connected(__METHOD__); + $queries = array(); + + switch ($this->config['dbms']) + { + case 'firebird': + $sql = 'SELECT RDB$GENERATOR_NAME + FROM RDB$GENERATORS + WHERE RDB$SYSTEM_FLAG = 0'; + $result = $this->pdo->query($sql); + + while ($row = $result->fetch(PDO::FETCH_NUM)) + { + $queries[] = 'DROP GENERATOR ' . current($row); + } + break; + + case 'oracle': + $sql = 'SELECT sequence_name + FROM USER_SEQUENCES'; + $result = $this->pdo->query($sql); + + while ($row = $result->fetch(PDO::FETCH_NUM)) + { + $queries[] = 'DROP SEQUENCE ' . current($row); + } + break; + } + + foreach($queries as $query) + { + $this->pdo->exec($query); + } + } } From 5cbe919256a0046a896a88c47b96276b6d7c05d0 Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Tue, 28 Feb 2012 13:47:15 -0600 Subject: [PATCH 007/443] [ticket/10678] Fix formatting PHPBB3-10678 --- .../phpbb_database_connection_helper.php | 10 +++++++++- tests/test_framework/phpbb_database_test_case.php | 2 +- .../phpbb_database_test_connection_manager.php | 10 +++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/tests/test_framework/phpbb_database_connection_helper.php b/tests/test_framework/phpbb_database_connection_helper.php index e1c50655ed..6ba527b5d9 100644 --- a/tests/test_framework/phpbb_database_connection_helper.php +++ b/tests/test_framework/phpbb_database_connection_helper.php @@ -1,4 +1,12 @@ get_database_config(); //Firebird requires table and column names to be uppercase - if($db_config['dbms'] == 'firebird') + if ($db_config['dbms'] == 'firebird') { $xml_data = file_get_contents($path); $xml_data = preg_replace_callback('/(?:(
      ))/', 'phpbb_database_test_case::to_upper', $xml_data); diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index 328d90fca9..6e3f602ab7 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -86,9 +86,9 @@ class phpbb_database_test_connection_manager //These require different connection strings on the phpBB side than they do in PDO //so you must provide a DSN string for ODBC separately - if($this->config['dbms'] == 'mssql' || $this->config['dbms'] == 'firebird') + if ($this->config['dbms'] == 'mssql' || $this->config['dbms'] == 'firebird') { - if(!empty($this->config['custom_dsn'])) + if (!empty($this->config['custom_dsn'])) { $dsn = 'odbc:' . $this->config['custom_dsn']; } @@ -96,7 +96,7 @@ class phpbb_database_test_connection_manager try { - switch($this->config['dbms']) + switch ($this->config['dbms']) { case 'mssql': case 'mssql_odbc': @@ -104,7 +104,7 @@ class phpbb_database_test_connection_manager break; case 'firebird': - if(!empty($this->config['custom_dsn'])) + if (!empty($this->config['custom_dsn'])) { $this->pdo = new phpbb_database_connection_ODBC_PDO_wrapper('firebird', 0, $dsn, $this->config['dbuser'], $this->config['dbpasswd']); break; @@ -408,7 +408,7 @@ class phpbb_database_test_connection_manager break; } - foreach($queries as $query) + foreach ($queries as $query) { $this->pdo->exec($query); } From 0a596c4b8c4d003d0c8af79af65cb5264e9754fe Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Sun, 4 Mar 2012 17:19:33 -0600 Subject: [PATCH 008/443] [ticket/10678] More formatting requests PHPBB3-10678 --- .../test_framework/phpbb_database_connection_helper.php | 4 ++-- .../phpbb_database_test_connection_manager.php | 9 +++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/tests/test_framework/phpbb_database_connection_helper.php b/tests/test_framework/phpbb_database_connection_helper.php index 6ba527b5d9..fbb85784f8 100644 --- a/tests/test_framework/phpbb_database_connection_helper.php +++ b/tests/test_framework/phpbb_database_connection_helper.php @@ -16,10 +16,10 @@ */ class phpbb_database_connection_ODBC_PDO_wrapper extends PDO { - //Name of the driver being used (i.e. mssql, firebird) + // Name of the driver being used (i.e. mssql, firebird) public $driver = ''; - //Version number of driver since PDO::getAttribute(PDO::ATTR_CLIENT_VERSION) is pretty useless for this + // Version number of driver since PDO::getAttribute(PDO::ATTR_CLIENT_VERSION) is pretty useless for this public $version = 0; function __construct($dbms, $version, $dsn, $user, $pass) diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index 6e3f602ab7..2334e08f78 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -8,7 +8,7 @@ */ require_once dirname(__FILE__) . '/../../phpBB/includes/functions_install.php'; -require_once 'phpbb_database_connection_helper.php'; +require_once dirname(__FILE__) . '/phpbb_database_connection_helper.php'; class phpbb_database_test_connection_manager { @@ -86,12 +86,9 @@ class phpbb_database_test_connection_manager //These require different connection strings on the phpBB side than they do in PDO //so you must provide a DSN string for ODBC separately - if ($this->config['dbms'] == 'mssql' || $this->config['dbms'] == 'firebird') + if (!empty($this->config['custom_dsn']) && ($this->config['dbms'] == 'mssql' || $this->config['dbms'] == 'firebird')) { - if (!empty($this->config['custom_dsn'])) - { - $dsn = 'odbc:' . $this->config['custom_dsn']; - } + $dsn = 'odbc:' . $this->config['custom_dsn']; } try From 9bb2785da0c84bcc4a95f737b7da14c58c5d4380 Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Mon, 2 Apr 2012 05:57:48 -0500 Subject: [PATCH 009/443] [ticket/10678] More formatting and docblocks PHPBB3-10678 --- tests/test_framework/phpbb_database_test_case.php | 10 +++++++++- .../phpbb_database_test_connection_manager.php | 6 +++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/test_framework/phpbb_database_test_case.php b/tests/test_framework/phpbb_database_test_case.php index b8be6a852a..53c3702aa6 100644 --- a/tests/test_framework/phpbb_database_test_case.php +++ b/tests/test_framework/phpbb_database_test_case.php @@ -32,7 +32,7 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test { $db_config = $this->get_database_config(); - //Firebird requires table and column names to be uppercase + // Firebird requires table and column names to be uppercase if ($db_config['dbms'] == 'firebird') { $xml_data = file_get_contents($path); @@ -129,6 +129,14 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test return new phpbb_database_test_connection_manager($config); } + /** + * Converts a match in the middle of a string to uppercase. + * This is necessary for tranforming the fixture information for Firebird tests + * + * @param $matches The array of matches from a regular expression + * + * @return string The string with the specified match converted to uppercase + */ public static function to_upper($matches) { return $matches[1] . strtoupper($matches[2]) . $matches[3]; diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index 2334e08f78..3c4a112d0d 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -84,8 +84,8 @@ class phpbb_database_test_connection_manager break; } - //These require different connection strings on the phpBB side than they do in PDO - //so you must provide a DSN string for ODBC separately + // These require different connection strings on the phpBB side than they do in PDO + // so you must provide a DSN string for ODBC separately if (!empty($this->config['custom_dsn']) && ($this->config['dbms'] == 'mssql' || $this->config['dbms'] == 'firebird')) { $dsn = 'odbc:' . $this->config['custom_dsn']; @@ -106,7 +106,7 @@ class phpbb_database_test_connection_manager $this->pdo = new phpbb_database_connection_ODBC_PDO_wrapper('firebird', 0, $dsn, $this->config['dbuser'], $this->config['dbpasswd']); break; } - //Fall through if they're using the firebird PDO driver and not the generic ODBC driver + // Fall through if they're using the firebird PDO driver and not the generic ODBC driver default: $this->pdo = new PDO($dsn, $this->config['dbuser'], $this->config['dbpasswd']); From ceacb63abfdc8144ce88c0d9ce763ccc74836be5 Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Thu, 12 Apr 2012 20:10:20 -0500 Subject: [PATCH 010/443] [ticket/10678] Lowercase class name, adjust comment width PHPBB3-10678 --- tests/RUNNING_TESTS.txt | 26 +++++++++++-------- .../phpbb_database_connection_helper.php | 2 +- ...phpbb_database_test_connection_manager.php | 4 +-- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/tests/RUNNING_TESTS.txt b/tests/RUNNING_TESTS.txt index 705fb28d07..487320f736 100644 --- a/tests/RUNNING_TESTS.txt +++ b/tests/RUNNING_TESTS.txt @@ -36,8 +36,9 @@ found on the wiki (see below). $dbuser = 'user'; $dbpasswd = 'password'; -Alternatively you can specify parameters in the environment, so e.g. the following -will run phpunit with the same parameters as in the shown test_config.php file: +Alternatively you can specify parameters in the environment, so e.g. the +following will run phpunit with the same parameters as in the shown +test_config.php file: $ PHPBB_TEST_DBMS='mysqli' PHPBB_TEST_DBHOST='localhost' \ PHPBB_TEST_DBNAME='database' PHPBB_TEST_DBUSER='user' \ @@ -46,9 +47,10 @@ will run phpunit with the same parameters as in the shown test_config.php file: Special Database Cases ---------------------- In order to run tests on some of the databases that we support, it will be -necessary to provide a custom DSN string in test_config.php. This is only needed for -MSSQL 2000+ (PHP module), MSSQL via ODBC, and Firebird when PDO_Firebird does not work -on your system (https://bugs.php.net/bug.php?id=61183). The variable must be named $custom_dsn. +necessary to provide a custom DSN string in test_config.php. This is only +needed for MSSQL 2000+ (PHP module), MSSQL via ODBC, and Firebird when +PDO_Firebird does not work on your system +(https://bugs.php.net/bug.php?id=61183). The variable must be named $custom_dsn. Examples: Firebird using http://www.firebirdsql.org/en/odbc-driver/ @@ -57,15 +59,17 @@ $custom_dsn = "Driver={Firebird/InterBase(r) driver};dbname=$dbhost:$dbname"; MSSQL $custom_dsn = "Driver={SQL Server Native Client 10.0};Server=$dbhost;Database=$dbname"; -The other fields in test_config.php should be filled out as you would normally to connect -to that database in phpBB. +The other fields in test_config.php should be filled out as you would normally +to connect to that database in phpBB. -Additionally, you will need to be running the DbUnit fork from https://github.com/phpbb/dbunit/tree/phpbb. +Additionally, you will need to be running the DbUnit fork from +https://github.com/phpbb/dbunit/tree/phpbb. Running ======= -Once the prerequisites are installed, run the tests from the project root directory (above phpBB): +Once the prerequisites are installed, run the tests from the project root +directory (above phpBB): $ phpunit @@ -73,8 +77,8 @@ Slow tests -------------- Certain tests, such as the UTF-8 normalizer or the DNS tests tend to be slow. Thus these tests are in the `slow` group, which is excluded by default. You can -enable slow tests by copying the phpunit.xml.all file to phpunit.xml. If you only -want the slow tests, run: +enable slow tests by copying the phpunit.xml.all file to phpunit.xml. If you +only want the slow tests, run: $ phpunit --group slow diff --git a/tests/test_framework/phpbb_database_connection_helper.php b/tests/test_framework/phpbb_database_connection_helper.php index fbb85784f8..5eba2e7a2e 100644 --- a/tests/test_framework/phpbb_database_connection_helper.php +++ b/tests/test_framework/phpbb_database_connection_helper.php @@ -14,7 +14,7 @@ * * This is used in the custom PHPUnit ODBC driver */ -class phpbb_database_connection_ODBC_PDO_wrapper extends PDO +class phpbb_database_connection_odbc_pdo_wrapper extends PDO { // Name of the driver being used (i.e. mssql, firebird) public $driver = ''; diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index 3c4a112d0d..8e214121f3 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -97,13 +97,13 @@ class phpbb_database_test_connection_manager { case 'mssql': case 'mssql_odbc': - $this->pdo = new phpbb_database_connection_ODBC_PDO_wrapper('mssql', 0, $dsn, $this->config['dbuser'], $this->config['dbpasswd']); + $this->pdo = new phpbb_database_connection_odbc_pdo_wrapper('mssql', 0, $dsn, $this->config['dbuser'], $this->config['dbpasswd']); break; case 'firebird': if (!empty($this->config['custom_dsn'])) { - $this->pdo = new phpbb_database_connection_ODBC_PDO_wrapper('firebird', 0, $dsn, $this->config['dbuser'], $this->config['dbpasswd']); + $this->pdo = new phpbb_database_connection_odbc_pdo_wrapper('firebird', 0, $dsn, $this->config['dbuser'], $this->config['dbpasswd']); break; } // Fall through if they're using the firebird PDO driver and not the generic ODBC driver From 3cdcd44c4b056211f3e3291a4e58beddbb81e25d Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Fri, 13 Apr 2012 01:40:55 -0500 Subject: [PATCH 011/443] [ticket/10678] Rename helper class file PHPBB3-10678 --- ...elper.php => phpbb_database_connection_odbc_pdo_wrapper.php} | 0 tests/test_framework/phpbb_database_test_connection_manager.php | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/test_framework/{phpbb_database_connection_helper.php => phpbb_database_connection_odbc_pdo_wrapper.php} (100%) diff --git a/tests/test_framework/phpbb_database_connection_helper.php b/tests/test_framework/phpbb_database_connection_odbc_pdo_wrapper.php similarity index 100% rename from tests/test_framework/phpbb_database_connection_helper.php rename to tests/test_framework/phpbb_database_connection_odbc_pdo_wrapper.php diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index 8e214121f3..0335c0de36 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -8,7 +8,7 @@ */ require_once dirname(__FILE__) . '/../../phpBB/includes/functions_install.php'; -require_once dirname(__FILE__) . '/phpbb_database_connection_helper.php'; +require_once dirname(__FILE__) . '/phpbb_database_connection_odbc_pdo_wrapper.php'; class phpbb_database_test_connection_manager { From 711d09633a17ef40e9efe67433f2285fa11f0608 Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Tue, 8 May 2012 04:34:19 -0500 Subject: [PATCH 012/443] [ticket/10678] Move config changes to new location PHPBB3-10678 --- tests/test_framework/phpbb_test_case_helpers.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_framework/phpbb_test_case_helpers.php b/tests/test_framework/phpbb_test_case_helpers.php index b46c36efaa..3622fb1b1a 100644 --- a/tests/test_framework/phpbb_test_case_helpers.php +++ b/tests/test_framework/phpbb_test_case_helpers.php @@ -69,6 +69,7 @@ class phpbb_test_case_helpers 'dbname' => $dbname, 'dbuser' => $dbuser, 'dbpasswd' => $dbpasswd, + 'custom_dsn' => isset($custom_dsn) ? $custom_dsn : '', )); if (isset($phpbb_functional_url)) @@ -85,7 +86,8 @@ class phpbb_test_case_helpers 'dbport' => isset($_SERVER['PHPBB_TEST_DBPORT']) ? $_SERVER['PHPBB_TEST_DBPORT'] : '', 'dbname' => isset($_SERVER['PHPBB_TEST_DBNAME']) ? $_SERVER['PHPBB_TEST_DBNAME'] : '', 'dbuser' => isset($_SERVER['PHPBB_TEST_DBUSER']) ? $_SERVER['PHPBB_TEST_DBUSER'] : '', - 'dbpasswd' => isset($_SERVER['PHPBB_TEST_DBPASSWD']) ? $_SERVER['PHPBB_TEST_DBPASSWD'] : '' + 'dbpasswd' => isset($_SERVER['PHPBB_TEST_DBPASSWD']) ? $_SERVER['PHPBB_TEST_DBPASSWD'] : '', + 'custom_dsn' => isset($_SERVER['PHPBB_TEST_CUSTOM_DSN']) ? $_SERVER['PHPBB_TEST_CUSTOM_DSN'] : '', )); } From 1496a4198a930e3f9412f6beb6c0307ddeeb6dda Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Tue, 8 May 2012 04:35:47 -0500 Subject: [PATCH 013/443] [ticket/10678] Add port handling for MSSQL tests PHPBB3-10678 --- .../phpbb_database_test_connection_manager.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index 0335c0de36..2e93b6799c 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -63,6 +63,13 @@ class phpbb_database_test_connection_manager // e.g. Driver={SQL Server Native Client 10.0};Server=(local)\SQLExpress; $dsn .= $this->config['dbhost']; + // Primarily for MSSQL Native/Azure as ODBC needs it in $dbhost, attached to the Server param + if ($this->config['dbport']) + { + $port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':'; + $dsn .= $port_delimiter . $this->config['dbport']; + } + if ($use_db) { $dsn .= ';Database=' . $this->config['dbname']; From 29b36b214a809b6ae49f941a4e3965ffba2b8741 Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Sun, 13 May 2012 16:56:07 -0500 Subject: [PATCH 014/443] [ticket/10678] Typo and formatting PHPBB3-10678 --- .../phpbb_database_connection_odbc_pdo_wrapper.php | 2 +- tests/test_framework/phpbb_database_test_case.php | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_framework/phpbb_database_connection_odbc_pdo_wrapper.php b/tests/test_framework/phpbb_database_connection_odbc_pdo_wrapper.php index 5eba2e7a2e..cb5956be9f 100644 --- a/tests/test_framework/phpbb_database_connection_odbc_pdo_wrapper.php +++ b/tests/test_framework/phpbb_database_connection_odbc_pdo_wrapper.php @@ -25,7 +25,7 @@ class phpbb_database_connection_odbc_pdo_wrapper extends PDO function __construct($dbms, $version, $dsn, $user, $pass) { $this->driver = $dbms; - $this->version = (double)$version; + $this->version = (double) $version; parent::__construct($dsn, $user, $pass); } diff --git a/tests/test_framework/phpbb_database_test_case.php b/tests/test_framework/phpbb_database_test_case.php index 53c3702aa6..bb86df0ef0 100644 --- a/tests/test_framework/phpbb_database_test_case.php +++ b/tests/test_framework/phpbb_database_test_case.php @@ -39,11 +39,11 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test $xml_data = preg_replace_callback('/(?:(
      ))/', 'phpbb_database_test_case::to_upper', $xml_data); $xml_data = preg_replace_callback('/(?:())([a-z_]+)(?:(<\/column>))/', 'phpbb_database_test_case::to_upper', $xml_data); - $temp = tmpfile(); - fwrite($temp, $xml_data); - fseek($temp, 0); + $new_fixture = tmpfile(); + fwrite($new_fixture, $xml_data); + fseek($new_fixture, 0); - $meta_data = stream_get_meta_data($temp); + $meta_data = stream_get_meta_data($new_fixture); $path = $meta_data['uri']; } @@ -131,7 +131,7 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test /** * Converts a match in the middle of a string to uppercase. - * This is necessary for tranforming the fixture information for Firebird tests + * This is necessary for transforming the fixture information for Firebird tests * * @param $matches The array of matches from a regular expression * From 9fa7ab62ad45abf3a5035cc792748893d6cd8a4d Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Mon, 21 May 2012 23:02:12 -0400 Subject: [PATCH 015/443] [ticket/10828] Connect to postgres database by default. When not connecting to a specific database, connect to postgres database which specifically exists as a default database to connect to. PHPBB3-10828 --- .../phpbb_database_test_connection_manager.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index c734c90a1a..ae21be6c34 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -80,6 +80,21 @@ class phpbb_database_test_connection_manager { $dsn .= ';dbname=' . $this->config['dbname']; } + else if ($this->dbms['PDO'] == 'pgsql') + { + // Postgres always connects to a + // database. If the database is not + // specified here, but the username + // is specified, then connection + // will be to the database named + // as the username. + // + // For greater compatibility, connect + // instead to postgres database which + // should always exist: + // http://www.postgresql.org/docs/9.0/static/manage-ag-templatedbs.html + $dsn .= ';dbname=postgres'; + } break; } From af3a730d9193307d908c3bd14329761cf2bbc098 Mon Sep 17 00:00:00 2001 From: Vinny Date: Wed, 11 Apr 2012 17:15:39 -0300 Subject: [PATCH 016/443] [ticket/10789] Remove unnecessary variables from PM print - prosilver PHPBB3-10789 --- .../styles/prosilver/template/ucp_pm_viewmessage_print.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html b/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html index ce2a376768..d92abb06dd 100644 --- a/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html +++ b/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html @@ -23,10 +23,9 @@
      From 118c5d90daa783ff55319e6121c0fc77166fe58c Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Thu, 31 May 2012 22:07:34 +0200 Subject: [PATCH 017/443] [develop-olympus] Incrementing the version to 3.0.12-dev in develop-olympus. --- phpBB/includes/constants.php | 2 +- phpBB/install/database_update.php | 2 +- phpBB/install/schemas/schema_data.sql | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index 5b72d89795..17c25ee3c6 100644 --- a/phpBB/includes/constants.php +++ b/phpBB/includes/constants.php @@ -25,7 +25,7 @@ if (!defined('IN_PHPBB')) */ // phpBB Version -define('PHPBB_VERSION', '3.0.11-RC1'); +define('PHPBB_VERSION', '3.0.12-dev'); // QA-related // define('PHPBB_QA', 1); diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index c1fe144c62..a52a329f20 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -8,7 +8,7 @@ * */ -define('UPDATES_TO_VERSION', '3.0.11-RC1'); +define('UPDATES_TO_VERSION', '3.0.12-dev'); // Enter any version to update from to test updates. The version within the db will not be updated. define('DEBUG_FROM_VERSION', false); diff --git a/phpBB/install/schemas/schema_data.sql b/phpBB/install/schemas/schema_data.sql index 99b8f7f96d..b139857d28 100644 --- a/phpBB/install/schemas/schema_data.sql +++ b/phpBB/install/schemas/schema_data.sql @@ -246,7 +246,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('topics_per_page', 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 ('version', '3.0.11-RC1'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('version', '3.0.12-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'); From fd2ab22556a6dca0c2e0ad01765639ef49ba438b Mon Sep 17 00:00:00 2001 From: Oyabun1 Date: Tue, 19 Jun 2012 04:36:27 -0500 Subject: [PATCH 018/443] [ticket/10865] Updates and additions to /docs/INSTALL.html Added anti-spam section. Changed www.mydomain.com/tld to www.example.com. Updated update section to mention third party styles. Reworded several sentences for clarity. Made file name/path formatting more consistent. Corrected update archive type availabilities. Changed PHP version listing to be less redundant. PHPBB3-10865 PHPBB3-10918 --- phpBB/docs/INSTALL.html | 81 +++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/phpBB/docs/INSTALL.html b/phpBB/docs/INSTALL.html index e17f496c56..9f030707f1 100644 --- a/phpBB/docs/INSTALL.html +++ b/phpBB/docs/INSTALL.html @@ -62,7 +62,7 @@
    • Updating from stable releases of phpBB 3.0.x
      1. Full package
      2. -
      3. Changed files only
      4. +
      5. Changed files
      6. Patch file
      7. Automatic update package
      8. All package types
      9. @@ -82,6 +82,7 @@
      10. Webserver configuration
    • +
    • Anti-Spam Measures
    • Copyright and disclaimer
    • @@ -107,10 +108,10 @@
    • Change the permissions on config.php to be writable by all (666 or -rw-rw-rw- within your FTP Client)
    • Change the permissions on the following directories to be writable by all (777 or -rwxrwxrwx within your FTP Client):
      store/, cache/, files/ and images/avatars/upload/.
    • -
    • Using your web browser visit the location you placed phpBB3 with the addition of install/index.php or pointing directly to install/, e.g. http://www.mydomain.com/phpBB3/install/, http://www.mydomain.com/forum/install/ etc.
    • -
    • Click the INSTALL tab, follow the steps and fill out all the requested information.
    • +
    • Using your web browser visit the location you placed phpBB3 with the addition of install/index.php or pointing directly to install/, e.g. http://www.example.com/phpBB3/install/, http://www.example.com/forum/install/.
    • +
    • Click the INSTALL tab, follow the steps and fill out all the requested information.
    • Change the permissions on config.php to be writable only by yourself (644 or -rw-r--r-- within your FTP Client)
    • -
    • phpBB3 should now be available, please MAKE SURE you read at least Section 6 below for important, security related post-installation instructions.
    • +
    • phpBB3 should now be available, please MAKE SURE you read at least Section 6 below for important, security related post-installation instructions, and also take note of Section 7 regarding anti-spam measures.
    • If you experienced problems or do not know how to proceed with any of the steps above please read the rest of this document.

      @@ -131,7 +132,7 @@
      -

      phpBB3 has a few requirements which must be met before you are able to install and use it.

      +

      phpBB 3.0.x has a few requirements which must be met before you are able to install and use it.

      • A webserver or web hosting account running on any major Operating System with support for PHP
      • @@ -145,7 +146,7 @@
      • Oracle
      -
    • PHP 4.3.3+ (>=4.3.3, >=4.4.x, >=5.x.x, >=5.4.x) with support for the database you intend to use.
    • +
    • PHP (>=4.3.3, >=4.4.0, >=5.0.0) with support for the database you intend to use.
    • getimagesize() function need to be enabled.
    • Presence of the following modules within PHP will provide access to additional features, but they are not required:
        @@ -158,7 +159,7 @@
      -

      If your server or hosting account does not meet the requirements above we are afraid phpBB3 is not for you.

      +

      If your server or hosting account does not meet the requirements above then phpBB 3.0.x is not for you.

    • @@ -184,11 +185,11 @@

      phpBB3 comes supplied with British English as its standard language. However a number of separate packs for different languages are available. If you are not a native English speaker you may wish to install one or more of these packages before continuing. The installation process below will allow you to select a default language from those available (you can of course change this default at a later stage). For more details of language packs, where to obtain them and how to install them please see the README.

      -

      Once all the files have been uploaded to your site you should point your browser at this location with the addition of install/. For example if your domain name is www.mydomain.tld and you placed phpBB3 in a directory /phpBB3 off your web root you would enter http://www.mydomain.tld/phpBB3/install/ or (alternatively) http://www.mydomain.tld/phpBB3/install/index.php into your browser. When you have done this you should see the phpBB3 Installation screen appear.

      +

      Once all the files have been uploaded to your site you should point your browser at this location with the addition of /install/. For example, if your domain name is www.example.com and you placed phpBB3 in a directory /phpBB3 off your web root you would enter http://www.example.com/phpBB3/install/ or (alternatively) http://www.example.com/phpBB3/install/index.php into your browser. When you have done this you should see the phpBB3 Introduction screen appear.

      Introduction:

      -

      The installation screen gives you a short introduction into phpBB. It allows you to read the license phpBB3 is released under (General Public License) and provides information about how you can receive support. To start the installation, use the Install button.

      +

      The initial screen gives you a short introduction into phpBB. It allows you to read the license phpBB3 is released under (General Public License v2) and provides information about how you can receive support. To start the installation, use the INSTALL tab.

      Requirements

      @@ -228,13 +229,13 @@

      In this step, phpBB will try to write the configuration file automatically. The forum needs the configuration to run properly. It contains all database settings, so without it, phpBB will not be able to access the database.

      -

      Usually writing the configuration file automatically works fine. But in some cases it can fail due to wrong file permissions, for instance. In this case, you need to upload the file manually. phpBB asks you to download the config.php file and tells you what to do with it. Please read the instructions carefully. After you have uploaded the file, use Done to get to the last step. If Done returns you to the same page as before, and does not return a success message, you did not upload the file correctly.

      +

      Usually writing the configuration file automatically works fine. But in some cases it can fail due to wrong file permissions, for instance. In this case, you need to upload the file manually. phpBB asks you to download the config.php file and tells you what to do with it. Please read the instructions carefully. After you have uploaded the file, use Done to get to the last step. If Done returns you to the same page as before, and does not return a success message, you did not upload the file correctly.

      Advanced settings

      -

      The Advanced settings allow you to set some parameters of the board configuration. They are optional, and you can always change them later. So if you are not sure what these settings mean, proceed to the final step and finish the installation.

      +

      The Advanced settings allow you to set some parameters of the board configuration. They are optional and you can always change them later. So, even if you are not sure what these settings mean you can still proceed to the final step and finish the installation.

      -

      If the installation was successful, you can now use the Login button to visit the Administration Control Panel. Congratulations, you have installed phpBB3 successfully. But there is still work ahead!

      +

      If the installation was successful, you can now use the Login button to visit the Administration Control Panel. Congratulations, you have installed phpBB successfully. But there is still work ahead!

      If you are unable to get phpBB3 installed even after reading this guide, please look at the support section to find out where you can ask for further assistance.

      @@ -264,19 +265,19 @@

      The full package is normally meant for new installations only, but if you want to replace all source files this package comes in handy.

      -

      First you should make a copy of your existing config.php file, keep it in a safe place! Next delete all the existing phpBB3 files, you may want to leave your files/ and images/ directory in place. You can leave alternative styles in-place too. With this complete you can upload the new phpBB3 files (see New installation for details if necessary). Once complete copy back your saved config.php, replacing the new one. Another method is to just replace the existing files with the files from the full package - though make sure you do not overwrite your config.php file.

      +

      First you should make a copy of your existing config.php file, keep it in a safe place! Next delete all the existing phpBB3 files, you may want to leave your files/ and images/ directory in place. You can leave alternative styles in-place too. With this complete you can upload the new phpBB files (see New installation for details if necessary). Once complete copy back your saved config.php, replacing the new one. Another method is to just replace the existing files with the files from the full package - though make sure you do not overwrite your config.php file.

      You should now run install/database_update.php which, depending on your previous version, will make a number of database changes. You may receive FAILURES during this procedure, they should not be a cause for concern unless you see an actual ERROR, in which case the script will stop (in this case you should seek help via our forums or bug tracker).

      Once the install/database_update.php has completed you may proceed to the Administration Control Panel and check remove the install directory as advised.

      -

      4.ii. Changed files only

      +

      4.ii. Changed files

      This package is meant for those wanting to only replace changed files from a previous version to the latest version. This package normally contains the changed files from up to five previous versions.

      -

      This package contains a number of archives, each contains the files changed from a given release to the latest version. You should select the appropriate archive for your current version, e.g. if you currently have 3.0.10 you should select the phpBB-3.0.10_to_3.0.11.zip/tar.gz file.

      +

      This package contains a number of archives, each contains the files changed from a given release to the latest version. You should select the appropriate archive for your current version, e.g. if you currently have 3.0.10 you should select the appropriate phpBB-3.0.11-files.zip/tar.bz2 file.

      -

      The directory structure has been preserved enabling you (if you wish) to simply upload the contents of the archive to the appropriate location on your server, i.e. simply overwrite the existing files with the new versions. Do not forget that if you have installed any MODs these files will overwrite the originals possibly destroying them in the process. You will need to re-add MODs to any affected file before uploading.

      +

      The directory structure has been preserved enabling you (if you wish) to simply upload the uncompressed contents of the archive to the appropriate location on your server, i.e. simply overwrite the existing files with the new versions. Do not forget that if you have installed any MODs these files will overwrite the originals possibly destroying them in the process. You will need to re-add MODs to any affected file before uploading.

      As for the other update procedures you should run install/database_update.php after you have finished updating the files. This will update your database schema and increment the version number.

      @@ -286,9 +287,9 @@

      The patch file is one solution for those with many Modifications (MODs) or other changes who do not want to re-add them back to all the changed files if they use the method explained above. To use this you will need command line access to a standard UNIX type patch application. If you do not have access to such an application but still want to use this update approach, we strongly recommend the Automatic update package explained below. It is also the recommended update method.

      -

      A number of patch files are provided to allow you to update from previous stable releases. Select the correct patch, e.g. if your current version is 3.0.10 you need the phpBB-3.0.10_to_3.0.11.patch file. Place the correct patch in the parent directory containing the phpBB3 core files (i.e. index.php, viewforum.php, etc.). With this done you should run the following command: patch -cl -d [PHPBB DIRECTORY] -p1 < [PATCH NAME] (where PHPBB DIRECTORY is the directory name your phpBB Installation resides in, for example phpBB3, and where PATCH NAME is the relevant filename of the selected patch file). This should complete quickly, hopefully without any HUNK FAILED comments.

      +

      A number of patch files are provided to allow you to update from previous stable releases. Select the correct patch, e.g. if your current version is 3.0.10 you need the phpBB-3.0.11-patch.zip/tar.bz2 file. Place the correct patch in the parent directory containing the phpBB core files (i.e. index.php, viewforum.php, etc.). With this done you should run the following command: patch -cl -d [PHPBB DIRECTORY] -p1 < [PATCH NAME] (where PHPBB DIRECTORY is the directory name your phpBB Installation resides in, for example phpBB, and where PATCH NAME is the relevant filename of the selected patch file). This should complete quickly, hopefully without any HUNK FAILED comments.

      -

      If you do get failures you should look at using the Changed files only package to replace the files which failed to patch, please note that you will need to manually re-add any Modifications (MODs) to these particular files. Alternatively if you know how you can examine the .rej files to determine what failed where and make manual adjustments to the relevant source.

      +

      If you do get failures you should look at using the Changed Files package to replace the files which failed to patch, please note that you will need to manually re-add any Modifications (MODs) to these particular files. Alternatively if you know how you can examine the .rej files to determine what failed where and make manual adjustments to the relevant source.

      You should of course delete the patch file (or files) after use. As for the other update procedures you should run install/database_update.php after you have finished updating the files. This will update your database schema and data (if appropriate) and increment the version number.

      @@ -298,13 +299,13 @@

      The automatic update package contains - contrary to the others - only the information required to update the previous release version to the latest available version. These packages are meant for use with the automatic update tool.

      -

      To perform the update, either follow the instructions from the Administration Control Panel->System Tab - this should point out that you are running an outdated version and will guide you through the update - or follow the instructions listed below.

      +

      To perform the update, either follow the instructions from the Administration Control Panel->System Tab - this should point out that you are running an outdated version and will guide you through the update - or follow the instructions listed below.

      • Go to the downloads page and download the latest update package listed there, matching your current version.
      • -
      • Upload the archives contents to your phpBB installation - only the install folder is required. Upload the whole install folder, retaining the file structure.
      • +
      • Upload the uncompressed archive contents to your phpBB installation - only the install folder is required. Upload the whole install folder, retaining the file structure.
      • After the install folder is present, phpBB3 will go offline automatically.
      • -
      • Point your browser to the install directory, for example http://www.example.com/phpBB3/install/
      • +
      • Point your browser to the install directory, for example http://www.example.com/phpBB3/install/
      • Choose the "Update" Tab and follow the instructions
      @@ -314,6 +315,8 @@

      If you have non-English language packs installed you may want to see if a new version has been made available. A number of missing strings may have been added which, though not essential, may be beneficial to users. Please note that at this time not all language packs have been updated so you should be prepared to periodically check for updates.

      +

      These update methods will only update the standard styles, prosilver and subsilver2, any other styles you have installed for your board will usually also need to be updated.

      +
      @@ -344,7 +347,7 @@

      To begin the conversion visit the install folder of your phpBB3 installation (the same as you have done for installing). Now you will see a new tab Convert. Click this tab.

      -

      As with install the conversion is automated. Your previous 2.0.x database tables will not be changed as well as the original 2.0.x files remaining unaltered. The conversion is actually only filling your phpBB3 database tables and copying additional data over to your phpBB3 installation. This has the benefit that if something goes wrong you are able to either re-run the conversion or continue a conversion, while your old board is still accessible. We really recommend you disable your old installation while converting, else you may have inconsistent data after the conversion.

      +

      As with install, the conversion is automated. Your previous 2.0.x database tables will not be changed as well as the original 2.0.x files remaining unaltered. The conversion is actually only filling your phpBB3 database tables and copying additional data over to your phpBB3 installation. This has the benefit that if something goes wrong you are able to either re-run the conversion or continue a conversion, while your old board is still accessible. We really recommend you disable your old installation while converting, else you may have inconsistent data after the conversion.

      Please note that this conversion process may take quite some time and depending on your hosting provider this may result in it failing (due to web server or other timeout issues). If this is the case you should ask your provider if they are willing to allow the convert script to temporarily exceed their limits (be nice and they will probably be quite helpful).

      @@ -356,21 +359,21 @@

      The first thing you may want to do is going to the administration control panel and checking every configuration item within the general tab. Thereafter you may want to adjust the forum descriptions/names if you entered HTML there. You also may want to access the other administrative sections, e.g. adjusting permissions, smilies, icons, ranks, etc.

      -

      Within the conversion the search index has not been created or transferred. This means after conversion you are not able to find any matches if you want to search for something. We recommend you rebuild your search index within Admin -> Maintenance -> Database -> Search Index.

      +

      Within the conversion the search index has not been created or transferred. This means after conversion you are not able to find any matches if you want to search for something. We recommend you rebuild your search index within Admin -> Maintenance -> Database -> Search Index.

      After verifying the settings in the ACP, you can delete the install directory to enable the board. The board will stay disabled until you do so.

      -

      Once you are pleased with your new installation you may want to give it the name of your old installation, changing the directory name. With phpBB3 this is possible without any problems - but you may still want to check your cookie settings within the administration panel, if the cookie path need to be adjusted prior to renaming.

      +

      Once you are pleased with your new installation you may want to give it the name of your old installation, changing the directory name. With phpBB3 this is possible without any problems - but you may still want to check your cookie settings within the administration panel, if the cookie path needs to be adjusted prior to renaming.

      5.iv. Common conversion problems

      Broken non-latin characters The conversion script assumes that the database encoding in the source phpBB2 matches the encoding defined in the lang_main.php file of the default language pack of the source installation. Edit that file to match the database's encoding and re-start the conversion procedure.

      -

      http 500 / white pages The conversion is a load-heavy procedure. Restrictions imposed by some server hosting providers can cause problems. The most common causes are: too low values for the php settings memory_limit and max_execution_time. Limits on the allowed CPU time are also a frequent cause for such errors, as are caps on the number of database queries allowed. If you cannot change such settings, then contact your hosting provider or run the conversion procedure on a different computer. The phpBB.com forums are also an excellent location to ask for support.

      +

      http 500 / white pages The conversion is a load-heavy procedure. Restrictions imposed by some server hosting providers can cause problems. The most common causes are: values too low for the PHP settings memory_limit and max_execution_time. Limits on the allowed CPU time are also a frequent cause for such errors, as are limits on the number of database queries allowed. If you cannot change such settings, then contact your hosting provider or run the conversion procedure on a different computer. The phpBB.com forums are also an excellent location to ask for support.

      Password conversion Due to the utf-8 based handling of passwords in phpBB3, it is not always possible to transfer all passwords. For passwords "lost in translation" the easiest workaround is to use the "forgotten password" function.

      -

      Path to your former board The converter expects the relative path to your old board's files. So, - for instance - if the old board is located at http://www.yourdomain.com/forum and the phpBB3 installation is located at http://www.yourdomain.com/phpBB3, then the correct value would be ../forum. Note that the webserver user must be able to access the source installation's files.

      +

      Path to your former board The converter expects the relative path to your old board's files. So, for instance, if the old board is located at http://www.yourdomain.com/forum and the phpBB3 installation is located at http://www.yourdomain.com/phpBB3, then the correct value would be ../forum. Note that the webserver user must be able to access the source installation's files.

      Missing images If your default board language's language pack does not include all images, then some images might be missing in your installation. Always use a complete language pack as default language.

      @@ -393,15 +396,15 @@
      -

      Once you have successfully installed phpBB3 you MUST ensure you remove the entire install/ directory. Leaving the install directory in place is a very serious potential security issue which may lead to deletion or alteration of files, etc. Please note that until this directory is removed, phpBB3 will not operate and a warning message will be displayed. Beyond this essential deletion, you may also wish to delete the docs/ directories if you wish.

      +

      Once you have successfully installed phpBB3 you MUST ensure you remove the entire install/ directory. Leaving the install directory in place is a very serious potential security issue which may lead to deletion or alteration of files, etc. Please note that until this directory is removed, phpBB will not operate and a warning message will be displayed. Beyond this essential deletion, you may also wish to delete the docs/ directories if you wish.

      -

      With these directories deleted you should proceed to the administration panel. Depending on how the installation completed you may have been directed there automatically. If not, login as the administrator you specified during install/conversion and click the Administration Panel link at the bottom of any page. Ensure that details specified in Admin -> General are correct!

      +

      With these directories deleted you should proceed to the administration panel. Depending on how the installation completed you may have been directed there automatically. If not, login as the administrator you specified during install/conversion and click the Administration Panel link at the bottom of any page. Ensure that details specified in Admin -> General are correct!

      6.i. Uploadable avatars

      phpBB3 supports several methods for allowing users to select their own avatar (an avatar is a small image generally unique to a user and displayed just below their username in posts).

      -

      Two of these options allow users to upload an avatar from their machine or a remote location (via a URL). If you wish to enable this function you should first ensure the correct paths for uploadeable avatars is set in Admin -> General -> Board Configuration -> Avatar settings. By default this is images/avatars/uploads but you can set it to whatever you like, just ensure the configuration setting is updated. You must also ensure this directory can be written to by the webserver. Usually this means you have to alter its permissions to allow anyone to read and write to. Exactly how you should do this depends on your ftp client or server operating system.

      +

      Two of these options allow users to upload an avatar from their machine or a remote location (via a URL). If you wish to enable this function you should first ensure the correct paths for uploadeable avatars is set in Admin -> General -> Board Configuration -> Avatar settings. By default this is images/avatars/uploads but you can set it to whatever you like, just ensure the configuration setting is updated. You must also ensure this directory can be written to by the webserver. Usually this means you have to alter its permissions to allow anyone to read and write to. Exactly how you should do this depends on your ftp client or server operating system.

      On UNIX systems for example you set the directory to a+rwx (or ugo+rwx or even 777). This can be done from a command line on your server using chmod or via your FTP client (using the Change Permissions, chmod or other Permissions dialoge box, see your FTP clients documentation for help). Most FTP clients list permissions in the form of User (Read, Write, Execute), Group (Read, Write, Execute) and Other (Read, Write, Execute). You need to tick all of these boxes to set correct permissions.

      @@ -413,7 +416,7 @@

      Depending on your web server you may have to configure your server to deny web access to the cache/, files/, store/ and other directories. This is to prevent users from accessing sensitive files.

      -

      For apache there are .htaccess files already in place to do this for you. For other webservers you will have to adjust the configuration yourself. Sample files for nginx and lighttpd to help you get started may be found in docs directory.

      +

      For Apache there are .htaccess files already in place to do this for you. Similarly, for Windows based servers using .ASP.NET there are web.config files already in place to do this for you. For other webservers you will have to adjust the configuration yourself. Sample files for nginx and lighttpd to help you get started may be found in docs directory.

      @@ -424,7 +427,23 @@
      -

      7. Copyright and disclaimer

      +

      7. Anti-Spam Measures

      + +
      +
      + +
      +

      Like any online site that allows user input your board could be subject to unwanted posts, often referred to as forum spam. The vast majority of these attacks will be from automated computer computer programs known as spambots. The attacks, generally, are not personal the spammers just try to find accessible targets. phpBB has a number of anti-spam measures built in including a range of CAPTCHAs. However, administrators are strongly earged to read and follow the advice for Preventing Spam in phpBB as soon as possible after completing the installation of your board.

      +
      + + + +
      +
      + +
      + +

      8. Copyright and disclaimer

      From bbd3204a9cf15155ccbc1c9270575d2ba44097cb Mon Sep 17 00:00:00 2001 From: Dhruv Goel Date: Tue, 19 Jun 2012 20:03:57 +0530 Subject: [PATCH 019/443] [ticket/9551] uncomment line and change length to 255 incase of partial collation change post_subject field will be changed back to the default collation and length 255. PHPBB3-9551 --- phpBB/includes/search/fulltext_mysql.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/search/fulltext_mysql.php b/phpBB/includes/search/fulltext_mysql.php index 779ec1d216..bd4c003397 100644 --- a/phpBB/includes/search/fulltext_mysql.php +++ b/phpBB/includes/search/fulltext_mysql.php @@ -747,7 +747,7 @@ class fulltext_mysql extends search_backend { if ($db->sql_layer == 'mysqli' || version_compare($db->sql_server_info(true), '4.1.3', '>=')) { - //$alter[] = 'MODIFY post_subject varchar(100) COLLATE utf8_unicode_ci DEFAULT \'\' NOT NULL'; + $alter[] = 'MODIFY post_subject varchar(255) COLLATE utf8_unicode_ci DEFAULT \'\' NOT NULL'; } else { From 5bc2219bbedefd234a58f99858ce8aadca89cce4 Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Tue, 19 Jun 2012 12:51:44 -0500 Subject: [PATCH 020/443] [ticket/10865] Typo and phrasing change PHPBB3-10865 --- phpBB/docs/INSTALL.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/docs/INSTALL.html b/phpBB/docs/INSTALL.html index 9f030707f1..781fffb976 100644 --- a/phpBB/docs/INSTALL.html +++ b/phpBB/docs/INSTALL.html @@ -433,7 +433,7 @@
      -

      Like any online site that allows user input your board could be subject to unwanted posts, often referred to as forum spam. The vast majority of these attacks will be from automated computer computer programs known as spambots. The attacks, generally, are not personal the spammers just try to find accessible targets. phpBB has a number of anti-spam measures built in including a range of CAPTCHAs. However, administrators are strongly earged to read and follow the advice for Preventing Spam in phpBB as soon as possible after completing the installation of your board.

      +

      Like any online site that allows user input, your board could be subject to unwanted posts; often referred to as forum spam. The vast majority of these attacks will be from automated computer computer programs known as spambots. The attacks, generally, are not personal as the spammers are just trying to find accessible targets. phpBB has a number of anti-spam measures built in including a range of CAPTCHAs. However, administrators are strongly urged to read and follow the advice for Preventing Spam in phpBB as soon as possible after completing the installation of your board.

      From 08e319198c3b6ddf249cdc7b2d3aa8258fd6d517 Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Fri, 22 Jun 2012 23:47:13 -0500 Subject: [PATCH 021/443] [ticket/10865] Grammar corrections for the entire document Fixed more grammatical issues, changed some phrasings, added a link for offline conversions, and other corrections. PHPBB3-10865 --- phpBB/docs/INSTALL.html | 112 ++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/phpBB/docs/INSTALL.html b/phpBB/docs/INSTALL.html index 781fffb976..84b6d6bce9 100644 --- a/phpBB/docs/INSTALL.html +++ b/phpBB/docs/INSTALL.html @@ -108,7 +108,7 @@
    • Change the permissions on config.php to be writable by all (666 or -rw-rw-rw- within your FTP Client)
    • Change the permissions on the following directories to be writable by all (777 or -rwxrwxrwx within your FTP Client):
      store/, cache/, files/ and images/avatars/upload/.
    • -
    • Using your web browser visit the location you placed phpBB3 with the addition of install/index.php or pointing directly to install/, e.g. http://www.example.com/phpBB3/install/, http://www.example.com/forum/install/.
    • +
    • Using your web browser, visit the location you placed phpBB3 with the addition of install/index.php or by pointing directly to install/, e.g. http://www.example.com/phpBB3/install/, http://www.example.com/forum/install/.
    • Click the INSTALL tab, follow the steps and fill out all the requested information.
    • Change the permissions on config.php to be writable only by yourself (644 or -rw-r--r-- within your FTP Client)
    • phpBB3 should now be available, please MAKE SURE you read at least Section 6 below for important, security related post-installation instructions, and also take note of Section 7 regarding anti-spam measures.
    • @@ -147,7 +147,7 @@
    • PHP (>=4.3.3, >=4.4.0, >=5.0.0) with support for the database you intend to use.
    • -
    • getimagesize() function need to be enabled.
    • +
    • getimagesize() function must be enabled.
    • Presence of the following modules within PHP will provide access to additional features, but they are not required:
      • zlib Compression support
      • @@ -159,7 +159,7 @@
      -

      If your server or hosting account does not meet the requirements above then phpBB 3.0.x is not for you.

      +

      If your server or hosting account does not meet the requirements above then you will be unable to install phpBB 3.0.x.

    • @@ -179,13 +179,13 @@

      Installation of phpBB3 will vary according to your server and database. If you have shell access to your account (via telnet or ssh for example) you may want to upload the entire phpBB3 archive (in binary mode!) to a directory on your host and unarchive it there.

      -

      If you do not have shell access or do not wish to use it you will need to decompress the phpBB3 archive to a local directory on your system using your favourite compression program, e.g. winzip, rar, zip, etc. From there you must FTP ALL the files it contains (being sure to retain the directory structure and filenames) to your host. Please ensure that the cases of filenames are retained, do NOT force filenames to all lower or upper case doing so will cause errors later.

      +

      If you do not have shell access or do not wish to use it, you will need to decompress the phpBB3 archive to a local directory on your system using your favourite compression program, e.g. winzip, rar, zip, etc. From there you must FTP ALL the files it contains (being sure to retain the directory structure and filenames) to your host. Please ensure that the cases of filenames are retained, do NOT force filenames to all lower or upper case as doing so will cause errors later.

      -

      All .php, .inc, .sql, .cfg, .html and .txt files should be uploaded in ASCII mode, while all graphics should be uploaded in BINARY mode. If you are unfamiliar with what this means please refer to your FTP client documentation. In most cases this is all handled transparantly by your ftp client but if you encounter problems later you should be sure the files where uploaded correctly as described here.

      +

      All .php, .sql, .cfg, .html and .txt files should be uploaded in ASCII mode, while all graphics should be uploaded in BINARY mode. If you are unfamiliar with what this means please refer to your FTP client documentation. In most cases this is all handled transparantly by your ftp client, but if you encounter problems later you should be sure the files were uploaded correctly as described here.

      -

      phpBB3 comes supplied with British English as its standard language. However a number of separate packs for different languages are available. If you are not a native English speaker you may wish to install one or more of these packages before continuing. The installation process below will allow you to select a default language from those available (you can of course change this default at a later stage). For more details of language packs, where to obtain them and how to install them please see the README.

      +

      phpBB3 comes supplied with British English as its standard language. However, a number of separate packs for different languages are available. If you are not a native English speaker you may wish to install one or more of these packages before continuing. The installation process below will allow you to select a default language from those available (you can, of course, change this default at a later stage). For more details on language packs, where to obtain them and how to install them please see the README.

      -

      Once all the files have been uploaded to your site you should point your browser at this location with the addition of /install/. For example, if your domain name is www.example.com and you placed phpBB3 in a directory /phpBB3 off your web root you would enter http://www.example.com/phpBB3/install/ or (alternatively) http://www.example.com/phpBB3/install/index.php into your browser. When you have done this you should see the phpBB3 Introduction screen appear.

      +

      Once all the files have been uploaded to your site, you should point your browser at this location with the addition of /install/. For example, if your domain name is www.example.com and you placed the phpBB3 files in the directory /phpBB3 off your web root you would enter http://www.example.com/phpBB3/install/ or (alternatively) http://www.example.com/phpBB3/install/index.php into your browser. When you have done this, you should see the phpBB3 Introduction screen appear.

      Introduction:

      @@ -193,7 +193,7 @@

      Requirements

      -

      The first page you will see after starting the installation is the Requirements list. phpBB3 checks automatically whether everything that it needs to run properly is installed on your server. You need to have at least the minimum PHP version installed, and at least one database available to continue the installation. Also important, is that all shown folders are available and do have the correct permissions. Please see the description of each section to find out whether they are optional or required for phpBB3 to run. If everything is in order, you can continue the installation with Start Install.

      +

      The first page you will see after starting the installation is the Requirements list. phpBB3 automatically checks whether everything that it needs to run properly is installed on your server. You need to have at least the minimum PHP version installed, and at least one database available to continue the installation. Also important, is that all shown folders are available and have the correct permissions. Please see the description of each section to find out whether they are optional or required for phpBB3 to run. If everything is in order, you can continue the installation with Start Install.

      Database settings

      @@ -211,33 +211,33 @@

      Note: if you are installing using SQLite, you should enter the full path to your database file in the DSN field and leave the username and password fields blank. For security reasons, you should make sure that the database file is not stored in a location accessible from the web.

      -

      You don't need to change the Prefix for tables in database setting, unless you plan on using multipe phpBB installations on one database. In this case you can use a different prefix for each installation to make it work.

      +

      You don't need to change the Prefix for tables in database setting, unless you plan on using multipe phpBB installations on one database. In this case, you can use a different prefix for each installation to make it work.

      -

      After you entered your details, you can continue with the Proceed to next step button. Now phpBB3 will check whether the data you entered will lead to a successful database connection and whether tables with the same prefix already exist.

      +

      After you entered your details, you can continue with the Proceed to next step button. Now phpBB3 will check whether the data you entered will lead to a successful database connection and whether tables with the same prefix already exist.

      A Could not connect to the database error means that you didn't enter the database data correctly and it is not possible for phpBB to connect. Make sure that everything you entered is in order and try again. Again, if you are unsure about your database settings, please contact your host.

      If you installed another version of phpBB before on the same database with the same prefix, phpBB will inform you and you just need to enter a different database prefix.

      -

      If you see the Successful Connection message, you can continue to the next step.

      +

      If you see the Successful Connection message, you can continue to the next step.

      Administrator details

      -

      Now you have to create your administration user. This user will have full administration access and he/she will be the first user on your forum. All fields on this page are required. You can also set the default language of your forum on this page. In a vanilla phpBB3 installation we only include English. You can download further languages from www.phpbb.com, and add them before installing or later.

      +

      Now you have to create your administration user. This user will have full administration access and he/she will be the first user on your forum. All fields on this page are required. You can also set the default language of your forum on this page. In a vanilla phpBB3 installation, we only include British English. You can download further languages from www.phpbb.com, and add them before installing or later.

      Configuration file

      -

      In this step, phpBB will try to write the configuration file automatically. The forum needs the configuration to run properly. It contains all database settings, so without it, phpBB will not be able to access the database.

      +

      In this step, phpBB will try to write the configuration file automatically. The forum needs the configuration file in order to operate. It contains all the database settings, so without it, phpBB will not be able to access the database.

      -

      Usually writing the configuration file automatically works fine. But in some cases it can fail due to wrong file permissions, for instance. In this case, you need to upload the file manually. phpBB asks you to download the config.php file and tells you what to do with it. Please read the instructions carefully. After you have uploaded the file, use Done to get to the last step. If Done returns you to the same page as before, and does not return a success message, you did not upload the file correctly.

      +

      Usually, writing the configuration file automatically works fine. If the file permissions are not set correctly, this process can fail. In this case, you need to upload the file manually. phpBB asks you to download the config.php file and tells you what to do with it. Please read the instructions carefully. After you have uploaded the file, use Done to get to the last step. If Done returns you to the same page as before, and does not return a success message, you did not upload the file correctly.

      Advanced settings

      -

      The Advanced settings allow you to set some parameters of the board configuration. They are optional and you can always change them later. So, even if you are not sure what these settings mean you can still proceed to the final step and finish the installation.

      +

      The Advanced settings allow you to set additional parameters of the board configuration. They are optional and you can always change them later. So, even if you are not sure what these settings mean, you can still proceed to the final step and finish the installation.

      -

      If the installation was successful, you can now use the Login button to visit the Administration Control Panel. Congratulations, you have installed phpBB successfully. But there is still work ahead!

      +

      If the installation was successful, you can now use the Login button to visit the Administration Control Panel. Congratulations, you have installed phpBB successfully. But there is still work ahead!

      -

      If you are unable to get phpBB3 installed even after reading this guide, please look at the support section to find out where you can ask for further assistance.

      +

      If you are unable to get phpBB3 installed even after reading this guide, please look at the support section of the installer's introduction page to find out where you can ask for further assistance.

      At this point if you are converting from phpBB 2.0.x, you should refer to the conversion steps for further information. If not, you should remove the install directory from your server as you will only be able to access the Administration Control Panel whilst it is present.

      @@ -257,47 +257,47 @@
      -

      If you are currently using a stable release of phpBB3 updating to this version is straightforward. You would have downloaded one of four packages and your choice determines what you need to do. Please Note: That before updating we heavily recommend you do a full backup of your database and existing phpBB3 files! If you are unsure how to achieve this please ask your hosting provider for advice.

      +

      If you are currently using a stable release of phpBB3, updating to this version is straightforward. You would have downloaded one of four packages and your choice determines what you need to do. Note: Before updating, we heavily recommend you do a full backup of your database and existing phpBB3 files! If you are unsure how to achieve this please ask your hosting provider for advice.

      Please make sure you update your phpBB3 source files too, even if you run the database_update.php file.

      4.i. Full package

      -

      The full package is normally meant for new installations only, but if you want to replace all source files this package comes in handy.

      +

      The full package is normally meant for new installations only, but if you want to replace all source files, this package comes in handy.

      -

      First you should make a copy of your existing config.php file, keep it in a safe place! Next delete all the existing phpBB3 files, you may want to leave your files/ and images/ directory in place. You can leave alternative styles in-place too. With this complete you can upload the new phpBB files (see New installation for details if necessary). Once complete copy back your saved config.php, replacing the new one. Another method is to just replace the existing files with the files from the full package - though make sure you do not overwrite your config.php file.

      +

      First, you should make a copy of your existing config.php file; keep it in a safe place! Next, delete all the existing phpBB3 files, you may want to leave your files/ and images/ directorie in place. You can leave alternative styles in place too. With this complete, you can upload the new phpBB files (see New installation for details if necessary). Once complete, copy back your saved config.php, replacing the new one. Another method is to just replace the existing files with the files from the full package - though make sure you do not overwrite your config.php file.

      -

      You should now run install/database_update.php which, depending on your previous version, will make a number of database changes. You may receive FAILURES during this procedure, they should not be a cause for concern unless you see an actual ERROR, in which case the script will stop (in this case you should seek help via our forums or bug tracker).

      +

      You should now run install/database_update.php which, depending on your previous version, will make a number of database changes. You may receive FAILURES during this procedure. They should not be a cause for concern unless you see an actual ERROR, in which case the script will stop (in this case you should seek help via our forums or bug tracker).

      -

      Once the install/database_update.php has completed you may proceed to the Administration Control Panel and check remove the install directory as advised.

      +

      Once install/database_update.php has completed, you may proceed to the Administration Control Panel and then remove the install directory as advised.

      4.ii. Changed files

      -

      This package is meant for those wanting to only replace changed files from a previous version to the latest version. This package normally contains the changed files from up to five previous versions.

      +

      This package is meant for those wanting to only replace the files that were changed between a previous version and the latest version.

      This package contains a number of archives, each contains the files changed from a given release to the latest version. You should select the appropriate archive for your current version, e.g. if you currently have 3.0.10 you should select the appropriate phpBB-3.0.11-files.zip/tar.bz2 file.

      -

      The directory structure has been preserved enabling you (if you wish) to simply upload the uncompressed contents of the archive to the appropriate location on your server, i.e. simply overwrite the existing files with the new versions. Do not forget that if you have installed any MODs these files will overwrite the originals possibly destroying them in the process. You will need to re-add MODs to any affected file before uploading.

      +

      The directory structure has been preserved, enabling you (if you wish) to simply upload the uncompressed contents of the archive to the appropriate location on your server, i.e. simply overwrite the existing files with the new versions. Do not forget that if you have installed any modifications (MODs) these files will overwrite the originals, possibly destroying them in the process. You will need to re-add MODs to any affected file before uploading.

      -

      As for the other update procedures you should run install/database_update.php after you have finished updating the files. This will update your database schema and increment the version number.

      +

      As for the other update procedures, you should run install/database_update.php after you have finished updating the files. This will update your database schema and increment the version number.

      4.iii. Patch file

      -

      The patch file package is for those wanting to update through the patch application, and being comfortable with it.

      +

      The patch file package is for those wanting to update through the patch application, and should only be used by those who are comfortable with it.

      -

      The patch file is one solution for those with many Modifications (MODs) or other changes who do not want to re-add them back to all the changed files if they use the method explained above. To use this you will need command line access to a standard UNIX type patch application. If you do not have access to such an application but still want to use this update approach, we strongly recommend the Automatic update package explained below. It is also the recommended update method.

      +

      The patch file is one solution for those with many Modifications (MODs) or other changes and do not want to re-add them back to all the changed files. To use this you will need command line access to a standard UNIX type patch application. If you do not have access to such an application, but still want to use this update approach, we strongly recommend the Automatic update package explained below. It is also the recommended update method.

      -

      A number of patch files are provided to allow you to update from previous stable releases. Select the correct patch, e.g. if your current version is 3.0.10 you need the phpBB-3.0.11-patch.zip/tar.bz2 file. Place the correct patch in the parent directory containing the phpBB core files (i.e. index.php, viewforum.php, etc.). With this done you should run the following command: patch -cl -d [PHPBB DIRECTORY] -p1 < [PATCH NAME] (where PHPBB DIRECTORY is the directory name your phpBB Installation resides in, for example phpBB, and where PATCH NAME is the relevant filename of the selected patch file). This should complete quickly, hopefully without any HUNK FAILED comments.

      +

      A number of patch files are provided to allow you to update from previous stable releases. Select the correct patch, e.g. if your current version is 3.0.10, you need the phpBB-3.0.11-patch.zip/tar.bz2 file. Place the correct patch in the parent directory containing the phpBB core files (i.e. index.php, viewforum.php, etc.). With this done you should run the following command: patch -cl -d [PHPBB DIRECTORY] -p1 < [PATCH NAME] (where PHPBB DIRECTORY is the directory name your phpBB Installation resides in, for example phpBB, and where PATCH NAME is the relevant filename of the selected patch file). This should complete quickly, hopefully without any HUNK FAILED comments.

      -

      If you do get failures you should look at using the Changed Files package to replace the files which failed to patch, please note that you will need to manually re-add any Modifications (MODs) to these particular files. Alternatively if you know how you can examine the .rej files to determine what failed where and make manual adjustments to the relevant source.

      +

      If you do get failures, you should look at using the Changed Files package to replace the files which failed to patch. Please note that you will need to manually re-add any MODs to these particular files. Alternatively, if you know how, you can examine the .rej files to determine what failed where and make manual adjustments to the relevant source.

      -

      You should of course delete the patch file (or files) after use. As for the other update procedures you should run install/database_update.php after you have finished updating the files. This will update your database schema and data (if appropriate) and increment the version number.

      +

      You should, of course, delete the patch file (or files) after use. As for the other update procedures, you should run install/database_update.php after you have finished updating the files. This will update your database schema and data (if appropriate) and increment the version number.

      4.iv. Automatic update package

      -

      This update method is the recommended method for updating. This package allows detecting changed files automatically and merges changes if needed.

      +

      This update method is the recommended method for updating. This package detects changed files automatically and merges in changes if needed.

      -

      The automatic update package contains - contrary to the others - only the information required to update the previous release version to the latest available version. These packages are meant for use with the automatic update tool.

      +

      The automatic update package will update the board from a given version to the latest version. A number of automatic update files are available, and you should choose the one that corresponds to the version of the board that you are currently running. For example, if your current version is 3.0.10, you need the phpBB-3.0.10_to_3.0.11.zip/tar.bz2 file.

      To perform the update, either follow the instructions from the Administration Control Panel->System Tab - this should point out that you are running an outdated version and will guide you through the update - or follow the instructions listed below.

      @@ -313,7 +313,7 @@

      4.v. All package types

      -

      If you have non-English language packs installed you may want to see if a new version has been made available. A number of missing strings may have been added which, though not essential, may be beneficial to users. Please note that at this time not all language packs have been updated so you should be prepared to periodically check for updates.

      +

      If you have non-English language packs installed, you may want to see if a new version has been made available. A number of missing strings may have been added which, though not essential, may be beneficial to users. Please note that at this time not all language packs have been updated so you should be prepared to periodically check for updates.

      These update methods will only update the standard styles, prosilver and subsilver2, any other styles you have installed for your board will usually also need to be updated.

      @@ -337,33 +337,33 @@

      5.i. Requirements before converting

      -

      Before converting we heavily recommend you do a full backup of your database and files! If you are unsure how to achieve this please ask your hosting provider for advice. You basically need to follow the basic instructions given for New installations. Please do not overwrite any old files - install phpBB3 at a different location.

      +

      Before converting, we heavily recommend you do a full backup of your database and files! If you are unsure how to achieve this, please ask your hosting provider for advice. You basically need to follow the instructions given for New installations. Please do not overwrite any old files - install phpBB3 at a different location.

      Once you made a backup of everything and also have a brand new phpBB3 installation, you can now begin the conversion.

      -

      Note that the conversion requires CREATE and DROP privileges for the phpBB3's database user account.

      +

      Note that the conversion requires CREATE and DROP privileges for the phpBB3 database user account.

      5.ii. Converting

      -

      To begin the conversion visit the install folder of your phpBB3 installation (the same as you have done for installing). Now you will see a new tab Convert. Click this tab.

      +

      To begin the conversion, visit the install. folder of your phpBB3 installation (the same as you have done for installing). Now you will see a new tab Convert. Click this tab.

      -

      As with install, the conversion is automated. Your previous 2.0.x database tables will not be changed as well as the original 2.0.x files remaining unaltered. The conversion is actually only filling your phpBB3 database tables and copying additional data over to your phpBB3 installation. This has the benefit that if something goes wrong you are able to either re-run the conversion or continue a conversion, while your old board is still accessible. We really recommend you disable your old installation while converting, else you may have inconsistent data after the conversion.

      +

      As with install, the conversion is automated. Your previous 2.0.x database tables will not be changed and the original 2.0.x files will remain unaltered. The conversion is actually only filling your phpBB3 database tables and copying additional data over to your phpBB3 installation. This has the benefit that if something goes wrong, you are able to either re-run the conversion or continue a conversion, while your old board is still accessible. We really recommend that you disable your old installation while converting, else you may have inconsistent data after the conversion.

      -

      Please note that this conversion process may take quite some time and depending on your hosting provider this may result in it failing (due to web server or other timeout issues). If this is the case you should ask your provider if they are willing to allow the convert script to temporarily exceed their limits (be nice and they will probably be quite helpful).

      +

      Please note that this conversion process may take quite some time and depending on your hosting provider this may result in it failing (due to web server resource limits or other timeout issues). If this is the case, you should ask your provider if they are willing to allow the convert script to temporarily exceed their limits (be nice and they will probably be quite helpful). If your host is unwilling to increase the limits to run the convertor, please see this article for performing the conversion on your local machine: Knowledge Base - Offline Conversions

      -

      Once completed your board should be immediately available. If you encountered errors you should report the problems to our bug tracker or seek help via our forums (see README for details).

      +

      Once completed, your board should be immediately available. If you encountered errors, you should report the problems to our bug tracker or seek help via our forums (see README for details).

      5.iii. Things to do after conversion

      -

      After successful conversion there may be a few items you need to do - apart from checking if the installation is accessible and everything displayed correctly.

      +

      After a successful conversion, there may be a few items you need to do - apart from checking if the installation is accessible and everything displayed correctly.

      -

      The first thing you may want to do is going to the administration control panel and checking every configuration item within the general tab. Thereafter you may want to adjust the forum descriptions/names if you entered HTML there. You also may want to access the other administrative sections, e.g. adjusting permissions, smilies, icons, ranks, etc.

      +

      The first thing you may want to do is to go to the administration control panel and check every configuration item within the general tab. Thereafter, you may want to adjust the forum descriptions/names if you entered HTML there. You also may want to access the other administrative sections, e.g. adjusting permissions, smilies, icons, ranks, etc.

      -

      Within the conversion the search index has not been created or transferred. This means after conversion you are not able to find any matches if you want to search for something. We recommend you rebuild your search index within Admin -> Maintenance -> Database -> Search Index.

      +

      During the conversion, the search index is not created or transferred. This means after conversion you are not able to find any matches if you want to search for something. We recommend you rebuild your search index within Administration Control Panel -> Maintenance -> Database -> Search Index.

      After verifying the settings in the ACP, you can delete the install directory to enable the board. The board will stay disabled until you do so.

      -

      Once you are pleased with your new installation you may want to give it the name of your old installation, changing the directory name. With phpBB3 this is possible without any problems - but you may still want to check your cookie settings within the administration panel, if the cookie path needs to be adjusted prior to renaming.

      +

      Once you are pleased with your new installation, you may want to give it the name of your old installation, changing the directory name. With phpBB3 this is possible without any problems, but you may still want to check your cookie settings within the administration panel; in case your cookie path needs to be adjusted prior to renaming.

      5.iv. Common conversion problems

      @@ -371,13 +371,13 @@

      http 500 / white pages The conversion is a load-heavy procedure. Restrictions imposed by some server hosting providers can cause problems. The most common causes are: values too low for the PHP settings memory_limit and max_execution_time. Limits on the allowed CPU time are also a frequent cause for such errors, as are limits on the number of database queries allowed. If you cannot change such settings, then contact your hosting provider or run the conversion procedure on a different computer. The phpBB.com forums are also an excellent location to ask for support.

      -

      Password conversion Due to the utf-8 based handling of passwords in phpBB3, it is not always possible to transfer all passwords. For passwords "lost in translation" the easiest workaround is to use the "forgotten password" function.

      +

      Password conversion Due to the utf-8 based handling of passwords in phpBB3, it is not always possible to transfer all passwords. For passwords "lost in translation" the easiest workaround is to use the I forgot my password link on the login page.

      -

      Path to your former board The converter expects the relative path to your old board's files. So, for instance, if the old board is located at http://www.yourdomain.com/forum and the phpBB3 installation is located at http://www.yourdomain.com/phpBB3, then the correct value would be ../forum. Note that the webserver user must be able to access the source installation's files.

      +

      Path to your former board The convertor expects the relative path to your old board's files. So, for instance, if the old board is located at http://www.yourdomain.com/forum and the phpBB3 installation is located at http://www.yourdomain.com/phpBB3, then the correct value would be ../forum. Note that the webserver user must be able to access the source installation's files.

      Missing images If your default board language's language pack does not include all images, then some images might be missing in your installation. Always use a complete language pack as default language.

      -

      Smilies During the conversion you might see warnings about image files where the copying failed. That can happen if the old board's smilies have the same file names as those on the new board. Copy those files manually after the conversion, if you want to continue using the old smilies.

      +

      Smilies During the conversion you might see warnings about image files where the copying failed. This can happen if the old board's smilies have the same file names as those on the new board. Copy those files manually after the conversion, if you want to continue using the old smilies.

      @@ -396,27 +396,27 @@
      -

      Once you have successfully installed phpBB3 you MUST ensure you remove the entire install/ directory. Leaving the install directory in place is a very serious potential security issue which may lead to deletion or alteration of files, etc. Please note that until this directory is removed, phpBB will not operate and a warning message will be displayed. Beyond this essential deletion, you may also wish to delete the docs/ directories if you wish.

      +

      Once you have successfully installed phpBB3 you MUST ensure you remove the entire install/ directory. Leaving the install directory in place is a very serious potential security issue which may lead to deletion or alteration of files, etc. Please note that until this directory is removed, phpBB will not operate and a warning message will be displayed. Beyond this essential deletion, you may also wish to delete the docs/ directory if you wish.

      -

      With these directories deleted you should proceed to the administration panel. Depending on how the installation completed you may have been directed there automatically. If not, login as the administrator you specified during install/conversion and click the Administration Panel link at the bottom of any page. Ensure that details specified in Admin -> General are correct!

      +

      With these directories deleted, you should proceed to the administration panel. Depending on how the installation completed, you may have been directed there automatically. If not, login as the administrator you specified during install/conversion and click the Administration Control Panel link at the bottom of any page. Ensure that details specified on the General tab are correct!

      6.i. Uploadable avatars

      phpBB3 supports several methods for allowing users to select their own avatar (an avatar is a small image generally unique to a user and displayed just below their username in posts).

      -

      Two of these options allow users to upload an avatar from their machine or a remote location (via a URL). If you wish to enable this function you should first ensure the correct paths for uploadeable avatars is set in Admin -> General -> Board Configuration -> Avatar settings. By default this is images/avatars/uploads but you can set it to whatever you like, just ensure the configuration setting is updated. You must also ensure this directory can be written to by the webserver. Usually this means you have to alter its permissions to allow anyone to read and write to. Exactly how you should do this depends on your ftp client or server operating system.

      +

      Two of these options allow users to upload an avatar from their machine or a remote location (via a URL). If you wish to enable this function you should first ensure the correct path for uploadable avatars is set in Administration Control Panel -> General -> Board Configuration -> Avatar settings. By default this is images/avatars/uploads, but you can set it to whatever you like, just ensure the configuration setting is updated. You must also ensure this directory can be written to by the webserver. Usually this means you have to alter its permissions to allow anyone to read and write to it. Exactly how you should do this depends on your FTP client or server operating system.

      -

      On UNIX systems for example you set the directory to a+rwx (or ugo+rwx or even 777). This can be done from a command line on your server using chmod or via your FTP client (using the Change Permissions, chmod or other Permissions dialoge box, see your FTP clients documentation for help). Most FTP clients list permissions in the form of User (Read, Write, Execute), Group (Read, Write, Execute) and Other (Read, Write, Execute). You need to tick all of these boxes to set correct permissions.

      +

      On UNIX systems, for example, you set the directory to a+rwx (or ugo+rwx or even 777). This can be done from a command line on your server using chmod or via your FTP client (using the Change Permissions, chmod or other Permissions dialog box, see your FTP client's documentation for help). Most FTP clients list permissions in the form of User (Read, Write, Execute), Group (Read, Write, Execute) and Other (Read, Write, Execute). You need to tick all of these boxes to set correct permissions.

      -

      On Windows system you need to ensure the directory is not write-protected and that it has global write permissions (see your servers documentation or contact your hosting provider if you are unsure on how to achieve this).

      +

      On Windows systems, you need to ensure the directory is not write-protected and that it has global write permissions (see your server's documentation or contact your hosting provider if you are unsure on how to achieve this).

      -

      Please be aware that setting a directories permissions to global write access is a potential security issue. While it is unlikely that anything nasty will occur (such as all the avatars being deleted) there are always people out there to cause trouble. Therefore you should monitor this directory and if possible make regular backups.

      +

      Please be aware that setting a directory's permissions to global write access is a potential security issue. While it is unlikely that anything nasty will occur (such as all the avatars being deleted) there are always people out there to cause trouble. Therefore you should monitor this directory and if possible make regular backups.

      6.ii. Webserver configuration

      -

      Depending on your web server you may have to configure your server to deny web access to the cache/, files/, store/ and other directories. This is to prevent users from accessing sensitive files.

      +

      Depending on your web server, you may have to configure your server to deny web access to the cache/, files/, store/ and other directories. This is to prevent users from accessing sensitive files.

      -

      For Apache there are .htaccess files already in place to do this for you. Similarly, for Windows based servers using .ASP.NET there are web.config files already in place to do this for you. For other webservers you will have to adjust the configuration yourself. Sample files for nginx and lighttpd to help you get started may be found in docs directory.

      +

      For Apache there are .htaccess files already in place to do this for you. Similarly, for Windows based servers using IIS there are web.config files already in place to do this for you. For other webservers, you will have to adjust the configuration yourself. Sample files for nginx and lighttpd to help you get started may be found in docs/ directory.

      @@ -433,7 +433,7 @@
      -

      Like any online site that allows user input, your board could be subject to unwanted posts; often referred to as forum spam. The vast majority of these attacks will be from automated computer computer programs known as spambots. The attacks, generally, are not personal as the spammers are just trying to find accessible targets. phpBB has a number of anti-spam measures built in including a range of CAPTCHAs. However, administrators are strongly urged to read and follow the advice for Preventing Spam in phpBB as soon as possible after completing the installation of your board.

      +

      Like any online site that allows user input, your board could be subject to unwanted posts; often referred to as forum spam. The vast majority of these attacks will be from automated computer programs known as spambots. The attacks, generally, are not personal as the spammers are just trying to find accessible targets. phpBB has a number of anti-spam measures built in, including a range of CAPTCHAs. However, administrators are strongly urged to read and follow the advice for Preventing Spam in phpBB as soon as possible after completing the installation of your board.

      @@ -450,7 +450,7 @@
      -

      This application is opensource software released under the GNU General Public License v2. Please see source code and the docs directory for more details. This package and its contents are Copyright (c) phpBB Group, All Rights Reserved.

      +

      This application is opensource software released under the GNU General Public License v2. Please see the source code and docs/ directory for more details. This package and its contents are Copyright © phpBB Group, All Rights Reserved.

      From 3baeb4276d6e09db1e81893bdad72a692f383e21 Mon Sep 17 00:00:00 2001 From: Bruno Ais Date: Thu, 26 Apr 2012 10:26:58 +0100 Subject: [PATCH 022/443] [ticket/10850] Changed the fopen mode to wb Changed the fopen mode from "wt" to "wb" as requested in the PR. The objective behind this is to prevent writting stuff like "\r\r\n" in windows PHPBB3-10850 --- phpBB/develop/create_schema_files.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/develop/create_schema_files.php b/phpBB/develop/create_schema_files.php index d44efb8870..7657932a05 100644 --- a/phpBB/develop/create_schema_files.php +++ b/phpBB/develop/create_schema_files.php @@ -237,7 +237,7 @@ $supported_dbms = array('firebird', 'mssql', 'mysql_40', 'mysql_41', 'oracle', ' foreach ($supported_dbms as $dbms) { - $fp = fopen($schema_path . $dbms . '_schema.sql', 'wt'); + $fp = fopen($schema_path . $dbms . '_schema.sql', 'wb'); $line = ''; From 2b89186294b2be5f074d8b57d875a337a0f60559 Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Thu, 28 Jun 2012 20:29:07 -0500 Subject: [PATCH 023/443] [ticket/10865] Phrase change for visiting with browser PHPBB3-10865 --- phpBB/docs/INSTALL.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/docs/INSTALL.html b/phpBB/docs/INSTALL.html index 84b6d6bce9..69c6505b65 100644 --- a/phpBB/docs/INSTALL.html +++ b/phpBB/docs/INSTALL.html @@ -108,7 +108,7 @@
    • Change the permissions on config.php to be writable by all (666 or -rw-rw-rw- within your FTP Client)
    • Change the permissions on the following directories to be writable by all (777 or -rwxrwxrwx within your FTP Client):
      store/, cache/, files/ and images/avatars/upload/.
    • -
    • Using your web browser, visit the location you placed phpBB3 with the addition of install/index.php or by pointing directly to install/, e.g. http://www.example.com/phpBB3/install/, http://www.example.com/forum/install/.
    • +
    • Point your web browser to the location where you uploaded the phpBB3 files with the addition of install/index.php or simply install/, e.g. http://www.example.com/phpBB3/install/index.php, http://www.example.com/forum/install/.
    • Click the INSTALL tab, follow the steps and fill out all the requested information.
    • Change the permissions on config.php to be writable only by yourself (644 or -rw-r--r-- within your FTP Client)
    • phpBB3 should now be available, please MAKE SURE you read at least Section 6 below for important, security related post-installation instructions, and also take note of Section 7 regarding anti-spam measures.
    • From cde5411e8aad0436ca709a46e109cd38e4c21a9e Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 8 Jul 2012 22:35:50 +0200 Subject: [PATCH 024/443] [ticket/10974] Rename tests/mock_user.php -> tests/mock/user.php PHPBB3-10974 --- tests/bbcode/url_bbcode_test.php | 2 +- tests/{mock_user.php => mock/user.php} | 0 tests/text_processing/censor_text_test.php | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename tests/{mock_user.php => mock/user.php} (100%) diff --git a/tests/bbcode/url_bbcode_test.php b/tests/bbcode/url_bbcode_test.php index 15bdfc434f..6b5afe5808 100644 --- a/tests/bbcode/url_bbcode_test.php +++ b/tests/bbcode/url_bbcode_test.php @@ -11,7 +11,7 @@ require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php'; require_once dirname(__FILE__) . '/../../phpBB/includes/bbcode.php'; require_once dirname(__FILE__) . '/../../phpBB/includes/message_parser.php'; -require_once dirname(__FILE__) . '/../mock_user.php'; +require_once dirname(__FILE__) . '/../mock/user.php'; class phpbb_url_bbcode_test extends phpbb_test_case { diff --git a/tests/mock_user.php b/tests/mock/user.php similarity index 100% rename from tests/mock_user.php rename to tests/mock/user.php diff --git a/tests/text_processing/censor_text_test.php b/tests/text_processing/censor_text_test.php index 8fcdb7ef85..f0e13638a5 100644 --- a/tests/text_processing/censor_text_test.php +++ b/tests/text_processing/censor_text_test.php @@ -9,7 +9,7 @@ require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php'; -require_once dirname(__FILE__) . '/../mock_user.php'; +require_once dirname(__FILE__) . '/../mock/user.php'; require_once dirname(__FILE__) . '/../mock/cache.php'; class phpbb_text_processing_censor_text_test extends phpbb_test_case From 797ee16eaf2e8dc562185cd940351bcfd311cf53 Mon Sep 17 00:00:00 2001 From: Fyorl Date: Mon, 16 Jul 2012 17:33:05 +0100 Subject: [PATCH 025/443] [ticket/10981] Added goutte via composer composer.phar added and autoloaded before tests PHPBB3-10981 --- composer.phar | Bin 0 -> 533673 bytes phpBB/composer.json | 6 ++ phpBB/composer.lock | 55 ++++++++++++++++++ tests/bootstrap.php | 15 +++++ .../phpbb_functional_test_case.php | 2 - vendor/goutte.phar | Bin 267414 -> 0 bytes 6 files changed, 76 insertions(+), 2 deletions(-) create mode 100755 composer.phar create mode 100644 phpBB/composer.json create mode 100644 phpBB/composer.lock delete mode 100644 vendor/goutte.phar diff --git a/composer.phar b/composer.phar new file mode 100755 index 0000000000000000000000000000000000000000..8b6eddbf21a06da1b6cc983749e5f3a755c674d5 GIT binary patch literal 533673 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

      &sc&YV^OBtLs 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 I&t5$Hf6wo5eE=')) { + if (getenv('PHPBB_NO_COMPOSER_AUTOLOAD')) + { + if (getenv('PHPBB_AUTOLOAD')) + { + require(getenv('PHPBB_AUTOLOAD')); + } + } + else + { + if (!file_exists($phpbb_root_path . 'vendor/autoload.php')) + { + trigger_error('You have not set up composer dependencies. See http://getcomposer.org/.', E_USER_ERROR); + } + require($phpbb_root_path . 'vendor/autoload.php'); + } require_once 'test_framework/phpbb_functional_test_case.php'; } diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 76fed76fae..2b6a6aaf29 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -36,8 +36,6 @@ class phpbb_functional_test_case extends phpbb_test_case { self::markTestSkipped('phar extension is not loaded'); } - - require_once 'phar://' . __DIR__ . '/../../vendor/goutte.phar'; } public function setUp() diff --git a/vendor/goutte.phar b/vendor/goutte.phar deleted file mode 100644 index 20b7166a6717aa5b904859fc1ffe3b32106d55a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 267414 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 L-+lYd^KbrtSl@Ba From d88411e10de898d8ad58b1adf9dcedf0f170b67f Mon Sep 17 00:00:00 2001 From: Fyorl Date: Mon, 16 Jul 2012 17:45:43 +0100 Subject: [PATCH 026/443] [ticket/10981] Modified functional framework to account for goutte changes PHPBB3-10981 --- tests/test_framework/phpbb_functional_test_case.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 2b6a6aaf29..e1a45a1bc4 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -46,7 +46,10 @@ class phpbb_functional_test_case extends phpbb_test_case } $this->cookieJar = new CookieJar; - $this->client = new Goutte\Client(array(), array(), null, $this->cookieJar); + $this->client = new Goutte\Client(array(), null, $this->cookieJar); + // Reset the curl handle because it is 0 at this point and not a valid + // resource + $this->client->getClient()->getCurlMulti()->reset(true); $this->root_url = self::$config['phpbb_functional_url']; // Clear the language array so that things // that were added in other tests are gone @@ -191,9 +194,9 @@ class phpbb_functional_test_case extends phpbb_test_case $cookies = $this->cookieJar->all(); // The session id is stored in a cookie that ends with _sid - we assume there is only one such cookie - foreach ($cookies as $key => $cookie); + foreach ($cookies as $cookie); { - if (substr($key, -4) == '_sid') + if (substr($cookie->getName(), -4) == '_sid') { $this->sid = $cookie->getValue(); } From ae07e80a6513b7277ba4a6a282df8281d2a37576 Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Tue, 17 Jul 2012 12:08:13 -0500 Subject: [PATCH 027/443] [ticket/10995] Return false in mssqlnative sql_fetchrow on empty result PHPBB3-10995 --- phpBB/includes/db/mssqlnative.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php index c91cc188b0..ff2f369706 100644 --- a/phpBB/includes/db/mssqlnative.php +++ b/phpBB/includes/db/mssqlnative.php @@ -436,7 +436,7 @@ class dbal_mssqlnative extends dbal unset($row['line2'], $row['line3']); } } - return $row; + return (sizeof($row)) ? $row : false; } /** From 7a412f846a9c4c8d712525cf03caa0b5549755ce Mon Sep 17 00:00:00 2001 From: Fyorl Date: Mon, 16 Jul 2012 18:03:47 +0100 Subject: [PATCH 028/443] [ticket/10981] Removed setupBeforeClass PHPBB3-10981 --- tests/test_framework/phpbb_functional_test_case.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index e1a45a1bc4..ed8ce9d040 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -30,14 +30,6 @@ class phpbb_functional_test_case extends phpbb_test_case static protected $config = array(); static protected $already_installed = false; - static public function setUpBeforeClass() - { - if (!extension_loaded('phar')) - { - self::markTestSkipped('phar extension is not loaded'); - } - } - public function setUp() { if (!isset(self::$config['phpbb_functional_url'])) From 74074994ba7a1af3ccd017006fc1808c2527706b Mon Sep 17 00:00:00 2001 From: Fyorl Date: Mon, 16 Jul 2012 18:07:20 +0100 Subject: [PATCH 029/443] [ticket/10981] Modified travis to use composer with --dev PHPBB3-10981 --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 6a1ecedac4..1a584add86 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,9 @@ before_script: - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'create database IF NOT EXISTS phpbb_tests;'; fi" - sh -c "if [ '$TRAVIS_PHP_VERSION' = '5.2' ]; then pear install --force phpunit/DbUnit; else pyrus install --force phpunit/DbUnit; fi" - phpenv rehash + - cd phpBB + - php ../composer.phar install --dev + - cd .. script: - phpunit --configuration travis/phpunit-$DB-travis.xml From aa2f7bcc2c56fdd82cb07e9794d6114d4b2c359c Mon Sep 17 00:00:00 2001 From: Fyorl Date: Mon, 16 Jul 2012 18:45:10 +0100 Subject: [PATCH 030/443] [ticket/10981] Added check for PHP version before running composer PHPBB3-10981 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1a584add86..7c7ba36bfb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ before_script: - sh -c "if [ '$TRAVIS_PHP_VERSION' = '5.2' ]; then pear install --force phpunit/DbUnit; else pyrus install --force phpunit/DbUnit; fi" - phpenv rehash - cd phpBB - - php ../composer.phar install --dev + - sh -c "if [ '$TRAVIS_PHP_VERSION' != '5.2' ]; then php ../composer.phar install --dev; fi" - cd .. script: From d157c3b3f40d4779a69af691bf8a304d7666c74d Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Wed, 18 Jul 2012 01:22:24 -0500 Subject: [PATCH 031/443] [ticket/10996] Use correct DBMS name in Travis config for PostgreSQL PHPBB3-10996 --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6a1ecedac4..2dbc2fc6d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,8 @@ env: - DB=postgres before_script: - - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'DROP DATABASE IF EXISTS phpbb_tests;' -U postgres; fi" - - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'create database phpbb_tests;' -U postgres; fi" + - sh -c "if [ '$DB' = 'postgres' ]; then psql -c 'DROP DATABASE IF EXISTS phpbb_tests;' -U postgres; fi" + - sh -c "if [ '$DB' = 'postgres' ]; then psql -c 'create database phpbb_tests;' -U postgres; fi" - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'create database IF NOT EXISTS phpbb_tests;'; fi" - sh -c "if [ '$TRAVIS_PHP_VERSION' = '5.2' ]; then pear install --force phpunit/DbUnit; else pyrus install --force phpunit/DbUnit; fi" - phpenv rehash From be44f32008d17c64d88eae4a7c5cae8b2773f218 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 21 Jul 2012 00:24:09 +0200 Subject: [PATCH 032/443] [ticket/11009] Backport build.xml from develop to fix Bamboo Unit Testing. PHPBB3-11009 --- build/build.xml | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/build/build.xml b/build/build.xml index c1179015eb..1b8d42a660 100644 --- a/build/build.xml +++ b/build/build.xml @@ -11,9 +11,9 @@ - - - + + + @@ -43,7 +43,13 @@ - + + + + + - + + + + From 647d395908a6e852acef9ec65aa649eb3754a1d2 Mon Sep 17 00:00:00 2001 From: Fyorl Date: Mon, 30 Jul 2012 12:54:00 +0100 Subject: [PATCH 033/443] [ticket/11034] Re-arranged install order to emulate real install PHPBB3-11034 --- tests/test_framework/phpbb_functional_test_case.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index ed8ce9d040..2423299b7c 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -139,13 +139,11 @@ class phpbb_functional_test_case extends phpbb_test_case $this->do_request('create_table', $data); + $this->do_request('config_file', $data); file_put_contents($phpbb_root_path . "config.$phpEx", phpbb_create_config_file_data($data, self::$config['dbms'], array(), true)); - $this->do_request('config_file', $data); - - copy($phpbb_root_path . "config.$phpEx", $phpbb_root_path . "config_test.$phpEx"); - $this->do_request('final', $data); + copy($phpbb_root_path . "config.$phpEx", $phpbb_root_path . "config_test.$phpEx"); } private function do_request($sub, $post_data = null) From d0a1c7bf0ae79bac3c35af03c6753862f446aa73 Mon Sep 17 00:00:00 2001 From: Senky Date: Mon, 23 Jul 2012 14:39:33 +0200 Subject: [PATCH 034/443] [ticket/10568] adding MESSAGE_EDITED to ucp.php and compose_pm PHPBB3-10568 --- phpBB/includes/ucp/ucp_pm_compose.php | 3 ++- phpBB/language/en/ucp.php | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php index 05243e3d7a..d1786dd9ba 100644 --- a/phpBB/includes/ucp/ucp_pm_compose.php +++ b/phpBB/includes/ucp/ucp_pm_compose.php @@ -755,7 +755,8 @@ function compose_pm($id, $mode, $action, $user_folders = array()) $return_box_lang = ($action === 'post' || $action === 'edit') ? 'PM_OUTBOX' : 'PM_INBOX'; - $message = $user->lang['MESSAGE_STORED'] . '

      ' . sprintf($user->lang['VIEW_PRIVATE_MESSAGE'], '', ''); + $save_message = ($action === 'edit') ? $user->lang['MESSAGE_EDITED'] : $user->lang['MESSAGE_STORED']; + $message = $save_message . '

      ' . $user->lang('VIEW_PRIVATE_MESSAGE', '', ''); $last_click_type = 'CLICK_RETURN_FOLDER'; if ($folder_url) diff --git a/phpBB/language/en/ucp.php b/phpBB/language/en/ucp.php index 94d9a5171e..d45cd3bd8b 100644 --- a/phpBB/language/en/ucp.php +++ b/phpBB/language/en/ucp.php @@ -257,6 +257,7 @@ $lang = array_merge($lang, array( 'MESSAGE_BY_AUTHOR' => 'by', 'MESSAGE_COLOURS' => 'Message colours', 'MESSAGE_DELETED' => 'Message successfully deleted.', + 'MESSAGE_EDITED' => 'Message successfully edited.', 'MESSAGE_HISTORY' => 'Message history', 'MESSAGE_REMOVED_FROM_OUTBOX' => 'This message has been removed by its author before it was delivered.', 'MESSAGE_SENT_ON' => 'on', From 72eef2af5cfbe5fc4ac879c2591556b790610fe9 Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Fri, 3 Aug 2012 20:27:35 -0500 Subject: [PATCH 035/443] [ticket/10865] Add .css, .js, and .htaccess to the list of ASCII mode files PHPBB3-10865 --- phpBB/docs/INSTALL.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/docs/INSTALL.html b/phpBB/docs/INSTALL.html index 69c6505b65..92dbef9d0d 100644 --- a/phpBB/docs/INSTALL.html +++ b/phpBB/docs/INSTALL.html @@ -181,7 +181,7 @@

      If you do not have shell access or do not wish to use it, you will need to decompress the phpBB3 archive to a local directory on your system using your favourite compression program, e.g. winzip, rar, zip, etc. From there you must FTP ALL the files it contains (being sure to retain the directory structure and filenames) to your host. Please ensure that the cases of filenames are retained, do NOT force filenames to all lower or upper case as doing so will cause errors later.

      -

      All .php, .sql, .cfg, .html and .txt files should be uploaded in ASCII mode, while all graphics should be uploaded in BINARY mode. If you are unfamiliar with what this means please refer to your FTP client documentation. In most cases this is all handled transparantly by your ftp client, but if you encounter problems later you should be sure the files were uploaded correctly as described here.

      +

      All .php, .sql, .cfg, .css, .js, .html, .htaccess and .txt files should be uploaded in ASCII mode, while all graphics should be uploaded in BINARY mode. If you are unfamiliar with what this means please refer to your FTP client documentation. In most cases this is all handled transparantly by your ftp client, but if you encounter problems later you should be sure the files were uploaded correctly as described here.

      phpBB3 comes supplied with British English as its standard language. However, a number of separate packs for different languages are available. If you are not a native English speaker you may wish to install one or more of these packages before continuing. The installation process below will allow you to select a default language from those available (you can, of course, change this default at a later stage). For more details on language packs, where to obtain them and how to install them please see the README.

      From 83a4d9abb58d22d9533e257dfaff83bac0d2a304 Mon Sep 17 00:00:00 2001 From: Dhruv Goel Date: Wed, 20 Jun 2012 11:14:16 +0530 Subject: [PATCH 036/443] [ticket/10943] use keywords variable to display in search box $keywords which contains the string as entered by the user should be used to display in search box instead of search_query. PHPBB3-10943 --- phpBB/search.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/search.php b/phpBB/search.php index 8cb2020630..7f3bd98289 100644 --- a/phpBB/search.php +++ b/phpBB/search.php @@ -603,7 +603,7 @@ if ($keywords || $author || $author_id || $search_id || $submit) $template->assign_vars(array( 'SEARCH_TITLE' => $l_search_title, 'SEARCH_MATCHES' => $l_search_matches, - 'SEARCH_WORDS' => $search->search_query, + 'SEARCH_WORDS' => $keywords, 'IGNORED_WORDS' => (sizeof($search->common_words)) ? implode(' ', $search->common_words) : '', 'PAGINATION' => generate_pagination($u_search, $total_match_count, $per_page, $start), 'PAGE_NUMBER' => on_page($total_match_count, $per_page, $start), From 2ba1cef5b03fc7c2c44076d21426d0b5028eda27 Mon Sep 17 00:00:00 2001 From: Dhruv Goel Date: Fri, 22 Jun 2012 15:16:13 +0530 Subject: [PATCH 037/443] [ticket/10943] displays searched query in search result Search backend displays an additional normalized search query just above the ignored words. PHPBB3-10943 --- phpBB/language/en/search.php | 1 + phpBB/search.php | 1 + phpBB/styles/prosilver/template/search_results.html | 1 + 3 files changed, 3 insertions(+) diff --git a/phpBB/language/en/search.php b/phpBB/language/en/search.php index cd38cd615f..97bc1f9bac 100644 --- a/phpBB/language/en/search.php +++ b/phpBB/language/en/search.php @@ -77,6 +77,7 @@ $lang = array_merge($lang, array( 'SEARCHED_FOR' => 'Search term used', 'SEARCHED_TOPIC' => 'Searched topic', + 'SEARCHED_QUERY' => 'Searched query', 'SEARCH_ALL_TERMS' => 'Search for all terms or use query as entered', 'SEARCH_ANY_TERMS' => 'Search for any terms', 'SEARCH_AUTHOR' => 'Search for author', diff --git a/phpBB/search.php b/phpBB/search.php index 7f3bd98289..ad9c371f63 100644 --- a/phpBB/search.php +++ b/phpBB/search.php @@ -604,6 +604,7 @@ if ($keywords || $author || $author_id || $search_id || $submit) 'SEARCH_TITLE' => $l_search_title, 'SEARCH_MATCHES' => $l_search_matches, 'SEARCH_WORDS' => $keywords, + 'SEARCHED_QUERY' => $search->search_query, 'IGNORED_WORDS' => (sizeof($search->common_words)) ? implode(' ', $search->common_words) : '', 'PAGINATION' => generate_pagination($u_search, $total_match_count, $per_page, $start), 'PAGE_NUMBER' => on_page($total_match_count, $per_page, $start), diff --git a/phpBB/styles/prosilver/template/search_results.html b/phpBB/styles/prosilver/template/search_results.html index f2a4435103..0ea9d8a047 100644 --- a/phpBB/styles/prosilver/template/search_results.html +++ b/phpBB/styles/prosilver/template/search_results.html @@ -1,6 +1,7 @@

      {SEARCH_TITLE}{SEARCH_MATCHES}: {SEARCH_WORDS}

      +

      {L_SEARCHED_QUERY}: {SEARCHED_QUERY}

      {L_IGNORED_TERMS}: {IGNORED_WORDS}

      From 0ae4b2016020191ae2217eb736ca91ae26dc7884 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Sun, 19 Aug 2012 02:18:22 +0200 Subject: [PATCH 038/443] [ticket/11059] Use https for the README logo It's causing troubles since we moved the site to HTTPS PHPBB3-11059 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 51e65176c6..f6ef523e17 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![phpBB](http://www.phpbb.com/theme/images/logos/blue/160x52.png)](http://www.phpbb.com) +[![phpBB](https://www.phpbb.com/theme/images/logos/blue/160x52.png)](http://www.phpbb.com) ## ABOUT From 92761e1f2b59bbe817579a1cdddd508b9817cdee Mon Sep 17 00:00:00 2001 From: David King Date: Tue, 21 Aug 2012 11:59:44 -0400 Subject: [PATCH 039/443] [ticket/10873] Change language for notice about undelivered, deleted PM. See the ticket for my reasoning. PHPBB3-10873 --- phpBB/language/en/ucp.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/language/en/ucp.php b/phpBB/language/en/ucp.php index 94d9a5171e..a2c1ad7a3e 100644 --- a/phpBB/language/en/ucp.php +++ b/phpBB/language/en/ucp.php @@ -258,7 +258,7 @@ $lang = array_merge($lang, array( 'MESSAGE_COLOURS' => 'Message colours', 'MESSAGE_DELETED' => 'Message successfully deleted.', 'MESSAGE_HISTORY' => 'Message history', - 'MESSAGE_REMOVED_FROM_OUTBOX' => 'This message has been removed by its author before it was delivered.', + 'MESSAGE_REMOVED_FROM_OUTBOX' => 'This message was deleted by its author.', 'MESSAGE_SENT_ON' => 'on', 'MESSAGE_STORED' => 'This message has been sent successfully.', 'MESSAGE_TO' => 'To', From 73cd044f5c81a1600f63103a33318e20163f5095 Mon Sep 17 00:00:00 2001 From: Jordan Rogers Date: Tue, 21 Aug 2012 10:20:35 -0300 Subject: [PATCH 040/443] [ticket/11066] Remove debug code error_reporting(E_ALL) from mssqlnative.php For some reason, all errors are just flipped on before connecting to the database, despite the system as a whole having a different setting for displayable errors. Had to add & ~E_STRICT in PHP 5.4.5 to suppress Strict Standards messages, but I would assume that the db piece shouldn't be involved with setting error_reporting at all. PHPBB3-11066 --- phpBB/includes/db/mssqlnative.php | 1 - 1 file changed, 1 deletion(-) diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php index ff2f369706..3ad0ff3e11 100644 --- a/phpBB/includes/db/mssqlnative.php +++ b/phpBB/includes/db/mssqlnative.php @@ -219,7 +219,6 @@ class dbal_mssqlnative extends dbal $this->server = $sqlserver . (($port) ? $port_delimiter . $port : ''); //connect to database - error_reporting(E_ALL); $this->db_connect_id = sqlsrv_connect($this->server, array( 'Database' => $this->dbname, 'UID' => $this->user, From 5407f9b00dc550c3c6fb7d4415400332cfa00204 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 26 Aug 2012 15:09:00 +0200 Subject: [PATCH 041/443] [ticket/11060] Backport ca4cee86afb88820a52ac1535de18c4dbb365f0e to olympus. PHPBB3-11060 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 42d7b201fa..94e7086c1e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ before_script: - sh -c "if [ '$DB' = 'postgres' ]; then psql -c 'DROP DATABASE IF EXISTS phpbb_tests;' -U postgres; fi" - sh -c "if [ '$DB' = 'postgres' ]; then psql -c 'create database phpbb_tests;' -U postgres; fi" - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'create database IF NOT EXISTS phpbb_tests;'; fi" + - sh -c "if [ '$TRAVIS_PHP_VERSION' != '5.2' ]; then pyrus set auto_discover 1; fi" - sh -c "if [ '$TRAVIS_PHP_VERSION' = '5.2' ]; then pear install --force phpunit/DbUnit; else pyrus install --force phpunit/DbUnit; fi" - phpenv rehash - cd phpBB From c83ca457a002be4899390cc8a7b0c2636f69e25d Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 26 Aug 2012 17:20:45 +0200 Subject: [PATCH 042/443] [ticket/11069] Add closing span back to credit line in subsilver2 simple footer Regression from 0ceb77fb995e7433242a87c1fe0c22840a2b23e1. PHPBB3-11069 --- phpBB/styles/subsilver2/template/simple_footer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/styles/subsilver2/template/simple_footer.html b/phpBB/styles/subsilver2/template/simple_footer.html index db95c7952a..6cb4f401da 100644 --- a/phpBB/styles/subsilver2/template/simple_footer.html +++ b/phpBB/styles/subsilver2/template/simple_footer.html @@ -2,7 +2,7 @@
      - {CREDIT_LINE} + {CREDIT_LINE}
      From 012c2817434e6b03b29076c644fb7b0f5fc83ff2 Mon Sep 17 00:00:00 2001 From: Fyorl Date: Mon, 6 Aug 2012 20:43:54 +0100 Subject: [PATCH 043/443] [ticket/11045] Added unit tests for the compress class PHPBB3-11045 --- tests/compress/archive/.gitkeep | 0 tests/compress/compress_test.php | 157 +++++++++++++++++++++++ tests/compress/extract/.gitkeep | 0 tests/compress/fixtures/1.txt | 1 + tests/compress/fixtures/archive.tar | Bin 0 -> 10240 bytes tests/compress/fixtures/archive.tar.bz2 | Bin 0 -> 224 bytes tests/compress/fixtures/archive.tar.gz | Bin 0 -> 239 bytes tests/compress/fixtures/archive.zip | Bin 0 -> 412 bytes tests/compress/fixtures/dir/2.txt | 1 + tests/compress/fixtures/dir/3.txt | 1 + tests/compress/fixtures/dir/subdir/4.txt | 1 + 11 files changed, 161 insertions(+) create mode 100644 tests/compress/archive/.gitkeep create mode 100644 tests/compress/compress_test.php create mode 100644 tests/compress/extract/.gitkeep create mode 100644 tests/compress/fixtures/1.txt create mode 100644 tests/compress/fixtures/archive.tar create mode 100644 tests/compress/fixtures/archive.tar.bz2 create mode 100644 tests/compress/fixtures/archive.tar.gz create mode 100644 tests/compress/fixtures/archive.zip create mode 100644 tests/compress/fixtures/dir/2.txt create mode 100644 tests/compress/fixtures/dir/3.txt create mode 100644 tests/compress/fixtures/dir/subdir/4.txt diff --git a/tests/compress/archive/.gitkeep b/tests/compress/archive/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/compress/compress_test.php b/tests/compress/compress_test.php new file mode 100644 index 0000000000..a88e5e5b32 --- /dev/null +++ b/tests/compress/compress_test.php @@ -0,0 +1,157 @@ +path = __DIR__ . '/fixtures/'; + $compress = new compress(); + + if (sizeof($compress->methods()) < 4) + { + $this->markTestSkipped('PHP needs to be compiled with --with-zlib and --with-bz2 in order to run these tests'); + } + } + + protected function tearDown() + { + foreach (array(__DIR__ . self::EXTRACT_DIR, __DIR__ . self::ARCHIVE_DIR) as $dir) { + $this->clear_dir($dir); + } + } + + protected function clear_dir($dir) + { + $iterator = new DirectoryIterator($dir); + foreach ($iterator as $fileinfo) + { + $name = $fileinfo->getFilename(); + $path = $fileinfo->getPathname(); + + if ($name[0] !== '.') + { + if ($fileinfo->isDir()) + { + $this->clear_dir($path); + rmdir($path); + } + else + { + unlink($path); + } + } + } + } + + protected function archive_files($compress) + { + $compress->add_file($this->path . '1.txt', $this->path); + $compress->add_file( + 'tests/compress/fixtures/dir/', + 'tests/compress/fixtures/', + '', + // The comma here is not an error, this is a comma-separated list + 'subdir/4.txt,3.txt' + ); + $compress->add_custom_file($this->path . 'dir/3.txt', 'dir/3.txt'); + $compress->add_data(file_get_contents($this->path . 'dir/subdir/4.txt'), 'dir/subdir/4.txt'); + } + + protected function valid_extraction() + { + foreach ($this->filelist as $filename) + { + $path = __DIR__ . self::EXTRACT_DIR . $filename; + $this->assertTrue(file_exists($path)); + + // Check the file's contents is correct + $this->assertEquals(basename($filename, '.txt') . "\n", file_get_contents($path)); + } + } + + public function tar_archive_list() + { + return array( + array('archive.tar', '.tar'), + array('archive.tar.gz', '.tar.gz'), + array('archive.tar.bz2', '.tar.bz2'), + ); + } + + /** + * @dataProvider tar_archive_list + */ + public function test_extract_tar($filename, $type) + { + $compress = new compress_tar('r', $this->path . $filename); + $compress->extract('tests/compress/' . self::EXTRACT_DIR); + $this->valid_extraction(); + } + + public function test_extract_zip() + { + $compress = new compress_zip('r', $this->path . 'archive.zip'); + $compress->extract('tests/compress/' . self::EXTRACT_DIR); + $this->valid_extraction(); + } + + /** + * @depends test_extract_tar + * @dataProvider tar_archive_list + */ + public function test_compress_tar($filename, $type) + { + $tar = __DIR__ . self::ARCHIVE_DIR . $filename; + $compress = new compress_tar('w', $tar); + $this->archive_files($compress); + $compress->close(); + $this->assertTrue(file_exists($tar)); + + $compress->mode = 'r'; + $compress->open(); + $compress->extract('tests/compress/' . self::EXTRACT_DIR); + $this->valid_extraction(); + } + + /** + * @depends test_extract_zip + */ + public function test_compress_zip() + { + $zip = __DIR__ . self::ARCHIVE_DIR . 'archive.zip'; + $compress = new compress_zip('w', $zip); + $this->archive_files($compress); + $compress->close(); + $this->assertTrue(file_exists($zip)); + + $compress = new compress_zip('r', $zip); + $compress->extract('tests/compress/' . self::EXTRACT_DIR); + $this->valid_extraction(); + } +} diff --git a/tests/compress/extract/.gitkeep b/tests/compress/extract/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/compress/fixtures/1.txt b/tests/compress/fixtures/1.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/compress/fixtures/1.txt @@ -0,0 +1 @@ +1 diff --git a/tests/compress/fixtures/archive.tar b/tests/compress/fixtures/archive.tar new file mode 100644 index 0000000000000000000000000000000000000000..54ed56084ed5035d52a6758895e953771a6f0ac5 GIT binary patch literal 10240 zcmeI0&kDmJ48}e0Df$GPQKQeZ(MuV-^bhRumlO)JL)RS?p0kH%WFtrDzs92R z(0>ig&Bn;if1y+v`0M+>p8p)lZvyQ9E3BFT{a2uj5Fh{oAOHd&00JNY0w4eaAOHd& Q00JNY0w4eaAW)yc2QS-gZ2$lO literal 0 HcmV?d00001 diff --git a/tests/compress/fixtures/archive.tar.bz2 b/tests/compress/fixtures/archive.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..04c0eccd743c82a71968aba3d44d4300f317ced8 GIT binary patch literal 224 zcmV<603ZKCT4**gL0KkKS-?;N8UO(*`+~ucKp;Q?|A0b_bSfS|KmY&;FaYyv!b)V- z8VwjDK+&|+5lKzyOhKXQ000Rj(lSgYfrMzp&)x^#h+|IJV&Rlb0vzZIY^{B*Kxi1S zLt`k2xNrw>z=1)o6MU^l(9ml$SydrY6u|~r80Vd$3PDQ2I99|#L}nc_O;M3CN^rol z2=4%3?*)?#ULo9)Ft~x-a;F6ZPPXY71j_-P1c5Z1Q5k_^Eswsu4RcTysaP!qKvWcx a;x5HPqSz!mfEikzU$-z4X0aU-Q0 zf1t~5>3>H5Yl!IosV)Bh plGZV>tN+vgU+_GQ{#TIDe*gdg00000004l$^Z|MERe%O3Z_s1YGQF|63Ac^ka`oKdPXLDX50=1 zY61d Date: Tue, 7 Aug 2012 12:25:21 +0100 Subject: [PATCH 044/443] [ticket/11045] Added tests for file conflicts PHPBB3-11045 --- tests/compress/compress_test.php | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/tests/compress/compress_test.php b/tests/compress/compress_test.php index a88e5e5b32..826abbc0c8 100644 --- a/tests/compress/compress_test.php +++ b/tests/compress/compress_test.php @@ -17,6 +17,7 @@ class phpbb_compress_test extends phpbb_test_case const ARCHIVE_DIR = '/archive/'; private $path; + protected $filelist = array( '1.txt', 'dir/2.txt', @@ -24,6 +25,12 @@ class phpbb_compress_test extends phpbb_test_case 'dir/subdir/4.txt', ); + protected $conflicts = array( + '1_1.txt', + '1_2.txt', + 'dir/2_1.txt', + ); + protected function setUp() { // Required for compress::add_file @@ -81,17 +88,26 @@ class phpbb_compress_test extends phpbb_test_case ); $compress->add_custom_file($this->path . 'dir/3.txt', 'dir/3.txt'); $compress->add_data(file_get_contents($this->path . 'dir/subdir/4.txt'), 'dir/subdir/4.txt'); + + // Add multiples of the same file to check conflicts are handled + $compress->add_file($this->path . '1.txt', $this->path); + $compress->add_file($this->path . '1.txt', $this->path); + $compress->add_file($this->path . 'dir/2.txt', $this->path); } - protected function valid_extraction() + protected function valid_extraction($extra = array()) { - foreach ($this->filelist as $filename) + $filelist = array_merge($this->filelist, $extra); + + foreach ($filelist as $filename) { $path = __DIR__ . self::EXTRACT_DIR . $filename; $this->assertTrue(file_exists($path)); // Check the file's contents is correct - $this->assertEquals(basename($filename, '.txt') . "\n", file_get_contents($path)); + $contents = explode('_', basename($filename, '.txt')); + $contents = $contents[0]; + $this->assertEquals($contents . "\n", file_get_contents($path)); } } @@ -136,7 +152,7 @@ class phpbb_compress_test extends phpbb_test_case $compress->mode = 'r'; $compress->open(); $compress->extract('tests/compress/' . self::EXTRACT_DIR); - $this->valid_extraction(); + $this->valid_extraction($this->conflicts); } /** @@ -152,6 +168,6 @@ class phpbb_compress_test extends phpbb_test_case $compress = new compress_zip('r', $zip); $compress->extract('tests/compress/' . self::EXTRACT_DIR); - $this->valid_extraction(); + $this->valid_extraction($this->conflicts); } } From 83a532607761fa7c6de70bd114fe8d6bf5ba2983 Mon Sep 17 00:00:00 2001 From: Fyorl Date: Fri, 10 Aug 2012 12:10:37 +0100 Subject: [PATCH 045/443] [ticket/11045] Explicitely check for zlib and bz2 PHPBB3-11045 --- tests/compress/compress_test.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/compress/compress_test.php b/tests/compress/compress_test.php index 826abbc0c8..c0e4e914e1 100644 --- a/tests/compress/compress_test.php +++ b/tests/compress/compress_test.php @@ -38,9 +38,8 @@ class phpbb_compress_test extends phpbb_test_case $phpbb_root_path = ''; $this->path = __DIR__ . '/fixtures/'; - $compress = new compress(); - if (sizeof($compress->methods()) < 4) + if (!@extension_loaded('zlib') || !@extension_loaded('bz2')) { $this->markTestSkipped('PHP needs to be compiled with --with-zlib and --with-bz2 in order to run these tests'); } From 94c9d7029809bce1ab8a70981f81dfb02a5b2a38 Mon Sep 17 00:00:00 2001 From: Fyorl Date: Tue, 14 Aug 2012 11:14:38 +0100 Subject: [PATCH 046/443] [ticket/11045] Opening brace on its own line PHPBB3-11045 --- tests/compress/compress_test.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/compress/compress_test.php b/tests/compress/compress_test.php index c0e4e914e1..c9450f2e29 100644 --- a/tests/compress/compress_test.php +++ b/tests/compress/compress_test.php @@ -47,7 +47,8 @@ class phpbb_compress_test extends phpbb_test_case protected function tearDown() { - foreach (array(__DIR__ . self::EXTRACT_DIR, __DIR__ . self::ARCHIVE_DIR) as $dir) { + foreach (array(__DIR__ . self::EXTRACT_DIR, __DIR__ . self::ARCHIVE_DIR) as $dir) + { $this->clear_dir($dir); } } From 1520130b2707039630fb3a83e4ab7654db3ad537 Mon Sep 17 00:00:00 2001 From: Fyorl Date: Sat, 1 Sep 2012 09:45:11 +0800 Subject: [PATCH 047/443] [ticket/11045] Replaced __DIR__ with dirname(__FILE__) PHPBB3-11045 --- tests/compress/compress_test.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/compress/compress_test.php b/tests/compress/compress_test.php index c9450f2e29..ac8dd358d3 100644 --- a/tests/compress/compress_test.php +++ b/tests/compress/compress_test.php @@ -7,9 +7,9 @@ * */ -require_once __DIR__ . '/../../phpBB/includes/functions.php'; -require_once __DIR__ . '/../../phpBB/includes/functions_admin.php'; -require_once __DIR__ . '/../../phpBB/includes/functions_compress.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/functions_admin.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/functions_compress.php'; class phpbb_compress_test extends phpbb_test_case { @@ -37,7 +37,7 @@ class phpbb_compress_test extends phpbb_test_case global $phpbb_root_path; $phpbb_root_path = ''; - $this->path = __DIR__ . '/fixtures/'; + $this->path = dirname(__FILE__) . '/fixtures/'; if (!@extension_loaded('zlib') || !@extension_loaded('bz2')) { @@ -47,7 +47,7 @@ class phpbb_compress_test extends phpbb_test_case protected function tearDown() { - foreach (array(__DIR__ . self::EXTRACT_DIR, __DIR__ . self::ARCHIVE_DIR) as $dir) + foreach (array(dirname(__FILE__) . self::EXTRACT_DIR, dirname(__FILE__) . self::ARCHIVE_DIR) as $dir) { $this->clear_dir($dir); } @@ -101,7 +101,7 @@ class phpbb_compress_test extends phpbb_test_case foreach ($filelist as $filename) { - $path = __DIR__ . self::EXTRACT_DIR . $filename; + $path = dirname(__FILE__) . self::EXTRACT_DIR . $filename; $this->assertTrue(file_exists($path)); // Check the file's contents is correct @@ -143,7 +143,7 @@ class phpbb_compress_test extends phpbb_test_case */ public function test_compress_tar($filename, $type) { - $tar = __DIR__ . self::ARCHIVE_DIR . $filename; + $tar = dirname(__FILE__) . self::ARCHIVE_DIR . $filename; $compress = new compress_tar('w', $tar); $this->archive_files($compress); $compress->close(); @@ -160,7 +160,7 @@ class phpbb_compress_test extends phpbb_test_case */ public function test_compress_zip() { - $zip = __DIR__ . self::ARCHIVE_DIR . 'archive.zip'; + $zip = dirname(__FILE__) . self::ARCHIVE_DIR . 'archive.zip'; $compress = new compress_zip('w', $zip); $this->archive_files($compress); $compress->close(); From 7cffebbd4997f8a41a871f8ea6fe12dc0abc08c8 Mon Sep 17 00:00:00 2001 From: David King Date: Sun, 19 Aug 2012 17:24:38 -0400 Subject: [PATCH 048/443] [task/functional] Added posting tests (reply and new topic) PHPBB-10758 --- tests/functional/posting_test.php | 110 ++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 tests/functional/posting_test.php diff --git a/tests/functional/posting_test.php b/tests/functional/posting_test.php new file mode 100644 index 0000000000..8d722361e0 --- /dev/null +++ b/tests/functional/posting_test.php @@ -0,0 +1,110 @@ +login(); + $this->add_lang('posting'); + + $crawler = $this->request('GET', 'posting.php?mode=post&f=2&sid=' . $this->sid); + $this->assertContains($this->lang('POST_TOPIC'), $crawler->filter('html')->text()); + + $hidden_fields = array(); + $hidden_fields[] = $crawler->filter('[type="hidden"]')->each(function ($node, $i) { + return array('name' => $node->getAttribute('name'), 'value' => $node->getAttribute('value')); + }); + + $test_message = 'This is a test topic posted by the testing framework.'; + $form_data = array( + 'subject' => 'Test Topic 1', + 'message' => $test_message, + 'post' => true, + 'f' => 2, + 'mode' => 'post', + 'sid' => $this->sid, + ); + + foreach ($hidden_fields as $fields) + { + foreach($fields as $field) + { + $form_data[$field['name']] = $field['value']; + } + } + + // Bypass time restriction that said that if the lastclick time (i.e. time when the form was opened) + // is not at least 2 seconds before submission, cancel the form + $form_data['lastclick'] = 0; + + // The add_form_key()/check_form_key() safeguards present a challenge because they require + // the timestamp created in add_form_key() to be sent as-is to check_form_key() but in check_form_key() + // it won't allow the current time to be the same as the timestamp it requires. + // As such, automated scripts like this one have to somehow bypass this without being able to change + // the timestamp. The only way I can think to do so is using sleep() + sleep(1); + + // I use a request because the form submission method does not allow you to send data that is not + // contained in one of the actual form fields that the browser sees (i.e. it ignores "hidden" inputs) + // Instead, I send it as a request with the submit button "post" set to true. + $crawler = $this->client->request('POST', 'posting.php', $form_data); + $this->assertContains($this->lang('POST_STORED'), $crawler->filter('html')->text()); + + $crawler = $this->request('GET', 'viewtopic.php?t=2&sid=' . $this->sid); + $this->assertContains($test_message, $crawler->filter('html')->text()); + } + + public function test_post_reply() + { + $this->login(); + $this->add_lang('posting'); + + $crawler = $this->request('GET', 'posting.php?mode=reply&t=2&f=2&sid=' . $this->sid); + $this->assertContains($this->lang('POST_REPLY'), $crawler->filter('html')->text()); + + $hidden_fields = array(); + $hidden_fields[] = $crawler->filter('[type="hidden"]')->each(function ($node, $i) { + return array('name' => $node->getAttribute('name'), 'value' => $node->getAttribute('value')); + }); + + $test_message = 'This is a test post posted by the testing framework.'; + $form_data = array( + 'subject' => 'Re: Test Topic 1', + 'message' => $test_message, + 'post' => true, + 't' => 2, + 'f' => 2, + 'mode' => 'reply', + 'sid' => $this->sid, + ); + + foreach ($hidden_fields as $fields) + { + foreach($fields as $field) + { + $form_data[$field['name']] = $field['value']; + } + } + + // For reasoning behind the following two commands, see the test_post_new_topic() test + $form_data['lastclick'] = 0; + sleep(1); + + // Submit the post + $crawler = $this->client->request('POST', 'posting.php', $form_data); + $this->assertContains($this->lang('POST_STORED'), $crawler->filter('html')->text()); + + $crawler = $this->request('GET', 'viewtopic.php?t=2&sid=' . $this->sid); + $this->assertContains($test_message, $crawler->filter('html')->text()); + } +} From 7dfe26dd781e7bd0438041058e2a1d95176e7836 Mon Sep 17 00:00:00 2001 From: David King Date: Sat, 1 Sep 2012 10:35:46 -0400 Subject: [PATCH 049/443] [task/functional] Allow tests to bypass certain restrictions with DEBUG_TEST PHPBB3-10758 --- phpBB/includes/functions.php | 2 +- phpBB/includes/functions_install.php | 5 ++++- tests/functional/posting_test.php | 10 +--------- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 5914831539..8e7e84bf83 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -2811,7 +2811,7 @@ function check_form_key($form_name, $timespan = false, $return_page = '', $trigg $diff = time() - $creation_time; // If creation_time and the time() now is zero we can assume it was not a human doing this (the check for if ($diff)... - if ($diff && ($diff <= $timespan || $timespan === -1)) + if (defined('DEBUG_TEST') || $diff && ($diff <= $timespan || $timespan === -1)) { $token_sid = ($user->data['user_id'] == ANONYMOUS && !empty($config['form_token_sid_guests'])) ? $user->session_id : ''; $key = sha1($creation_time . $user->data['user_form_salt'] . $form_name . $token_sid); diff --git a/phpBB/includes/functions_install.php b/phpBB/includes/functions_install.php index 89dfb7cd2f..2e10db6b24 100644 --- a/phpBB/includes/functions_install.php +++ b/phpBB/includes/functions_install.php @@ -551,10 +551,12 @@ function adjust_language_keys_callback($matches) * @param string $dbms The name of the DBAL class to use * @param array $load_extensions Array of additional extensions that should be loaded * @param bool $debug If the debug constants should be enabled by default or not +* @param bool $debug_test If the DEBUG_TEST constant should be added +* NOTE: Only for use within the testing framework * * @return string The output to write to the file */ -function phpbb_create_config_file_data($data, $dbms, $load_extensions, $debug = false) +function phpbb_create_config_file_data($data, $dbms, $load_extensions, $debug = false, $debug_test = false) { $load_extensions = implode(',', $load_extensions); @@ -584,6 +586,7 @@ function phpbb_create_config_file_data($data, $dbms, $load_extensions, $debug = { $config_data .= "@define('DEBUG', true);\n"; $config_data .= "@define('DEBUG_EXTRA', true);\n"; + $config_data .= "@define('DEBUG_TEST', true);\n"; } else { diff --git a/tests/functional/posting_test.php b/tests/functional/posting_test.php index 8d722361e0..f54a3591b2 100644 --- a/tests/functional/posting_test.php +++ b/tests/functional/posting_test.php @@ -47,13 +47,6 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case // is not at least 2 seconds before submission, cancel the form $form_data['lastclick'] = 0; - // The add_form_key()/check_form_key() safeguards present a challenge because they require - // the timestamp created in add_form_key() to be sent as-is to check_form_key() but in check_form_key() - // it won't allow the current time to be the same as the timestamp it requires. - // As such, automated scripts like this one have to somehow bypass this without being able to change - // the timestamp. The only way I can think to do so is using sleep() - sleep(1); - // I use a request because the form submission method does not allow you to send data that is not // contained in one of the actual form fields that the browser sees (i.e. it ignores "hidden" inputs) // Instead, I send it as a request with the submit button "post" set to true. @@ -96,9 +89,8 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case } } - // For reasoning behind the following two commands, see the test_post_new_topic() test + // For reasoning behind the following command, see the test_post_new_topic() test $form_data['lastclick'] = 0; - sleep(1); // Submit the post $crawler = $this->client->request('POST', 'posting.php', $form_data); From 4dd1bbc5879ae5fcae04341a9152e0366ed68bdd Mon Sep 17 00:00:00 2001 From: David King Date: Sat, 1 Sep 2012 10:53:01 -0400 Subject: [PATCH 050/443] [task/functional] Fixed DEBUG_TEST related issues PHPBB3-10758 --- phpBB/includes/functions_install.php | 6 +++++- tests/test_framework/phpbb_functional_test_case.php | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/phpBB/includes/functions_install.php b/phpBB/includes/functions_install.php index 2e10db6b24..eae136808c 100644 --- a/phpBB/includes/functions_install.php +++ b/phpBB/includes/functions_install.php @@ -586,7 +586,6 @@ function phpbb_create_config_file_data($data, $dbms, $load_extensions, $debug = { $config_data .= "@define('DEBUG', true);\n"; $config_data .= "@define('DEBUG_EXTRA', true);\n"; - $config_data .= "@define('DEBUG_TEST', true);\n"; } else { @@ -594,6 +593,11 @@ function phpbb_create_config_file_data($data, $dbms, $load_extensions, $debug = $config_data .= "// @define('DEBUG_EXTRA', true);\n"; } + if ($debug_test) + { + $config_data .= "@define('DEBUG_TEST', true);\n"; + } + return $config_data; } diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 2423299b7c..d35913e415 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -140,7 +140,7 @@ class phpbb_functional_test_case extends phpbb_test_case $this->do_request('create_table', $data); $this->do_request('config_file', $data); - file_put_contents($phpbb_root_path . "config.$phpEx", phpbb_create_config_file_data($data, self::$config['dbms'], array(), true)); + file_put_contents($phpbb_root_path . "config.$phpEx", phpbb_create_config_file_data($data, self::$config['dbms'], array(), true, true)); $this->do_request('final', $data); copy($phpbb_root_path . "config.$phpEx", $phpbb_root_path . "config_test.$phpEx"); From ce7cffcf9ebb21bccf1fae4da41a924708429e94 Mon Sep 17 00:00:00 2001 From: Fyorl Date: Tue, 11 Sep 2012 09:42:29 +0100 Subject: [PATCH 051/443] [ticket/11045] Removed file conflict tests for compress class PHPBB3-11045 --- tests/compress/compress_test.php | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/tests/compress/compress_test.php b/tests/compress/compress_test.php index ac8dd358d3..65094671e3 100644 --- a/tests/compress/compress_test.php +++ b/tests/compress/compress_test.php @@ -25,12 +25,6 @@ class phpbb_compress_test extends phpbb_test_case 'dir/subdir/4.txt', ); - protected $conflicts = array( - '1_1.txt', - '1_2.txt', - 'dir/2_1.txt', - ); - protected function setUp() { // Required for compress::add_file @@ -88,11 +82,6 @@ class phpbb_compress_test extends phpbb_test_case ); $compress->add_custom_file($this->path . 'dir/3.txt', 'dir/3.txt'); $compress->add_data(file_get_contents($this->path . 'dir/subdir/4.txt'), 'dir/subdir/4.txt'); - - // Add multiples of the same file to check conflicts are handled - $compress->add_file($this->path . '1.txt', $this->path); - $compress->add_file($this->path . '1.txt', $this->path); - $compress->add_file($this->path . 'dir/2.txt', $this->path); } protected function valid_extraction($extra = array()) @@ -152,7 +141,7 @@ class phpbb_compress_test extends phpbb_test_case $compress->mode = 'r'; $compress->open(); $compress->extract('tests/compress/' . self::EXTRACT_DIR); - $this->valid_extraction($this->conflicts); + $this->valid_extraction(); } /** @@ -168,6 +157,6 @@ class phpbb_compress_test extends phpbb_test_case $compress = new compress_zip('r', $zip); $compress->extract('tests/compress/' . self::EXTRACT_DIR); - $this->valid_extraction($this->conflicts); + $this->valid_extraction(); } } From f7a6169184ed67d0f25fcccb57309580b4603635 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 27 Sep 2012 11:19:22 +0200 Subject: [PATCH 052/443] [ticket/11122] Move Acyd Burn, Arty and Toonarmy to former contributors PHPBB3-11122 --- phpBB/docs/AUTHORS | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/phpBB/docs/AUTHORS b/phpBB/docs/AUTHORS index 446b204a08..c623bbb988 100644 --- a/phpBB/docs/AUTHORS +++ b/phpBB/docs/AUTHORS @@ -22,15 +22,12 @@ involved in phpBB. phpBB Lead Developer: naderman (Nils Adermann) -phpBB Developers: Acyd Burn (Meik Sievertsen) [Lead 09/2005 - 01/2010] - Arty (Vjacheslav Trushkin) - bantu (Andreas Fischer) - imkingdavid (David King) +phpBB Developers: bantu (Andreas Fischer) igorw (Igor Wiedler) + imkingdavid (David King) nickvergessen (Joas Schilling) Oleg (Oleg Pudeyev) rxu (Ruslan Uzdenov) - ToonArmy (Chris Smith) Contributions by: leviatan21 (Gabriel Vazquez) Raimon (Raimon Meuldijk) @@ -39,13 +36,16 @@ Contributions by: leviatan21 (Gabriel Vazquez) -- Former Contributors -- -phpBB Project Manager: theFinn (James Atkinson) [Founder - 04/2007] +phpBB Project Manager: theFinn (James Atkinson) [Founder - 04/2007] SHS` (Jonathan Stanley) -phpBB Lead Developer: psoTFX (Paul S. Owen) [2001 - 09/2005] +phpBB Lead Developer: Acyd Burn (Meik Sievertsen) [09/2005 - 01/2010] + psoTFX (Paul S. Owen) [2001 - 09/2005] phpBB Developers: A_Jelly_Doughnut (Josh Woody) [01/2010 - 11/2010] + Acyd Burn (Meik Sievertsen) [02/2003 - 09/2005] APTX (Marek A. Ruszczyński) [12/2007 - 04/2011] + Arty (Vjacheslav Trushkin) [02/2012 - 07/2012] Ashe (Ludovic Arnaud) [10/2002 - 11/2003, 06/2006 - 10/2006] BartVB (Bart van Bragt) [11/2000 - 03/2006] ckwalsh (Cullen Walsh) [01/2010 - 07/2011] @@ -54,6 +54,7 @@ phpBB Developers: A_Jelly_Doughnut (Josh Woody) [01/2010 - 11/2010] GrahamJE (Graham Eames) [09/2005 - 11/2006] kellanved (Henry Sudhof) [04/2007 - 03/2011] TerraFrost (Jim Wigginton) [04/2009 - 01/2011] + ToonArmy (Chris Smith) [06/2008 - 11/2011] Vic D'Elfant (Vic D'Elfant) [04/2007 - 04/2009] -- Copyrights -- From 1f89fc9cb6eeaeb2e1b5b3063d76edc82ae9f131 Mon Sep 17 00:00:00 2001 From: Senky Date: Mon, 1 Oct 2012 15:38:16 +0200 Subject: [PATCH 053/443] [ticket/11112] updating links to phpbb.com to use SSL PHPBB3-11112 --- phpBB/adm/index.php | 2 +- phpBB/includes/functions.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/phpBB/adm/index.php b/phpBB/adm/index.php index 3c984f8290..2e4089c02e 100644 --- a/phpBB/adm/index.php +++ b/phpBB/adm/index.php @@ -199,7 +199,7 @@ function adm_page_footer($copyright_html = true) 'DEBUG_OUTPUT' => (defined('DEBUG')) ? $debug_output : '', 'TRANSLATION_INFO' => (!empty($user->lang['TRANSLATION_INFO'])) ? $user->lang['TRANSLATION_INFO'] : '', 'S_COPYRIGHT_HTML' => $copyright_html, - 'CREDIT_LINE' => $user->lang('POWERED_BY', 'phpBB® Forum Software © phpBB Group'), + 'CREDIT_LINE' => $user->lang('POWERED_BY', 'phpBB® Forum Software © phpBB Group'), 'VERSION' => $config['version']) ); diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 8e7e84bf83..ca58220619 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3921,7 +3921,7 @@ function msg_handler($errno, $msg_text, $errfile, $errline) echo '
      '; echo ' '; echo ' '; echo ''; echo ''; @@ -4741,7 +4741,7 @@ function page_footer($run_cron = true) $template->assign_vars(array( 'DEBUG_OUTPUT' => (defined('DEBUG')) ? $debug_output : '', 'TRANSLATION_INFO' => (!empty($user->lang['TRANSLATION_INFO'])) ? $user->lang['TRANSLATION_INFO'] : '', - 'CREDIT_LINE' => $user->lang('POWERED_BY', 'phpBB® Forum Software © phpBB Group'), + 'CREDIT_LINE' => $user->lang('POWERED_BY', 'phpBB® Forum Software © phpBB Group'), 'U_ACP' => ($auth->acl_get('a_') && !empty($user->data['is_registered'])) ? append_sid("{$phpbb_root_path}adm/index.$phpEx", false, true, $user->session_id) : '') ); From dbeace22c802065994797ea7ef71176ac183f138 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Tue, 2 Oct 2012 14:58:20 +0200 Subject: [PATCH 054/443] [ticket/11131] Correctly use indefinite article for "warning". PHPBB3-11131 --- phpBB/language/en/acp/board.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/language/en/acp/board.php b/phpBB/language/en/acp/board.php index f24376f8aa..ccd12fcb6a 100644 --- a/phpBB/language/en/acp/board.php +++ b/phpBB/language/en/acp/board.php @@ -53,7 +53,7 @@ $lang = array_merge($lang, array( 'SYSTEM_TIMEZONE' => 'Guest timezone', 'SYSTEM_TIMEZONE_EXPLAIN' => 'Timezone to use for displaying times to users who are not logged in (guests, bots). Logged in users set their timezone during registration and can change it in their user control panel.', 'WARNINGS_EXPIRE' => 'Warning duration', - 'WARNINGS_EXPIRE_EXPLAIN' => 'Number of days that will elapse before the warning will automatically expire from a user’s record. Set this value to 0 to make warnings permanent.', + 'WARNINGS_EXPIRE_EXPLAIN' => 'Number of days that will elapse before a warning will automatically expire from a user’s record. Set this value to 0 to make warnings permanent.', )); // Board Features From 95d02d74ac6d71578a98e8850140d9a6cad7e852 Mon Sep 17 00:00:00 2001 From: Vinny Date: Fri, 5 Oct 2012 21:18:59 -0300 Subject: [PATCH 055/443] [ticket/11135] Full replacement of credit link to https PHPBB3-11135 --- phpBB/adm/style/install_footer.html | 2 +- phpBB/install/convertors/convert_phpbb20.php | 2 +- phpBB/install/database_update.php | 2 +- phpBB/install/index.php | 2 +- phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html | 2 +- phpBB/styles/prosilver/template/viewtopic_print.html | 2 +- phpBB/styles/prosilver/theme/stylesheet.css | 2 +- phpBB/styles/subsilver2/template/ucp_pm_viewmessage_print.html | 2 +- phpBB/styles/subsilver2/template/viewtopic_print.html | 2 +- phpBB/styles/subsilver2/theme/stylesheet.css | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/phpBB/adm/style/install_footer.html b/phpBB/adm/style/install_footer.html index 26a3c6ab3d..319f7e06c7 100644 --- a/phpBB/adm/style/install_footer.html +++ b/phpBB/adm/style/install_footer.html @@ -8,7 +8,7 @@ diff --git a/phpBB/install/convertors/convert_phpbb20.php b/phpBB/install/convertors/convert_phpbb20.php index 7d6fed6164..960cc5b335 100644 --- a/phpBB/install/convertors/convert_phpbb20.php +++ b/phpBB/install/convertors/convert_phpbb20.php @@ -33,7 +33,7 @@ $convertor_data = array( 'forum_name' => 'phpBB 2.0.x', 'version' => '1.0.3', 'phpbb_version' => '3.0.11', - 'author' => 'phpBB Group', + 'author' => 'phpBB Group', 'dbms' => $dbms, 'dbhost' => $dbhost, 'dbport' => $dbport, diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 5a186d0eeb..40837145ba 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -527,7 +527,7 @@ function _print_footer() diff --git a/phpBB/install/index.php b/phpBB/install/index.php index 5135e2dbd8..ad46e273c2 100644 --- a/phpBB/install/index.php +++ b/phpBB/install/index.php @@ -569,7 +569,7 @@ class module echo ' '; echo ' '; echo ' '; echo ''; echo ''; diff --git a/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html b/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html index d92abb06dd..67e14defc3 100644 --- a/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html +++ b/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html @@ -48,7 +48,7 @@ diff --git a/phpBB/styles/prosilver/template/viewtopic_print.html b/phpBB/styles/prosilver/template/viewtopic_print.html index 0fd0e6dfa6..39d2d76394 100644 --- a/phpBB/styles/prosilver/template/viewtopic_print.html +++ b/phpBB/styles/prosilver/template/viewtopic_print.html @@ -44,7 +44,7 @@ diff --git a/phpBB/styles/prosilver/theme/stylesheet.css b/phpBB/styles/prosilver/theme/stylesheet.css index 4a7356fbaa..40620179a1 100644 --- a/phpBB/styles/prosilver/theme/stylesheet.css +++ b/phpBB/styles/prosilver/theme/stylesheet.css @@ -3,7 +3,7 @@ Style name: prosilver (the default phpBB 3.0.x style) Based on style: Original author: Tom Beddard ( http://www.subblue.com/ ) - Modified by: phpBB Group ( http://www.phpbb.com/ ) + Modified by: phpBB Group ( https://www.phpbb.com/ ) -------------------------------------------------------------- */ diff --git a/phpBB/styles/subsilver2/template/ucp_pm_viewmessage_print.html b/phpBB/styles/subsilver2/template/ucp_pm_viewmessage_print.html index 24194e4c26..cd55c16a50 100644 --- a/phpBB/styles/subsilver2/template/ucp_pm_viewmessage_print.html +++ b/phpBB/styles/subsilver2/template/ucp_pm_viewmessage_print.html @@ -114,7 +114,7 @@ hr.sep {
      - +
      {S_TIMEZONE}
      Powered by phpBB® Forum Software © phpBB Group
      http://www.phpbb.com/
      Powered by phpBB® Forum Software © phpBB Group
      https://www.phpbb.com/
      diff --git a/phpBB/styles/subsilver2/template/viewtopic_print.html b/phpBB/styles/subsilver2/template/viewtopic_print.html index 964c95f677..1ca1eccc99 100644 --- a/phpBB/styles/subsilver2/template/viewtopic_print.html +++ b/phpBB/styles/subsilver2/template/viewtopic_print.html @@ -128,7 +128,7 @@ hr.sep { {S_TIMEZONE} - Powered by phpBB® Forum Software © phpBB Group
      http://www.phpbb.com/
      + Powered by phpBB® Forum Software © phpBB Group
      https://www.phpbb.com/
      diff --git a/phpBB/styles/subsilver2/theme/stylesheet.css b/phpBB/styles/subsilver2/theme/stylesheet.css index 444104ae3c..177a988e93 100644 --- a/phpBB/styles/subsilver2/theme/stylesheet.css +++ b/phpBB/styles/subsilver2/theme/stylesheet.css @@ -3,7 +3,7 @@ Style name: subsilver2 Based on style: subSilver (the default phpBB 2.0.x style) Original author: Tom Beddard ( http://www.subblue.com/ ) - Modified by: phpBB Group ( http://www.phpbb.com/ ) + Modified by: phpBB Group ( https://www.phpbb.com/ ) -------------------------------------------------------------- */ From d434672dde1592f51013459357c25ed49887d12f Mon Sep 17 00:00:00 2001 From: Senky Date: Mon, 23 Jul 2012 14:28:47 +0200 Subject: [PATCH 056/443] [ticket/10967] adding $root_path to posting_get_topic_icons PHPBB3-10967 --- phpBB/includes/functions_posting.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index 68b6199cf5..aa15593a19 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -288,13 +288,15 @@ function posting_gen_topic_icons($mode, $icon_id) if (sizeof($icons)) { + $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_root_path; + foreach ($icons as $id => $data) { if ($data['display']) { $template->assign_block_vars('topic_icon', array( 'ICON_ID' => $id, - 'ICON_IMG' => $phpbb_root_path . $config['icons_path'] . '/' . $data['img'], + 'ICON_IMG' => $root_path . $config['icons_path'] . '/' . $data['img'], 'ICON_WIDTH' => $data['width'], 'ICON_HEIGHT' => $data['height'], @@ -2637,7 +2639,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u * - 'topic_last_post_subject' * - 'topic_last_poster_name' * - 'topic_last_poster_colour' -* @param int $bump_time The time at which topic was bumped, usually it is a current time as obtained via time(). +* @param int $bump_time The time at which topic was bumped, usually it is a current time as obtained via time(). * @return string An URL to the bumped topic, example: ./viewtopic.php?forum_id=1&topic_id=2&p=3#p3 */ function phpbb_bump_topic($forum_id, $topic_id, $post_data, $bump_time = false) From d376348acf271ab0e2bcba4e8eb5993192d0ef87 Mon Sep 17 00:00:00 2001 From: westr Date: Tue, 16 Oct 2012 12:44:33 +0100 Subject: [PATCH 057/443] [ticket/11093] acp_users_overview.html has a wrongly placed Amended the closing dd tag to the appropriate line: line 145 instead of 141 PHPBB3-11093 --- phpBB/adm/style/acp_users_overview.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/phpBB/adm/style/acp_users_overview.html b/phpBB/adm/style/acp_users_overview.html index e2dcdb6307..ba350a13fb 100644 --- a/phpBB/adm/style/acp_users_overview.html +++ b/phpBB/adm/style/acp_users_overview.html @@ -142,10 +142,11 @@

      {L_DELETE_USER_EXPLAIN}
      -
      + {L_USER_NO_POSTS_TO_DELETE} +

      From c630480ca1a426cb0897be35626baac2694fccf5 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 17 Oct 2012 15:03:06 -0400 Subject: [PATCH 058/443] [ticket/10848] Redirect from adm to installer correctly. PHPBB3-10848 --- phpBB/common.php | 6 +++- phpBB/includes/functions.php | 30 ++++++++++++++++++++ tests/functions/clean_path_test.php | 44 +++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 tests/functions/clean_path_test.php diff --git a/phpBB/common.php b/phpBB/common.php index 491addc5e0..bdb33707cc 100644 --- a/phpBB/common.php +++ b/phpBB/common.php @@ -38,10 +38,14 @@ if (!defined('PHPBB_INSTALLED')) $script_name = (!empty($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : getenv('REQUEST_URI'); } + // $phpbb_root_path accounts for redirects from e.g. /adm + $script_path = trim(dirname($script_name)) . '/' . $phpbb_root_path . 'install/index.' . $phpEx; // Replace any number of consecutive backslashes and/or slashes with a single slash // (could happen on some proxy setups and/or Windows servers) - $script_path = trim(dirname($script_name)) . '/install/index.' . $phpEx; $script_path = preg_replace('#[\\\\/]{2,}#', '/', $script_path); + // Eliminate . and .. from the path + require($phpbb_root_path . 'includes/functions.' . $phpEx); + $script_path = clean_path($script_path); $url = (($secure) ? 'https://' : 'http://') . $server_name; diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index ca58220619..2391b45038 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -1176,6 +1176,36 @@ else } } +/** +* Eliminates useless . and .. components from specified path. +* +* @param string $path Path to clean +* @return string Cleaned path +*/ +function clean_path($path) +{ + $exploded = explode('/', $path); + $filtered = array(); + foreach ($exploded as $part) + { + if ($part === '.' && !empty($filtered)) + { + continue; + } + + if ($part === '..' && !empty($filtered) && $filtered[sizeof($filtered) - 1] !== '..') + { + array_pop($filtered); + } + else + { + $filtered[] = $part; + } + } + $path = implode('/', $filtered); + return $path; +} + if (!function_exists('htmlspecialchars_decode')) { /** diff --git a/tests/functions/clean_path_test.php b/tests/functions/clean_path_test.php new file mode 100644 index 0000000000..4c8fe54909 --- /dev/null +++ b/tests/functions/clean_path_test.php @@ -0,0 +1,44 @@ +assertEquals($expected, $output); + } +} From bb09cd9c8e76ac3af848d09db8ea1928dab66158 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 17 Oct 2012 15:13:35 -0400 Subject: [PATCH 059/443] [ticket/10848] Add phpbb_ prefix. PHPBB3-10848 --- phpBB/common.php | 2 +- phpBB/includes/functions.php | 2 +- tests/functions/clean_path_test.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/phpBB/common.php b/phpBB/common.php index bdb33707cc..5849d48453 100644 --- a/phpBB/common.php +++ b/phpBB/common.php @@ -45,7 +45,7 @@ if (!defined('PHPBB_INSTALLED')) $script_path = preg_replace('#[\\\\/]{2,}#', '/', $script_path); // Eliminate . and .. from the path require($phpbb_root_path . 'includes/functions.' . $phpEx); - $script_path = clean_path($script_path); + $script_path = phpbb_clean_path($script_path); $url = (($secure) ? 'https://' : 'http://') . $server_name; diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 2391b45038..65d8be32ad 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -1182,7 +1182,7 @@ else * @param string $path Path to clean * @return string Cleaned path */ -function clean_path($path) +function phpbb_clean_path($path) { $exploded = explode('/', $path); $filtered = array(); diff --git a/tests/functions/clean_path_test.php b/tests/functions/clean_path_test.php index 4c8fe54909..bcbe9838d9 100644 --- a/tests/functions/clean_path_test.php +++ b/tests/functions/clean_path_test.php @@ -37,7 +37,7 @@ class phpbb_clean_path_test extends phpbb_test_case */ public function test_clean_path($input, $expected) { - $output = clean_path($input); + $output = phpbb_clean_path($input); $this->assertEquals($expected, $output); } From b283df8241c3d8fc5f2684e37d8a0f237df39c4f Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 17 Oct 2012 22:35:36 -0400 Subject: [PATCH 060/443] [ticket/10848] Move include up. PHPBB3-10848 --- phpBB/common.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/phpBB/common.php b/phpBB/common.php index 5849d48453..31ca746924 100644 --- a/phpBB/common.php +++ b/phpBB/common.php @@ -26,6 +26,8 @@ if (file_exists($phpbb_root_path . 'config.' . $phpEx)) if (!defined('PHPBB_INSTALLED')) { // Redirect the user to the installer + require($phpbb_root_path . 'includes/functions.' . $phpEx); + // We have to generate a full HTTP/1.1 header here since we can't guarantee to have any of the information // available as used by the redirect function $server_name = (!empty($_SERVER['HTTP_HOST'])) ? strtolower($_SERVER['HTTP_HOST']) : ((!empty($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : getenv('SERVER_NAME')); @@ -44,7 +46,6 @@ if (!defined('PHPBB_INSTALLED')) // (could happen on some proxy setups and/or Windows servers) $script_path = preg_replace('#[\\\\/]{2,}#', '/', $script_path); // Eliminate . and .. from the path - require($phpbb_root_path . 'includes/functions.' . $phpEx); $script_path = phpbb_clean_path($script_path); $url = (($secure) ? 'https://' : 'http://') . $server_name; From 88bd7292f16817d681264b9f06ff30c2a38c1da4 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Mon, 29 Oct 2012 13:39:45 -0400 Subject: [PATCH 061/443] [ticket/11158] Revert old fix in PHPBB3-10186. Revert "[ticket/10186] UCP signature panel displays when not authed for signatures" This reverts commit f6fa52540c0fb20d79b4d59cb08c49484d9f3116. PHPBB3-10186 PHPBB3-11158 --- phpBB/ucp.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/phpBB/ucp.php b/phpBB/ucp.php index 45caeb12ea..520ab3caad 100644 --- a/phpBB/ucp.php +++ b/phpBB/ucp.php @@ -320,12 +320,6 @@ if (!$config['allow_topic_notify'] && !$config['allow_forum_notify']) $module->set_display('main', 'subscribed', false); } -// Do not display signature panel if not authed to do so -if (!$auth->acl_get('u_sig')) -{ - $module->set_display('profile', 'signature', false); -} - // Select the active module $module->set_active($id, $mode); From 5f5d395c625fe0257e7bca5d787424808f7649cc Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Mon, 29 Oct 2012 13:58:24 -0400 Subject: [PATCH 062/443] [ticket/11158] Require acl_u_sig for ucp signature module. PHPBB3-11158 --- phpBB/includes/ucp/info/ucp_profile.php | 2 +- phpBB/install/database_update.php | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/phpBB/includes/ucp/info/ucp_profile.php b/phpBB/includes/ucp/info/ucp_profile.php index d19b80f4c0..4591776768 100644 --- a/phpBB/includes/ucp/info/ucp_profile.php +++ b/phpBB/includes/ucp/info/ucp_profile.php @@ -21,7 +21,7 @@ class ucp_profile_info 'version' => '1.0.0', 'modes' => array( 'profile_info' => array('title' => 'UCP_PROFILE_PROFILE_INFO', 'auth' => '', 'cat' => array('UCP_PROFILE')), - 'signature' => array('title' => 'UCP_PROFILE_SIGNATURE', 'auth' => '', 'cat' => array('UCP_PROFILE')), + 'signature' => array('title' => 'UCP_PROFILE_SIGNATURE', 'auth' => 'acl_u_sig', 'cat' => array('UCP_PROFILE')), 'avatar' => array('title' => 'UCP_PROFILE_AVATAR', 'auth' => 'cfg_allow_avatar && (cfg_allow_avatar_local || cfg_allow_avatar_remote || cfg_allow_avatar_upload || cfg_allow_avatar_remote_upload)', 'cat' => array('UCP_PROFILE')), 'reg_details' => array('title' => 'UCP_PROFILE_REG_DETAILS', 'auth' => '', 'cat' => array('UCP_PROFILE')), ), diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 40837145ba..099ab6aeb5 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -1005,6 +1005,8 @@ function database_update_info() ), // No changes from 3.0.11-RC2 to 3.0.11 '3.0.11-RC2' => array(), + // No changes from 3.0.11 to 3.0.12-RC1 + '3.0.11' => array(), /** @todo DROP LOGIN_ATTEMPT_TABLE.attempt_id in 3.0.12-RC1 */ ); @@ -2108,6 +2110,16 @@ function change_database_data(&$no_updates, $version) // No changes from 3.0.11-RC2 to 3.0.11 case '3.0.11-RC2': break; + + // Changes from 3.0.11 to 3.0.12-RC1 + case '3.0.11': + $sql = 'UPDATE ' . MODULES_TABLE . ' + SET module_auth = \'acl_u_sig\' + WHERE module_class = \'ucp\' + AND module_basename = \'profile\' + AND module_mode = \'signature\''; + _sql($sql, $errored, $error_ary); + break; } } From fd6ee50e06cb48c9e3a476bf23285875484ff5f7 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 2 Nov 2012 16:05:53 -0400 Subject: [PATCH 063/443] [ticket/11162] Extract existing behavior into a function and add a test. PHPBB3-11162 --- phpBB/includes/functions.php | 24 ++++++- tests/functions/fixtures/duplicates.xml | 56 +++++++++++++++ .../update_rows_avoiding_duplicates_test.php | 71 +++++++++++++++++++ 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 tests/functions/fixtures/duplicates.xml create mode 100644 tests/functions/update_rows_avoiding_duplicates_test.php diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 65d8be32ad..8608c6ca4f 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -1297,6 +1297,28 @@ function tz_select($default = '', $truncate = false) return $tz_select; } +/** +* Updates rows in given table from a set of values to a new value. +* If this results in rows violating uniqueness constraints, the duplicate +* rows are eliminated. +* +* @param dbal $db Database object +* @param string $table Table on which to perform the update +* @param string $column Column whose values to change +* @param array $from_values An array of values that should be changed +* @param int $to_value The new value +* @return null +*/ +function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_values, $to_value) +{ + $db->sql_return_on_error(true); + $condition = $db->sql_in_set($column, $from_values); + $db->sql_query('UPDATE ' . $table . ' SET ' . $column . ' = ' . (int) $to_value. ' WHERE ' . $condition); + $db->sql_return_on_error(false); + + $db->sql_query('DELETE FROM ' . $table . ' WHERE ' . $condition); +} + // Functions handling topic/post tracking/marking /** @@ -3355,7 +3377,7 @@ function parse_cfg_file($filename, $lines = false) $parsed_items[$key] = $value; } - + if (isset($parsed_items['inherit_from']) && isset($parsed_items['name']) && $parsed_items['inherit_from'] == $parsed_items['name']) { unset($parsed_items['inherit_from']); diff --git a/tests/functions/fixtures/duplicates.xml b/tests/functions/fixtures/duplicates.xml new file mode 100644 index 0000000000..bc08016a8f --- /dev/null +++ b/tests/functions/fixtures/duplicates.xml @@ -0,0 +1,56 @@ + + + + user_id + topic_id + notify_status + + + + 1 + 1 + 1 + + + + + 2 + 2 + 1 + + + 3 + 3 + 1 + + + + + 1 + 4 + 1 + + + 1 + 5 + 1 + + + + + 1 + 6 + 1 + + + 1 + 7 + 1 + + + 2 + 6 + 1 + +
      +
      diff --git a/tests/functions/update_rows_avoiding_duplicates_test.php b/tests/functions/update_rows_avoiding_duplicates_test.php new file mode 100644 index 0000000000..0e949717d2 --- /dev/null +++ b/tests/functions/update_rows_avoiding_duplicates_test.php @@ -0,0 +1,71 @@ +createXMLDataSet(dirname(__FILE__).'/fixtures/duplicates.xml'); + } + + public static function fixture_data() + { + return array( + // description + // from array + // to value + // expected count with to value post update + array( + 'trivial', + array(1), + 10, + 1, + ), + array( + 'no conflict', + array(2), + 3, + 2, + ), + array( + 'conflict', + array(4), + 5, + 1, + ), + array( + 'conflict and no conflict', + array(6), + 7, + 2, + ), + ); + } + + /** + * @dataProvider fixture_data + */ + public function test_trivial_update($description, $from, $to, $expected_result_count) + { + $db = $this->new_dbal(); + + phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $from, $to); + + $sql = 'SELECT count(*) AS count + FROM ' . TOPICS_WATCH_TABLE . ' + WHERE topic_id = ' . $db->sql_escape($to); + $result = $db->sql_query($sql); + $result_count = $db->sql_fetchfield('count'); + $db->sql_freeresult($result); + + $this->assertEquals($expected_result_count, $result_count); + } +} From 0dbd569385f26d62086ff64e8f45b6aab6bfb8b0 Mon Sep 17 00:00:00 2001 From: Unknown Bliss Date: Sun, 4 Nov 2012 13:27:47 +0000 Subject: [PATCH 064/443] [ticket/11164] Update composer.phar PHPBB3-11164 --- composer.phar | Bin 533673 -> 634856 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/composer.phar b/composer.phar index 8b6eddbf21a06da1b6cc983749e5f3a755c674d5..af7b8c1a67f6aebf54ce26b4a973a5ccb150cd8a 100755 GIT binary patch delta 91589 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Π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 delta 22743 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 From a7babc211c975dc6aead4740046afd593d90cc78 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 6 Nov 2012 10:41:06 -0500 Subject: [PATCH 065/443] [ticket/11159] static public is the currently approved order. PHPBB3-11159 --- tests/dbal/select_test.php | 16 ++++++++-------- tests/dbal/write_test.php | 4 ++-- tests/privmsgs/delete_user_pms_test.php | 2 +- tests/request/request_var_test.php | 2 +- tests/security/extract_current_page_test.php | 2 +- tests/security/redirect_test.php | 2 +- tests/template/template_test.php | 4 ++-- .../test_framework/phpbb_database_test_case.php | 2 +- tests/text_processing/make_clickable_test.php | 2 +- tests/utf/utf8_clean_string_test.php | 2 +- 10 files changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/dbal/select_test.php b/tests/dbal/select_test.php index 81cd13b006..6dbab05a41 100644 --- a/tests/dbal/select_test.php +++ b/tests/dbal/select_test.php @@ -17,7 +17,7 @@ class phpbb_dbal_select_test extends phpbb_database_test_case return $this->createXMLDataSet(dirname(__FILE__).'/fixtures/three_users.xml'); } - public static function return_on_error_select_data() + static public function return_on_error_select_data() { return array( array('phpbb_users', "username_clean = 'bertie'", array(array('username_clean' => 'bertie'))), @@ -44,7 +44,7 @@ class phpbb_dbal_select_test extends phpbb_database_test_case $this->assertEquals($expected, $db->sql_fetchrowset($result)); } - public static function fetchrow_data() + static public function fetchrow_data() { return array( array('', array(array('username_clean' => 'barfoo'), @@ -95,7 +95,7 @@ class phpbb_dbal_select_test extends phpbb_database_test_case $db->sql_freeresult($result); } - public static function fetchfield_data() + static public function fetchfield_data() { return array( array('', array('barfoo', 'foobar', 'bertie')), @@ -125,7 +125,7 @@ class phpbb_dbal_select_test extends phpbb_database_test_case $this->assertEquals($expected, $ary); } - public static function fetchfield_seek_data() + static public function fetchfield_seek_data() { return array( array(1, 'foobar'), @@ -151,7 +151,7 @@ class phpbb_dbal_select_test extends phpbb_database_test_case $this->assertEquals($expected, $field); } - public static function query_limit_data() + static public function query_limit_data() { return array( array(0, 0, array(array('username_clean' => 'barfoo'), @@ -192,7 +192,7 @@ class phpbb_dbal_select_test extends phpbb_database_test_case $this->assertEquals($expected, $ary); } - public static function like_expression_data() + static public function like_expression_data() { // * = any_char; # = one_char return array( @@ -229,7 +229,7 @@ class phpbb_dbal_select_test extends phpbb_database_test_case $db->sql_freeresult($result); } - public static function in_set_data() + static public function in_set_data() { return array( array('user_id', 3, false, false, array(array('username_clean' => 'bertie'))), @@ -303,7 +303,7 @@ class phpbb_dbal_select_test extends phpbb_database_test_case $db->sql_freeresult($result); } - public static function build_array_data() + static public function build_array_data() { return array( array(array('username_clean' => 'barfoo'), array(array('username_clean' => 'barfoo'))), diff --git a/tests/dbal/write_test.php b/tests/dbal/write_test.php index 596c50a220..ecfd774896 100644 --- a/tests/dbal/write_test.php +++ b/tests/dbal/write_test.php @@ -16,7 +16,7 @@ class phpbb_dbal_write_test extends phpbb_database_test_case return $this->createXMLDataSet(dirname(__FILE__).'/fixtures/config.xml'); } - public static function build_array_insert_data() + static public function build_array_insert_data() { return array( array(array( @@ -104,7 +104,7 @@ class phpbb_dbal_write_test extends phpbb_database_test_case $db->sql_freeresult($result); } - public static function update_data() + static public function update_data() { return array( array( diff --git a/tests/privmsgs/delete_user_pms_test.php b/tests/privmsgs/delete_user_pms_test.php index 265df1596a..f705825262 100644 --- a/tests/privmsgs/delete_user_pms_test.php +++ b/tests/privmsgs/delete_user_pms_test.php @@ -16,7 +16,7 @@ class phpbb_privmsgs_delete_user_pms_test extends phpbb_database_test_case return $this->createXMLDataSet(dirname(__FILE__).'/fixtures/delete_user_pms.xml'); } - public static function delete_user_pms_data() + static public function delete_user_pms_data() { return array( // array( diff --git a/tests/request/request_var_test.php b/tests/request/request_var_test.php index 8e609c00af..0c07fe11a3 100644 --- a/tests/request/request_var_test.php +++ b/tests/request/request_var_test.php @@ -73,7 +73,7 @@ class phpbb_request_request_var_test extends phpbb_test_case unset($_GET[$var], $_POST[$var], $_REQUEST[$var], $_COOKIE[$var]); } - public static function request_variables() + static public function request_variables() { return array( // strings diff --git a/tests/security/extract_current_page_test.php b/tests/security/extract_current_page_test.php index 4911f7b452..0f5128884b 100644 --- a/tests/security/extract_current_page_test.php +++ b/tests/security/extract_current_page_test.php @@ -14,7 +14,7 @@ require_once dirname(__FILE__) . '/../../phpBB/includes/session.php'; class phpbb_security_extract_current_page_test extends phpbb_security_test_base { - public static function security_variables() + static public function security_variables() { return array( array('http://localhost/phpBB/index.php', 'mark=forums&x=">', 'mark=forums&x=%22%3E%3Cscript%3Ealert(/XSS/);%3C/script%3E'), diff --git a/tests/security/redirect_test.php b/tests/security/redirect_test.php index 4848a938c6..872a331dc7 100644 --- a/tests/security/redirect_test.php +++ b/tests/security/redirect_test.php @@ -14,7 +14,7 @@ require_once dirname(__FILE__) . '/../../phpBB/includes/session.php'; class phpbb_security_redirect_test extends phpbb_security_test_base { - public static function provider() + static public function provider() { // array(Input -> redirect(), expected triggered error (else false), expected returned result url (else false)) return array( diff --git a/tests/template/template_test.php b/tests/template/template_test.php index aaee7bb4a0..9b3c6ac245 100644 --- a/tests/template/template_test.php +++ b/tests/template/template_test.php @@ -94,7 +94,7 @@ class phpbb_template_template_test extends phpbb_test_case /** * @todo put test data into templates/xyz.test */ - public static function template_data() + static public function template_data() { return array( /* @@ -419,7 +419,7 @@ class phpbb_template_template_test extends phpbb_test_case $GLOBALS['config']['tpl_allow_php'] = false; } - public static function alter_block_array_data() + static public function alter_block_array_data() { return array( array( diff --git a/tests/test_framework/phpbb_database_test_case.php b/tests/test_framework/phpbb_database_test_case.php index bb86df0ef0..75a3c0944b 100644 --- a/tests/test_framework/phpbb_database_test_case.php +++ b/tests/test_framework/phpbb_database_test_case.php @@ -137,7 +137,7 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test * * @return string The string with the specified match converted to uppercase */ - public static function to_upper($matches) + static public function to_upper($matches) { return $matches[1] . strtoupper($matches[2]) . $matches[3]; } diff --git a/tests/text_processing/make_clickable_test.php b/tests/text_processing/make_clickable_test.php index 8697907311..db0812319d 100644 --- a/tests/text_processing/make_clickable_test.php +++ b/tests/text_processing/make_clickable_test.php @@ -12,7 +12,7 @@ require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php'; class phpbb_text_processing_make_clickable_test extends phpbb_test_case { - public static function make_clickable_data() + static public function make_clickable_data() { // value => whether it should work $prefix_texts = array( diff --git a/tests/utf/utf8_clean_string_test.php b/tests/utf/utf8_clean_string_test.php index 70bd549d5b..5ebf6409af 100644 --- a/tests/utf/utf8_clean_string_test.php +++ b/tests/utf/utf8_clean_string_test.php @@ -11,7 +11,7 @@ require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php'; class phpbb_utf_utf8_clean_string_test extends phpbb_test_case { - public static function cleanable_strings() + static public function cleanable_strings() { return array( array('MiXed CaSe', 'mixed case', 'Checking case folding'), From 87a80e70da33a4730d1e16bd255b929d086f3151 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 6 Nov 2012 17:46:54 -0500 Subject: [PATCH 066/443] [ticket/11081] Drop duplicated in subsilver captcha qa template. PHPBB3-11081 --- phpBB/styles/subsilver2/template/captcha_qa.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/styles/subsilver2/template/captcha_qa.html b/phpBB/styles/subsilver2/template/captcha_qa.html index acc9cdcdfb..3a5778b33e 100644 --- a/phpBB/styles/subsilver2/template/captcha_qa.html +++ b/phpBB/styles/subsilver2/template/captcha_qa.html @@ -3,6 +3,6 @@ {QA_CONFIRM_QUESTION}:
      {L_CONFIRM_QUESTION_EXPLAIN} - tabindex="{$CAPTCHA_TAB_INDEX}" /> + tabindex="{$CAPTCHA_TAB_INDEX}" /> From 399662d2afa58dfd631128e3eac033d90464f794 Mon Sep 17 00:00:00 2001 From: Carlo Date: Tue, 28 Aug 2012 09:56:59 +0200 Subject: [PATCH 067/443] [ticket/10897] Bot list updated 'Baidu [Spider]' updated. 'Bing [Bot]' fixed only identation. 'Exabot [Bot]' changed because there is used also 'Exabot-Thumbnails' user agent. 'NG-Search [Bot]' no longer exists. 'Nutch/CVS [Bot]' is the same of 'Nutch [Bot]'. 'OmniExplorer [Bot]' no longer exists. 'Seekport [Bot]' no longer exists. 'Synoo [Bot]' no longer exists. 'Voyager [Bot]' updated. 'W3C [Validator]' corrected (there was a *). 'WiseNut [Bot]' no longer exists. PHPBB3-10897 --- phpBB/install/install_install.php | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/phpBB/install/install_install.php b/phpBB/install/install_install.php index f1003b07d7..67ebb8b1c5 100644 --- a/phpBB/install/install_install.php +++ b/phpBB/install/install_install.php @@ -2103,9 +2103,9 @@ class install_install extends module 'Alexa [Bot]' => array('ia_archiver', ''), 'Alta Vista [Bot]' => array('Scooter/', ''), 'Ask Jeeves [Bot]' => array('Ask Jeeves', ''), - 'Baidu [Spider]' => array('Baiduspider+(', ''), - 'Bing [Bot]' => array('bingbot/', ''), - 'Exabot [Bot]' => array('Exabot/', ''), + 'Baidu [Spider]' => array('Baiduspider', ''), + 'Bing [Bot]' => array('bingbot/', ''), + 'Exabot [Bot]' => array('Exabot', ''), 'FAST Enterprise [Crawler]' => array('FAST Enterprise Crawler', ''), 'FAST WebCrawler [Crawler]' => array('FAST-WebCrawler/', ''), 'Francis [Bot]' => array('http://www.neomo.de/', ''), @@ -2124,27 +2124,21 @@ class install_install extends module 'MSN NewsBlogs' => array('msnbot-NewsBlogs/', ''), 'MSN [Bot]' => array('msnbot/', ''), 'MSNbot Media' => array('msnbot-media/', ''), - 'NG-Search [Bot]' => array('NG-Search/', ''), 'Nutch [Bot]' => array('http://lucene.apache.org/nutch/', ''), - 'Nutch/CVS [Bot]' => array('NutchCVS/', ''), - 'OmniExplorer [Bot]' => array('OmniExplorer_Bot/', ''), 'Online link [Validator]' => array('online link validator', ''), 'psbot [Picsearch]' => array('psbot/0', ''), - 'Seekport [Bot]' => array('Seekbot/', ''), 'Sensis [Crawler]' => array('Sensis Web Crawler', ''), 'SEO Crawler' => array('SEO search Crawler/', ''), 'Seoma [Crawler]' => array('Seoma [SEO Crawler]', ''), 'SEOSearch [Crawler]' => array('SEOsearch/', ''), 'Snappy [Bot]' => array('Snappy/1.1 ( http://www.urltrends.com/ )', ''), 'Steeler [Crawler]' => array('http://www.tkl.iis.u-tokyo.ac.jp/~crawler/', ''), - 'Synoo [Bot]' => array('SynooBot/', ''), 'Telekom [Bot]' => array('crawleradmin.t-info@telekom.de', ''), 'TurnitinBot [Bot]' => array('TurnitinBot/', ''), - 'Voyager [Bot]' => array('voyager/1.0', ''), + 'Voyager [Bot]' => array('voyager/', ''), 'W3 [Sitesearch]' => array('W3 SiteSearch Crawler', ''), 'W3C [Linkcheck]' => array('W3C-checklink/', ''), - 'W3C [Validator]' => array('W3C_*Validator', ''), - 'WiseNut [Bot]' => array('http://www.WISEnutbot.com', ''), + 'W3C [Validator]' => array('W3C_Validator', ''), 'YaCy [Bot]' => array('yacybot', ''), 'Yahoo MMCrawler [Bot]' => array('Yahoo-MMCrawler/', ''), 'Yahoo Slurp [Bot]' => array('Yahoo! DE Slurp', ''), From 53e9bab237470e827243fcf3743eb7ca3d9ee346 Mon Sep 17 00:00:00 2001 From: Carlo Date: Tue, 28 Aug 2012 10:02:27 +0200 Subject: [PATCH 068/443] [ticket/10897] Update bots during phpBB update PHPBB3-10897 --- phpBB/install/database_update.php | 70 +++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 099ab6aeb5..0343e0dc86 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -2119,6 +2119,76 @@ function change_database_data(&$no_updates, $version) AND module_basename = \'profile\' AND module_mode = \'signature\''; _sql($sql, $errored, $error_ary); + + $bots_to_update = array( + 'Baidu [Spider]' => array('Baiduspider', ''), + 'Exabot [Bot]' => array('Exabot', ''), + 'Voyager [Bot]' => array('voyager/', ''), + 'W3C [Validator]' => array('W3C_Validator', ''), + ); + + $bots_to_delete = array( + 'NG-Search [Bot]', + 'Nutch/CVS [Bot]', + 'OmniExplorer [Bot]', + 'Seekport [Bot]', + 'Synoo [Bot]', + 'WiseNut [Bot]', + ); + + foreach($bots_to_update as $bot_name => $bot_array) + { + list($bot_agent, $bot_ip) = $bot_array; + + $bot_name_clean = utf8_clean_string($bot_name); + + $sql = 'SELECT user_id + FROM ' . USERS_TABLE . " + WHERE username_clean = '" . $db->sql_escape($bot_name_clean) . "'"; + $result = $db->sql_query($sql); + $is_user = (bool) $db->sql_fetchfield('user_id'); + $db->sql_freeresult($result); + + if ($is_user) + { + $sql = 'UPDATE ' . BOTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array( + 'bot_agent' => (string) $bot_agent, + 'bot_ip' => (string) $bot_ip, + )) . " WHERE bot_name = '" . $db->sql_escape($bot_name) . "'"; + + _sql($sql, $errored, $error_ary); + } + } + + if (!function_exists('user_delete')) + { + include($phpbb_root_path . 'includes/functions_user.' . $phpEx); + } + + foreach($bots_to_delete as $bot_name) + { + $bot_name_clean = utf8_clean_string($bot_name); + + $sql = 'SELECT user_id + FROM ' . USERS_TABLE . " + WHERE username_clean = '" . $db->sql_escape($bot_name_clean) . "'"; + $result = $db->sql_query($sql); + $bot_user_id = $db->sql_fetchfield('user_id'); + $is_user = (bool) $bot_user_id; + $db->sql_freeresult($result); + + if ($is_user) + { + $sql = 'DELETE FROM ' . BOTS_TABLE . " + WHERE bot_name = '" . $db->sql_escape($bot_name) . "'"; + + _sql($sql, $errored, $error_ary); + + user_delete('remove', $bot_user_id); + } + } + + $no_updates = false; break; } } From 07e7c475d510a221c9080529647ec432cca038c6 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 9 Nov 2012 12:12:12 +0100 Subject: [PATCH 069/443] [ticket/10897] Add space after foreach. PHPBB3-10897 --- phpBB/install/database_update.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 0343e0dc86..4c94cdf5bd 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -2136,7 +2136,7 @@ function change_database_data(&$no_updates, $version) 'WiseNut [Bot]', ); - foreach($bots_to_update as $bot_name => $bot_array) + foreach ($bots_to_update as $bot_name => $bot_array) { list($bot_agent, $bot_ip) = $bot_array; @@ -2165,7 +2165,7 @@ function change_database_data(&$no_updates, $version) include($phpbb_root_path . 'includes/functions_user.' . $phpEx); } - foreach($bots_to_delete as $bot_name) + foreach ($bots_to_delete as $bot_name) { $bot_name_clean = utf8_clean_string($bot_name); From b2183c9b705dc5283f3a1c3abbc80331f74e4b72 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 9 Nov 2012 12:12:27 +0100 Subject: [PATCH 070/443] [ticket/10897] Remove unnecessary string casting. PHPBB3-10897 --- phpBB/install/database_update.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 4c94cdf5bd..bbb05e67ec 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -2152,8 +2152,8 @@ function change_database_data(&$no_updates, $version) if ($is_user) { $sql = 'UPDATE ' . BOTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array( - 'bot_agent' => (string) $bot_agent, - 'bot_ip' => (string) $bot_ip, + 'bot_agent' => $bot_agent, + 'bot_ip' => $bot_ip, )) . " WHERE bot_name = '" . $db->sql_escape($bot_name) . "'"; _sql($sql, $errored, $error_ary); From de6d741d96e57a704e7653e8c73a20b3c196a0d9 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 9 Nov 2012 12:19:18 +0100 Subject: [PATCH 071/443] [ticket/10897] Add comment about what's going on. PHPBB3-10897 --- phpBB/install/database_update.php | 1 + 1 file changed, 1 insertion(+) diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index bbb05e67ec..c8675fa95a 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -2120,6 +2120,7 @@ function change_database_data(&$no_updates, $version) AND module_mode = \'signature\''; _sql($sql, $errored, $error_ary); + // Update bot list $bots_to_update = array( 'Baidu [Spider]' => array('Baiduspider', ''), 'Exabot [Bot]' => array('Exabot', ''), From 935bc33268bb062158d6421242335483fcd955bd Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 9 Nov 2012 12:19:58 +0100 Subject: [PATCH 072/443] [ticket/10897] Move bot delete data to the relevant foreach loop. PHPBB3-10897 --- phpBB/install/database_update.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index c8675fa95a..0372b6e608 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -2128,15 +2128,6 @@ function change_database_data(&$no_updates, $version) 'W3C [Validator]' => array('W3C_Validator', ''), ); - $bots_to_delete = array( - 'NG-Search [Bot]', - 'Nutch/CVS [Bot]', - 'OmniExplorer [Bot]', - 'Seekport [Bot]', - 'Synoo [Bot]', - 'WiseNut [Bot]', - ); - foreach ($bots_to_update as $bot_name => $bot_array) { list($bot_agent, $bot_ip) = $bot_array; @@ -2166,6 +2157,15 @@ function change_database_data(&$no_updates, $version) include($phpbb_root_path . 'includes/functions_user.' . $phpEx); } + $bots_to_delete = array( + 'NG-Search [Bot]', + 'Nutch/CVS [Bot]', + 'OmniExplorer [Bot]', + 'Seekport [Bot]', + 'Synoo [Bot]', + 'WiseNut [Bot]', + ); + foreach ($bots_to_delete as $bot_name) { $bot_name_clean = utf8_clean_string($bot_name); From 63c64694bc253358a50dce7dce99a7551b5e2b17 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 9 Nov 2012 12:41:59 +0100 Subject: [PATCH 073/443] [ticket/10897] Update by user_id instead of bot_name. PHPBB3-10897 --- phpBB/install/database_update.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 0372b6e608..6496069658 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -2132,22 +2132,23 @@ function change_database_data(&$no_updates, $version) { list($bot_agent, $bot_ip) = $bot_array; - $bot_name_clean = utf8_clean_string($bot_name); - $sql = 'SELECT user_id FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $db->sql_escape($bot_name_clean) . "'"; + WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($bot_name)) . "'"; $result = $db->sql_query($sql); - $is_user = (bool) $db->sql_fetchfield('user_id'); + $bot_user_id = (int) $db->sql_fetchfield('user_id'); $db->sql_freeresult($result); - if ($is_user) + if ($bot_user_id) { - $sql = 'UPDATE ' . BOTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array( + $update_array = array( 'bot_agent' => $bot_agent, 'bot_ip' => $bot_ip, - )) . " WHERE bot_name = '" . $db->sql_escape($bot_name) . "'"; + ); + $sql = 'UPDATE ' . BOTS_TABLE . ' + SET ' . $db->sql_build_array('UPDATE', $update_array) . " + WHERE user_id = $bot_user_id"; _sql($sql, $errored, $error_ary); } } From c054757f3caad66152eaafe09f2c98abcb9ef0e2 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 9 Nov 2012 12:45:20 +0100 Subject: [PATCH 074/443] [ticket/10897] Do not handle IP address. There is no need. PHPBB3-10897 --- phpBB/install/database_update.php | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 6496069658..154fc313a0 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -2121,17 +2121,16 @@ function change_database_data(&$no_updates, $version) _sql($sql, $errored, $error_ary); // Update bot list + // Bot name to bot user agent map $bots_to_update = array( - 'Baidu [Spider]' => array('Baiduspider', ''), - 'Exabot [Bot]' => array('Exabot', ''), - 'Voyager [Bot]' => array('voyager/', ''), - 'W3C [Validator]' => array('W3C_Validator', ''), + 'Baidu [Spider]' => 'Baiduspider', + 'Exabot [Bot]' => 'Exabot', + 'Voyager [Bot]' => 'voyager/', + 'W3C [Validator]' => 'W3C_Validator', ); - foreach ($bots_to_update as $bot_name => $bot_array) + foreach ($bots_to_update as $bot_name => $bot_agent) { - list($bot_agent, $bot_ip) = $bot_array; - $sql = 'SELECT user_id FROM ' . USERS_TABLE . " WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($bot_name)) . "'"; @@ -2141,13 +2140,8 @@ function change_database_data(&$no_updates, $version) if ($bot_user_id) { - $update_array = array( - 'bot_agent' => $bot_agent, - 'bot_ip' => $bot_ip, - ); - $sql = 'UPDATE ' . BOTS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $update_array) . " + SET bot_agent = ' . $db->sql_escape($bot_agent) . " WHERE user_id = $bot_user_id"; _sql($sql, $errored, $error_ary); } From 520ffdf368bee84549a0b284bd2df4da1d633a8f Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 9 Nov 2012 12:47:50 +0100 Subject: [PATCH 075/443] [ticket/10897] Make sure the user we're fetching is a bot. PHPBB3-10897 --- phpBB/install/database_update.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 154fc313a0..bd12a90288 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -2132,8 +2132,9 @@ function change_database_data(&$no_updates, $version) foreach ($bots_to_update as $bot_name => $bot_agent) { $sql = 'SELECT user_id - FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($bot_name)) . "'"; + FROM ' . USERS_TABLE . ' + WHERE user_type = ' . USER_IGNORE . " + AND username_clean = '" . $db->sql_escape(utf8_clean_string($bot_name)) . "'"; $result = $db->sql_query($sql); $bot_user_id = (int) $db->sql_fetchfield('user_id'); $db->sql_freeresult($result); From 54700f5ba24fe944616e017c3c2ff9c09c312445 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 9 Nov 2012 12:53:33 +0100 Subject: [PATCH 076/443] [ticket/10897] Use same code/query for deleting. PHPBB3-10897 --- phpBB/install/database_update.php | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index bd12a90288..b8bf85e283 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -2164,21 +2164,18 @@ function change_database_data(&$no_updates, $version) foreach ($bots_to_delete as $bot_name) { - $bot_name_clean = utf8_clean_string($bot_name); - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $db->sql_escape($bot_name_clean) . "'"; + FROM ' . USERS_TABLE . ' + WHERE user_type = ' . USER_IGNORE . " + AND username_clean = '" . $db->sql_escape(utf8_clean_string($bot_name)) . "'"; $result = $db->sql_query($sql); - $bot_user_id = $db->sql_fetchfield('user_id'); - $is_user = (bool) $bot_user_id; + $bot_user_id = (int) $db->sql_fetchfield('user_id'); $db->sql_freeresult($result); - if ($is_user) + if ($bot_user_id) { $sql = 'DELETE FROM ' . BOTS_TABLE . " - WHERE bot_name = '" . $db->sql_escape($bot_name) . "'"; - + WHERE user_id = $bot_user_id"; _sql($sql, $errored, $error_ary); user_delete('remove', $bot_user_id); From 60ea1c10ef0038fdb00fd38253d4b7407215e699 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 9 Nov 2012 12:59:05 +0100 Subject: [PATCH 077/443] [ticket/10897] Combine bot updates and bot delete. PHPBB3-10897 --- phpBB/install/database_update.php | 73 ++++++++++++++----------------- 1 file changed, 32 insertions(+), 41 deletions(-) diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index b8bf85e283..f7980ab1be 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -2120,16 +2120,30 @@ function change_database_data(&$no_updates, $version) AND module_mode = \'signature\''; _sql($sql, $errored, $error_ary); - // Update bot list - // Bot name to bot user agent map - $bots_to_update = array( + // Update bots + if (!function_exists('user_delete')) + { + include($phpbb_root_path . 'includes/functions_user.' . $phpEx); + } + + $bots_updates = array( + // Bot Deletions + 'NG-Search [Bot]' => false, + 'Nutch/CVS [Bot]' => false, + 'OmniExplorer [Bot]' => false, + 'Seekport [Bot]' => false, + 'Synoo [Bot]' => false, + 'WiseNut [Bot]' => false, + + // Bot Updates + // Bot name to bot user agent map 'Baidu [Spider]' => 'Baiduspider', 'Exabot [Bot]' => 'Exabot', 'Voyager [Bot]' => 'voyager/', 'W3C [Validator]' => 'W3C_Validator', ); - foreach ($bots_to_update as $bot_name => $bot_agent) + foreach ($bots_updates as $bot_name => $bot_agent) { $sql = 'SELECT user_id FROM ' . USERS_TABLE . ' @@ -2141,44 +2155,21 @@ function change_database_data(&$no_updates, $version) if ($bot_user_id) { - $sql = 'UPDATE ' . BOTS_TABLE . ' - SET bot_agent = ' . $db->sql_escape($bot_agent) . " - WHERE user_id = $bot_user_id"; - _sql($sql, $errored, $error_ary); - } - } + if ($bot_agent === false) + { + $sql = 'DELETE FROM ' . BOTS_TABLE . " + WHERE user_id = $bot_user_id"; + _sql($sql, $errored, $error_ary); - if (!function_exists('user_delete')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - $bots_to_delete = array( - 'NG-Search [Bot]', - 'Nutch/CVS [Bot]', - 'OmniExplorer [Bot]', - 'Seekport [Bot]', - 'Synoo [Bot]', - 'WiseNut [Bot]', - ); - - foreach ($bots_to_delete as $bot_name) - { - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . ' - WHERE user_type = ' . USER_IGNORE . " - AND username_clean = '" . $db->sql_escape(utf8_clean_string($bot_name)) . "'"; - $result = $db->sql_query($sql); - $bot_user_id = (int) $db->sql_fetchfield('user_id'); - $db->sql_freeresult($result); - - if ($bot_user_id) - { - $sql = 'DELETE FROM ' . BOTS_TABLE . " - WHERE user_id = $bot_user_id"; - _sql($sql, $errored, $error_ary); - - user_delete('remove', $bot_user_id); + user_delete('remove', $bot_user_id); + } + else + { + $sql = 'UPDATE ' . BOTS_TABLE . " + SET bot_agent = '" . $db->sql_escape($bot_agent) . "' + WHERE user_id = $bot_user_id"; + _sql($sql, $errored, $error_ary); + } } } From ed74c9c4870885cc3f1e04a2f68efb600012f529 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 9 Nov 2012 14:26:45 +0100 Subject: [PATCH 078/443] [ticket/11178] Do not set error_reporting to E_ALL in database_updater.php Take whatever startup.php sets instead. This especially takes care of E_STRICT messages that are generated because of PHP4 compatibility. PHPBB3-11178 --- phpBB/install/database_update.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 099ab6aeb5..b6299dbf7c 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -60,8 +60,6 @@ $updates_to_version = UPDATES_TO_VERSION; $debug_from_version = DEBUG_FROM_VERSION; $oldest_from_version = OLDEST_FROM_VERSION; -error_reporting(E_ALL); - @set_time_limit(0); // Include essential scripts From 923137cf3157fe009ccd1b982968e6720237ec87 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Fri, 9 Nov 2012 23:22:02 +0100 Subject: [PATCH 079/443] [ticket/11181] Bump PHP requirement to 5.3.3 (from 5.3.2) [develop-olympus] PHPBB3-11181 --- phpBB/includes/acp/acp_main.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/acp/acp_main.php b/phpBB/includes/acp/acp_main.php index cffe296651..ee7bd4dc45 100644 --- a/phpBB/includes/acp/acp_main.php +++ b/phpBB/includes/acp/acp_main.php @@ -398,7 +398,7 @@ class acp_main // Version check $user->add_lang('install'); - if ($auth->acl_get('a_server') && version_compare(PHP_VERSION, '5.3.2', '<')) + if ($auth->acl_get('a_server') && version_compare(PHP_VERSION, '5.3.3', '<')) { $template->assign_vars(array( 'S_PHP_VERSION_OLD' => true, From 6e6cc28b76c00800acde6c9050de318f84b5724a Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 9 Nov 2012 20:10:43 -0500 Subject: [PATCH 080/443] [ticket/10865] Should have been a slash. PHPBB3-10865 --- phpBB/docs/INSTALL.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/docs/INSTALL.html b/phpBB/docs/INSTALL.html index 92dbef9d0d..6d291490a2 100644 --- a/phpBB/docs/INSTALL.html +++ b/phpBB/docs/INSTALL.html @@ -345,7 +345,7 @@

      5.ii. Converting

      -

      To begin the conversion, visit the install. folder of your phpBB3 installation (the same as you have done for installing). Now you will see a new tab Convert. Click this tab.

      +

      To begin the conversion, visit the install/ folder of your phpBB3 installation (the same as you have done for installing). Now you will see a new tab Convert. Click this tab.

      As with install, the conversion is automated. Your previous 2.0.x database tables will not be changed and the original 2.0.x files will remain unaltered. The conversion is actually only filling your phpBB3 database tables and copying additional data over to your phpBB3 installation. This has the benefit that if something goes wrong, you are able to either re-run the conversion or continue a conversion, while your old board is still accessible. We really recommend that you disable your old installation while converting, else you may have inconsistent data after the conversion.

      From 7c4318c03314c1aba09ae2502cdda91ef9828d73 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 9 Nov 2012 20:13:06 -0500 Subject: [PATCH 081/443] [ticket/10865] Use code tags for install/database_update.php. PHPBB3-10865 --- phpBB/docs/INSTALL.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpBB/docs/INSTALL.html b/phpBB/docs/INSTALL.html index 6d291490a2..9f1c01e7ea 100644 --- a/phpBB/docs/INSTALL.html +++ b/phpBB/docs/INSTALL.html @@ -269,7 +269,7 @@

      You should now run install/database_update.php which, depending on your previous version, will make a number of database changes. You may receive FAILURES during this procedure. They should not be a cause for concern unless you see an actual ERROR, in which case the script will stop (in this case you should seek help via our forums or bug tracker).

      -

      Once install/database_update.php has completed, you may proceed to the Administration Control Panel and then remove the install directory as advised.

      +

      Once install/database_update.php has completed, you may proceed to the Administration Control Panel and then remove the install directory as advised.

      4.ii. Changed files

      @@ -279,7 +279,7 @@

      The directory structure has been preserved, enabling you (if you wish) to simply upload the uncompressed contents of the archive to the appropriate location on your server, i.e. simply overwrite the existing files with the new versions. Do not forget that if you have installed any modifications (MODs) these files will overwrite the originals, possibly destroying them in the process. You will need to re-add MODs to any affected file before uploading.

      -

      As for the other update procedures, you should run install/database_update.php after you have finished updating the files. This will update your database schema and increment the version number.

      +

      As for the other update procedures, you should run install/database_update.php after you have finished updating the files. This will update your database schema and increment the version number.

      4.iii. Patch file

      From f7f21fa6927eab5fcff7d51d3618d2c48bd4e29d Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Sat, 10 Nov 2012 14:34:52 +0100 Subject: [PATCH 082/443] [ticket/11186] Database unit tests fail on windows using sqlite2 The problem is, that we try to recreate the db and reconnect to it, while the old connection is still hold. To resolve this, we just drop all tables and recreate the tables instead of the hole db. PHPBB3-11186 --- .../phpbb_database_test_connection_manager.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index 25e0972f42..a43215bcf2 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -166,12 +166,6 @@ class phpbb_database_test_connection_manager switch ($this->config['dbms']) { case 'sqlite': - if (file_exists($this->config['dbhost'])) - { - unlink($this->config['dbhost']); - } - break; - case 'firebird': $this->connect(); // Drop all of the tables From e3b0e1a8a23b5627388df2b57ef82737c01dd1a1 Mon Sep 17 00:00:00 2001 From: Fyorl Date: Sun, 11 Nov 2012 10:44:47 +0000 Subject: [PATCH 083/443] [ticket/11190] Functional tests purge cache before running. Added functions to get and purge cache to functional framework also. PHPBB3-11190 --- .../phpbb_functional_test_case.php | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index d35913e415..bd248a662e 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -9,11 +9,14 @@ use Symfony\Component\BrowserKit\CookieJar; require_once __DIR__ . '/../../phpBB/includes/functions_install.php'; +require_once __DIR__ . '/../../phpBB/includes/acm/acm_file.php'; +require_once __DIR__ . '/../../phpBB/includes/cache.php'; class phpbb_functional_test_case extends phpbb_test_case { protected $client; protected $root_url; + protected $cache = null; /** * Session ID for current test's session (each test makes its own) @@ -47,6 +50,7 @@ class phpbb_functional_test_case extends phpbb_test_case // that were added in other tests are gone $this->lang = array(); $this->add_lang('common'); + $this->purge_cache(); } public function request($method, $path) @@ -61,6 +65,25 @@ class phpbb_functional_test_case extends phpbb_test_case { } + protected function get_cache_driver() + { + if (!$this->cache) + { + $this->cache = new cache(); + } + + return $this->cache; + } + + protected function purge_cache() + { + $cache = $this->get_cache_driver(); + + $cache->purge(); + $cache->unload(); + $cache->load(); + } + public function __construct($name = NULL, array $data = array(), $dataName = '') { parent::__construct($name, $data, $dataName); From c699b88bc58ae07fffb33611a6d7ed950bbb1e15 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 11 Nov 2012 14:35:31 +0100 Subject: [PATCH 084/443] [ticket/11192] Add Tebibyte to get_formatted_filesize(). PHPBB3-11192 --- phpBB/includes/functions.php | 6 ++++++ phpBB/language/en/common.php | 2 ++ 2 files changed, 8 insertions(+) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 65d8be32ad..33545ab845 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -301,6 +301,12 @@ function get_formatted_filesize($value, $string_only = true, $allowed_units = fa global $user; $available_units = array( + 'tb' => array( + 'min' => 1099511627776, // pow(2, 40) + 'index' => 4, + 'si_unit' => 'TB', + 'iec_unit' => 'TIB', + ), 'gb' => array( 'min' => 1073741824, // pow(2, 30) 'index' => 3, diff --git a/phpBB/language/en/common.php b/phpBB/language/en/common.php index 0184dd083b..844d5ef3ef 100644 --- a/phpBB/language/en/common.php +++ b/phpBB/language/en/common.php @@ -568,9 +568,11 @@ $lang = array_merge($lang, array( 'SUBJECT' => 'Subject', 'SUBMIT' => 'Submit', + 'TB' => 'TB', 'TERMS_USE' => 'Terms of use', 'TEST_CONNECTION' => 'Test connection', 'THE_TEAM' => 'The team', + 'TIB' => 'TiB', 'TIME' => 'Time', 'TOO_LARGE' => 'The value you entered is too large.', From b0812c43fa05bec8c59e5ff3c7889f0f98089775 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 11 Nov 2012 17:40:58 +0100 Subject: [PATCH 085/443] [ticket/11162] Use integer casting instead of SQL escape. PHPBB3-11162 --- tests/functions/update_rows_avoiding_duplicates_test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functions/update_rows_avoiding_duplicates_test.php b/tests/functions/update_rows_avoiding_duplicates_test.php index 0e949717d2..e4e156209d 100644 --- a/tests/functions/update_rows_avoiding_duplicates_test.php +++ b/tests/functions/update_rows_avoiding_duplicates_test.php @@ -61,7 +61,7 @@ class phpbb_update_rows_avoiding_duplicates_test extends phpbb_database_test_cas $sql = 'SELECT count(*) AS count FROM ' . TOPICS_WATCH_TABLE . ' - WHERE topic_id = ' . $db->sql_escape($to); + WHERE topic_id = ' . (int) $to; $result = $db->sql_query($sql); $result_count = $db->sql_fetchfield('count'); $db->sql_freeresult($result); From 7d0cc15b926dda1a53b8151e063e2ffda7441240 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 11 Nov 2012 17:48:59 +0100 Subject: [PATCH 086/443] [ticket/11162] Rename count variable name to remaining_rows. PHPBB3-11162 --- tests/functions/update_rows_avoiding_duplicates_test.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/functions/update_rows_avoiding_duplicates_test.php b/tests/functions/update_rows_avoiding_duplicates_test.php index e4e156209d..0c9ae068a4 100644 --- a/tests/functions/update_rows_avoiding_duplicates_test.php +++ b/tests/functions/update_rows_avoiding_duplicates_test.php @@ -59,11 +59,11 @@ class phpbb_update_rows_avoiding_duplicates_test extends phpbb_database_test_cas phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $from, $to); - $sql = 'SELECT count(*) AS count + $sql = 'SELECT count(*) AS remaining_rows FROM ' . TOPICS_WATCH_TABLE . ' WHERE topic_id = ' . (int) $to; $result = $db->sql_query($sql); - $result_count = $db->sql_fetchfield('count'); + $result_count = $db->sql_fetchfield('remaining_rows'); $db->sql_freeresult($result); $this->assertEquals($expected_result_count, $result_count); From ac9c4d7d59ea458834cb64b9c9020c3de8fe90a2 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 11 Nov 2012 17:49:21 +0100 Subject: [PATCH 087/443] [ticket/11162] Make count function upper case. PHPBB3-11162 --- tests/functions/update_rows_avoiding_duplicates_test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functions/update_rows_avoiding_duplicates_test.php b/tests/functions/update_rows_avoiding_duplicates_test.php index 0c9ae068a4..0d68e22d4a 100644 --- a/tests/functions/update_rows_avoiding_duplicates_test.php +++ b/tests/functions/update_rows_avoiding_duplicates_test.php @@ -59,7 +59,7 @@ class phpbb_update_rows_avoiding_duplicates_test extends phpbb_database_test_cas phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $from, $to); - $sql = 'SELECT count(*) AS remaining_rows + $sql = 'SELECT COUNT(*) AS remaining_rows FROM ' . TOPICS_WATCH_TABLE . ' WHERE topic_id = ' . (int) $to; $result = $db->sql_query($sql); From 170967c48a583e4db5fa1131e23d7abe71681ae6 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Tue, 13 Nov 2012 20:26:49 +0100 Subject: [PATCH 088/443] [ticket/10879] Remove arrow icon from attachment link in editor If you upload a file with a long filename the filename will partially cover the arrow icon background image. Remove the icon as it's not needed anyways. PHPBB3-10879 --- phpBB/styles/prosilver/template/posting_editor.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/styles/prosilver/template/posting_editor.html b/phpBB/styles/prosilver/template/posting_editor.html index 5b3f2beed0..5acdb3a08c 100644 --- a/phpBB/styles/prosilver/template/posting_editor.html +++ b/phpBB/styles/prosilver/template/posting_editor.html @@ -165,7 +165,7 @@
      -
      {attach_row.FILENAME}
      +
      {attach_row.FILENAME}
        From 4ab178f3efd2ec497081bc1b3e57e4566d2eee6d Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 15 Nov 2012 08:19:40 -0500 Subject: [PATCH 089/443] [ticket/11202] Add a heuristic function to check for response success. This tries to account for php sending fatal errors with 200 status code. PHPBB3-11202 --- .../phpbb_functional_test_case.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index d35913e415..09f52effec 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -182,7 +182,7 @@ class phpbb_functional_test_case extends phpbb_test_case $login = $this->client->submit($form, array('username' => 'admin', 'password' => 'admin')); $cookies = $this->cookieJar->all(); - + // The session id is stored in a cookie that ends with _sid - we assume there is only one such cookie foreach ($cookies as $cookie); { @@ -229,4 +229,19 @@ class phpbb_functional_test_case extends phpbb_test_case return call_user_func_array('sprintf', $args); } + + /** + * Heuristic function to check that the response is success. + * + * When php decides to die with a fatal error, it still sends 200 OK + * status code. This assertion tries to catch that. + * + * @param string $message Optional failure message + */ + public function assert_response_success($message = null) + { + $this->assertEquals(200, $this->client->getResponse()->getStatus()); + $content = $this->client->getResponse()->getContent(); + $this->assertNotContains('Fatal error:', $content); + } } From dc61fd1091d7cf7994eb1559691c4dfabec740f5 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 15 Nov 2012 08:20:07 -0500 Subject: [PATCH 090/443] [ticket/11202] Check response success before content assertions. This does not change tests that perform requests which are either clearly not supposed to succeed or are a gray area. PHPBB3-11202 --- tests/functional/browse_test.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/functional/browse_test.php b/tests/functional/browse_test.php index 26c18c4c1f..b5748059c6 100644 --- a/tests/functional/browse_test.php +++ b/tests/functional/browse_test.php @@ -15,18 +15,21 @@ class phpbb_functional_browse_test extends phpbb_functional_test_case public function test_index() { $crawler = $this->request('GET', 'index.php'); + $this->assert_response_success(); $this->assertGreaterThan(0, $crawler->filter('.topiclist')->count()); } public function test_viewforum() { $crawler = $this->request('GET', 'viewforum.php?f=2'); + $this->assert_response_success(); $this->assertGreaterThan(0, $crawler->filter('.topiclist')->count()); } public function test_viewtopic() { $crawler = $this->request('GET', 'viewtopic.php?t=1'); + $this->assert_response_success(); $this->assertGreaterThan(0, $crawler->filter('.postbody')->count()); } } From af7ab2d3ac287db1a2c9ed623e21393cb429203f Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 15 Nov 2012 08:40:29 -0500 Subject: [PATCH 091/443] [ticket/11202] Custom message does not make sense here, delete it. PHPBB3-11202 --- tests/test_framework/phpbb_functional_test_case.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 09f52effec..de04783bce 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -236,9 +236,9 @@ class phpbb_functional_test_case extends phpbb_test_case * When php decides to die with a fatal error, it still sends 200 OK * status code. This assertion tries to catch that. * - * @param string $message Optional failure message + * @return null */ - public function assert_response_success($message = null) + public function assert_response_success() { $this->assertEquals(200, $this->client->getResponse()->getStatus()); $content = $this->client->getResponse()->getContent(); From c15b98999ef1ba26531e3d6e20695a8f2672f5a4 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 15 Nov 2012 23:57:55 -0500 Subject: [PATCH 092/443] [ticket/11192] Add tests. PHPBB3-11192 --- .../functions/get_formatted_filesize_test.php | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 tests/functions/get_formatted_filesize_test.php diff --git a/tests/functions/get_formatted_filesize_test.php b/tests/functions/get_formatted_filesize_test.php new file mode 100644 index 0000000000..1cc7ddf9ec --- /dev/null +++ b/tests/functions/get_formatted_filesize_test.php @@ -0,0 +1,50 @@ +assertEquals($expected, $output); + } +} From b7ec639945a4667508e4a3d1f8ac73da94809b21 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 16 Nov 2012 07:43:24 +0100 Subject: [PATCH 093/443] [ticket/11192] Also test powers of 10 / 1000. PHPBB3-11192 --- tests/functions/get_formatted_filesize_test.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/functions/get_formatted_filesize_test.php b/tests/functions/get_formatted_filesize_test.php index 1cc7ddf9ec..802f82d126 100644 --- a/tests/functions/get_formatted_filesize_test.php +++ b/tests/functions/get_formatted_filesize_test.php @@ -21,6 +21,13 @@ class phpbb_get_formatted_filesize_test extends phpbb_test_case array(1073741824, '1 GIB'), array(1099511627776, '1 TIB'), + // exact powers of 10 + array(1000, '1000 BYTES'), + array(1000000, '976.56 KIB'), + array(1000000000, '953.67 MIB'), + array(1000000000000, '931.32 GIB'), + array(100000000000000, '90.95 TIB'), + array(0, '0 BYTES'), array(2, '2 BYTES'), array(-2, '-2 BYTES'), From 09c8c58a5c9602a665519586b75ae3e9831367c8 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 16 Nov 2012 08:00:12 +0100 Subject: [PATCH 094/443] [ticket/11192] Also test strings, e.g. sums returned by the database. PHPBB3-11192 --- tests/functions/get_formatted_filesize_test.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/functions/get_formatted_filesize_test.php b/tests/functions/get_formatted_filesize_test.php index 802f82d126..85b06b723d 100644 --- a/tests/functions/get_formatted_filesize_test.php +++ b/tests/functions/get_formatted_filesize_test.php @@ -54,4 +54,14 @@ class phpbb_get_formatted_filesize_test extends phpbb_test_case $this->assertEquals($expected, $output); } + + /** + * @dataProvider get_formatted_filesize_test_data + */ + public function test_get_formatted_filesize_string($input, $expected) + { + $output = get_formatted_filesize("$input"); + + $this->assertEquals($expected, $output); + } } From 4e3a42f59fa32fb1a3e14cff959b19576e5ba7cf Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 16 Nov 2012 08:20:58 +0100 Subject: [PATCH 095/443] [ticket/11192] Test strings not converted to int/float before. PHPBB3-11192 --- .../functions/get_formatted_filesize_test.php | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/tests/functions/get_formatted_filesize_test.php b/tests/functions/get_formatted_filesize_test.php index 85b06b723d..88866f90ac 100644 --- a/tests/functions/get_formatted_filesize_test.php +++ b/tests/functions/get_formatted_filesize_test.php @@ -45,6 +45,40 @@ class phpbb_get_formatted_filesize_test extends phpbb_test_case ); } + public function get_formatted_filesize_test_data_string() + { + return array( + // exact powers of 2 + array('1', '1 BYTES'), + array('1024', '1 KIB'), + array('1048576', '1 MIB'), + array('1073741824', '1 GIB'), + array('1099511627776', '1 TIB'), + + // exact powers of 10 + array('1000', '1000 BYTES'), + array('1000000', '976.56 KIB'), + array('1000000000', '953.67 MIB'), + array('1000000000000', '931.32 GIB'), + array('100000000000000', '90.95 TIB'), + + array('0', '0 BYTES'), + array('2', '2 BYTES'), + array('-2', '-2 BYTES'), + + array('1023', '1023 BYTES'), + array('1025', '1 KIB'), + array('-1023', '-1023 BYTES'), + array('-1025', '-1025 BYTES'), + + array('1048575', '1024 KIB'), + + // large negatives + array('-1073741824', '-1073741824 BYTES'), + array('-1099511627776', '-1099511627776 BYTES'), + ); + } + /** * @dataProvider get_formatted_filesize_test_data */ @@ -56,11 +90,11 @@ class phpbb_get_formatted_filesize_test extends phpbb_test_case } /** - * @dataProvider get_formatted_filesize_test_data + * @dataProvider get_formatted_filesize_test_data_string */ public function test_get_formatted_filesize_string($input, $expected) { - $output = get_formatted_filesize("$input"); + $output = get_formatted_filesize($input); $this->assertEquals($expected, $output); } From 7cbd440e7a69eb836eb9d58800f1c535d41b83ab Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 16 Nov 2012 08:28:35 +0100 Subject: [PATCH 096/443] [ticket/11192] Mark negative byte numbers as unsupported. PHPBB3-11192 --- phpBB/includes/functions.php | 2 +- tests/functions/get_formatted_filesize_test.php | 16 ---------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 33545ab845..8688ba3f7e 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -289,7 +289,7 @@ function phpbb_gmgetdate($time = false) /** * Return formatted string for filesizes * -* @param int $value filesize in bytes +* @param int $value filesize in bytes (non-negative number) * @param bool $string_only true if language string should be returned * @param array $allowed_units only allow these units (data array indexes) * diff --git a/tests/functions/get_formatted_filesize_test.php b/tests/functions/get_formatted_filesize_test.php index 88866f90ac..c4793e8073 100644 --- a/tests/functions/get_formatted_filesize_test.php +++ b/tests/functions/get_formatted_filesize_test.php @@ -30,18 +30,10 @@ class phpbb_get_formatted_filesize_test extends phpbb_test_case array(0, '0 BYTES'), array(2, '2 BYTES'), - array(-2, '-2 BYTES'), array(1023, '1023 BYTES'), array(1025, '1 KIB'), - array(-1023, '-1023 BYTES'), - array(-1025, '-1025 BYTES'), - array(1048575, '1024 KIB'), - - // large negatives - array(-1073741824, '-1073741824 BYTES'), - array(-1099511627776, '-1099511627776 BYTES'), ); } @@ -64,18 +56,10 @@ class phpbb_get_formatted_filesize_test extends phpbb_test_case array('0', '0 BYTES'), array('2', '2 BYTES'), - array('-2', '-2 BYTES'), array('1023', '1023 BYTES'), array('1025', '1 KIB'), - array('-1023', '-1023 BYTES'), - array('-1025', '-1025 BYTES'), - array('1048575', '1024 KIB'), - - // large negatives - array('-1073741824', '-1073741824 BYTES'), - array('-1099511627776', '-1099511627776 BYTES'), ); } From efd6f1df63c24ed2947bccb863bb92c2346bf697 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 16 Nov 2012 08:29:57 +0100 Subject: [PATCH 097/443] [ticket/11192] Update $value parameter description to support other types. PHPBB3-11192 --- phpBB/includes/functions.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 8688ba3f7e..6e661228b7 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -289,7 +289,8 @@ function phpbb_gmgetdate($time = false) /** * Return formatted string for filesizes * -* @param int $value filesize in bytes (non-negative number) +* @param mixed $value filesize in bytes +* (non-negative number; int, float or string) * @param bool $string_only true if language string should be returned * @param array $allowed_units only allow these units (data array indexes) * From 8851f9589a5295d569316e76b366f1b16f1a9a96 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 16 Nov 2012 16:20:55 +0100 Subject: [PATCH 098/443] [ticket/11192] Merge dataProvider arrays because the test is the same now. PHPBB3-11192 --- tests/functions/get_formatted_filesize_test.php | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/tests/functions/get_formatted_filesize_test.php b/tests/functions/get_formatted_filesize_test.php index c4793e8073..96ea2be132 100644 --- a/tests/functions/get_formatted_filesize_test.php +++ b/tests/functions/get_formatted_filesize_test.php @@ -34,12 +34,8 @@ class phpbb_get_formatted_filesize_test extends phpbb_test_case array(1023, '1023 BYTES'), array(1025, '1 KIB'), array(1048575, '1024 KIB'), - ); - } - public function get_formatted_filesize_test_data_string() - { - return array( + // String values // exact powers of 2 array('1', '1 BYTES'), array('1024', '1 KIB'), @@ -72,14 +68,4 @@ class phpbb_get_formatted_filesize_test extends phpbb_test_case $this->assertEquals($expected, $output); } - - /** - * @dataProvider get_formatted_filesize_test_data_string - */ - public function test_get_formatted_filesize_string($input, $expected) - { - $output = get_formatted_filesize($input); - - $this->assertEquals($expected, $output); - } } From 41a95d2c646aba8d6a66ee046c532a51a9022784 Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Sun, 18 Nov 2012 20:38:58 -0600 Subject: [PATCH 099/443] [ticket/11219] Update sequence values after loading fixtures If a value is provide for an auto_increment type of column, certain DBMSes do not update their internal sequencers. If a row is inserted later, it can be given an ID that is already in use, resulting in an error. The database test cases now resynchronise the sequencers before the tests are run. PHPBB3-11219 --- .../phpbb_database_test_case.php | 10 ++ ...phpbb_database_test_connection_manager.php | 129 ++++++++++++++++++ 2 files changed, 139 insertions(+) diff --git a/tests/test_framework/phpbb_database_test_case.php b/tests/test_framework/phpbb_database_test_case.php index 75a3c0944b..0916679108 100644 --- a/tests/test_framework/phpbb_database_test_case.php +++ b/tests/test_framework/phpbb_database_test_case.php @@ -28,6 +28,16 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test ); } + protected function setUp() + { + parent::setUp(); + + $config = $this->get_database_config(); + $manager = $this->create_connection_manager($config); + $manager->connect(); + $manager->post_setup_synchronisation(); + } + public function createXMLDataSet($path) { $db_config = $this->get_database_config(); diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index a43215bcf2..cae1720587 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -426,4 +426,133 @@ class phpbb_database_test_connection_manager $this->pdo->exec($query); } } + + /** + * Performs synchronisations on the database after a fixture has been loaded + */ + public function post_setup_synchronisation() + { + $this->ensure_connected(__METHOD__); + $queries = array(); + + switch ($this->config['dbms']) + { + case 'oracle': + // Get all of the information about the sequences + $sql = "SELECT t.table_name, tc.column_name, d.referenced_name as sequence_name + FROM USER_TRIGGERS t + JOIN USER_DEPENDENCIES d on d.name = t.trigger_name + JOIN USER_TRIGGER_COLS tc on (tc.trigger_name = t.trigger_name) + WHERE d.referenced_type = 'SEQUENCE' + AND d.type = 'TRIGGER'"; + $result = $this->pdo->query($sql); + + while ($row = $result->fetch(PDO::FETCH_ASSOC)) + { + // Get the current max value of the table + $sql = "SELECT MAX({$row['COLUMN_NAME']}) + 1 FROM {$row['TABLE_NAME']}"; + + $max_result = $this->pdo->query($sql); + $max_row = $max_result->fetch(PDO::FETCH_NUM); + + if (!$max_row) + { + continue; + } + + $maxval = current($max_row); + if ($maxval == null) + { + $maxval = 1; + } + + // Get the sequence's next value + $sql = "SELECT {$row['SEQUENCE_NAME']}.nextval FROM dual"; + try + { + $nextval_result = $this->pdo->query($sql); + } + catch (PDOException $e) + { + // If we catch an exception here it's because the sequencer hasn't been initialized yet. + // If the table hasn't been used, then there's nothing to do. + continue; + } + $nextval_row = $nextval_result->fetch(PDO::FETCH_NUM); + + if ($nextval_row) + { + $nextval = current($nextval_row); + + // Make sure we aren't setting the new increment to zero. + if ($maxval != $nextval) + { + // This is a multi-step process. First we need to get the sequence back into position. + // That means either advancing it or moving it backwards. Sequences have a minimum value + // of 1, so you cannot go past that. Once the offset it determined, you have to request + // the next sequence value to actually move the pointer into position. So if you're at 21 + // and need to be back at 1, set the incrementer to -20. When it's requested, it'll give + // you 1. Then we have to set the increment amount back to 1 to resume normal behavior. + + // Move the sequence to the correct position. + $sql = "ALTER SEQUENCE {$row['SEQUENCE_NAME']} INCREMENT BY " . ($maxval - $nextval); + $this->pdo->exec($sql); + + // Select the next value to actually update the sequence values + $sql = "SELECT {$row['SEQUENCE_NAME']}.nextval FROM dual"; + $this->pdo->query($sql); + + // Reset the sequence's increment amount + $sql = "ALTER SEQUENCE {$row['SEQUENCE_NAME']} INCREMENT BY 1"; + $this->pdo->exec($sql); + } + } + } + break; + + case 'postgres': + // First get the sequences + $sequences = array(); + $sql = "SELECT relname FROM pg_class WHERE relkind = 'S'"; + $result = $this->pdo->query($sql); + while ($row = $result->fetch(PDO::FETCH_ASSOC)) + { + $sequences[] = $row['relname']; + } + + // Now get the name of the column using it + foreach ($sequences as $sequence) + { + $table = str_replace('_seq', '', $sequence); + $sql = "SELECT column_name FROM information_schema.columns + WHERE table_name = '$table' + AND column_default = 'nextval(''$sequence''::regclass)'"; + $result = $this->pdo->query($sql); + $row = $result->fetch(PDO::FETCH_ASSOC); + + // Finally, set the new sequence value + if ($row) + { + $column = $row['column_name']; + + // Get the old value if it exists, or use 1 if it doesn't + $sql = "SELECT COALESCE((SELECT MAX({$column}) + 1 FROM {$table}), 1) AS val"; + $result = $this->pdo->query($sql); + $row = $result->fetch(PDO::FETCH_ASSOC); + + if ($row) + { + // The last parameter is false so that the system doesn't increment it again + $queries[] = "SELECT SETVAL('{$sequence}', {$row['val']}, false)"; + } + } + } + break; + } + + foreach ($queries as $query) + { + $this->pdo->exec($query); + } + } } From a7404409a8376e7db9f295e5cf598ccee59523b5 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Mon, 19 Nov 2012 13:49:04 +0100 Subject: [PATCH 100/443] [ticket/11219] Add unit test for inserting into a sequence column PHPBB3-11219 --- tests/dbal/write_sequence_test.php | 55 ++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 tests/dbal/write_sequence_test.php diff --git a/tests/dbal/write_sequence_test.php b/tests/dbal/write_sequence_test.php new file mode 100644 index 0000000000..d2c30b4e89 --- /dev/null +++ b/tests/dbal/write_sequence_test.php @@ -0,0 +1,55 @@ +createXMLDataSet(dirname(__FILE__).'/fixtures/three_users.xml'); + } + + static public function write_sequence_data() + { + return array( + array( + 'ticket/11219', + 4, + ), + ); + } + + /** + * @dataProvider write_sequence_data + */ + public function test_write_sequence($username, $expected) + { + $db = $this->new_dbal(); + + $sql = 'INSERT INTO phpbb_users ' . $db->sql_build_array('INSERT', array( + 'username' => $username, + 'username_clean' => $username, + 'user_permissions' => '', + 'user_sig' => '', + 'user_occ' => '', + 'user_interests' => '', + )); + $db->sql_query($sql); + + $this->assertEquals($expected, $db->sql_nextid()); + + $sql = "SELECT user_id + FROM phpbb_users + WHERE username_clean = '" . $db->sql_escape($username) . "'"; + $result = $db->sql_query_limit($sql, 1); + + $this->assertEquals($expected, $db->sql_fetchfield('user_id')); + } +} From 1dff6d1bf988bb0d11a393fad0c0d0183366a5c9 Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Tue, 20 Nov 2012 04:40:06 -0600 Subject: [PATCH 101/443] [ticket/11219] Recreate Oracle sequences instead of altering them The previous method would always leave a gap between the last value and the new one due to how you have to update the sequence values. To remove gaps in all situations, the options are to alter the USER_SEQUENCES table or just drop the sequence and recreate it. The prior requires elevated priveleges and the latter can break attached objects. Since we don't attach objects to the sequences, we won't have any problems doing it for the tests. PHPBB3-11219 --- ...phpbb_database_test_connection_manager.php | 69 +++++-------------- 1 file changed, 17 insertions(+), 52 deletions(-) diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index cae1720587..e79a764e1d 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -439,10 +439,11 @@ class phpbb_database_test_connection_manager { case 'oracle': // Get all of the information about the sequences - $sql = "SELECT t.table_name, tc.column_name, d.referenced_name as sequence_name + $sql = "SELECT t.table_name, tc.column_name, d.referenced_name as sequence_name, s.increment_by, s.min_value FROM USER_TRIGGERS t - JOIN USER_DEPENDENCIES d on d.name = t.trigger_name - JOIN USER_TRIGGER_COLS tc on (tc.trigger_name = t.trigger_name) + JOIN USER_DEPENDENCIES d ON (d.name = t.trigger_name) + JOIN USER_TRIGGER_COLS tc ON (tc.trigger_name = t.trigger_name) + JOIN USER_SEQUENCES s ON (s.sequence_name = d.referenced_name) WHERE d.referenced_type = 'SEQUENCE' AND d.type = 'TRIGGER'"; $result = $this->pdo->query($sql); @@ -450,63 +451,27 @@ class phpbb_database_test_connection_manager while ($row = $result->fetch(PDO::FETCH_ASSOC)) { // Get the current max value of the table - $sql = "SELECT MAX({$row['COLUMN_NAME']}) + 1 FROM {$row['TABLE_NAME']}"; - + $sql = "SELECT MAX({$row['COLUMN_NAME']}) AS max FROM {$row['TABLE_NAME']}"; $max_result = $this->pdo->query($sql); - $max_row = $max_result->fetch(PDO::FETCH_NUM); + $max_row = $max_result->fetch(PDO::FETCH_ASSOC); if (!$max_row) { continue; } - $maxval = current($max_row); - if ($maxval == null) - { - $maxval = 1; - } + $maxval = (int)$max_row['MAX']; + $maxval++; - // Get the sequence's next value - $sql = "SELECT {$row['SEQUENCE_NAME']}.nextval FROM dual"; - try - { - $nextval_result = $this->pdo->query($sql); - } - catch (PDOException $e) - { - // If we catch an exception here it's because the sequencer hasn't been initialized yet. - // If the table hasn't been used, then there's nothing to do. - continue; - } - $nextval_row = $nextval_result->fetch(PDO::FETCH_NUM); - - if ($nextval_row) - { - $nextval = current($nextval_row); - - // Make sure we aren't setting the new increment to zero. - if ($maxval != $nextval) - { - // This is a multi-step process. First we need to get the sequence back into position. - // That means either advancing it or moving it backwards. Sequences have a minimum value - // of 1, so you cannot go past that. Once the offset it determined, you have to request - // the next sequence value to actually move the pointer into position. So if you're at 21 - // and need to be back at 1, set the incrementer to -20. When it's requested, it'll give - // you 1. Then we have to set the increment amount back to 1 to resume normal behavior. - - // Move the sequence to the correct position. - $sql = "ALTER SEQUENCE {$row['SEQUENCE_NAME']} INCREMENT BY " . ($maxval - $nextval); - $this->pdo->exec($sql); - - // Select the next value to actually update the sequence values - $sql = "SELECT {$row['SEQUENCE_NAME']}.nextval FROM dual"; - $this->pdo->query($sql); - - // Reset the sequence's increment amount - $sql = "ALTER SEQUENCE {$row['SEQUENCE_NAME']} INCREMENT BY 1"; - $this->pdo->exec($sql); - } - } + // This is not the "proper" way, but the proper way does not allow you to completely reset + // tables with no rows since you have to select the next value to make the change go into effct. + // You would have to go past the minimum value to set it correctly, but that's illegal. + // Since we have no objects attached to our sequencers (triggers aren't attached), this works fine. + $queries[] = 'DROP SEQUENCE ' . $row['SEQUENCE_NAME']; + $queries[] = "CREATE SEQUENCE {$row['SEQUENCE_NAME']} + MINVALUE {$row['MIN_VALUE']} + INCREMENT BY {$row['INCREMENT_BY']} + START WITH $maxval"; } break; From 65253a3023a78b1068be63b91b77618e3fb2d5fd Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 29 Nov 2012 15:35:21 -0500 Subject: [PATCH 102/443] [ticket/11227] @return void -> @return null in develop-olympus. PHPBB3-11227 --- phpBB/develop/generate_utf_casefold.php | 2 +- phpBB/develop/generate_utf_confusables.php | 2 +- phpBB/develop/generate_utf_tables.php | 2 +- phpBB/develop/utf_normalizer_test.php | 2 +- phpBB/docs/auth_api.html | 2 +- phpBB/includes/acm/acm_apc.php | 2 +- phpBB/includes/acm/acm_eaccelerator.php | 4 ++-- phpBB/includes/acm/acm_memcache.php | 4 ++-- phpBB/includes/acm/acm_redis.php | 4 ++-- phpBB/includes/acm/acm_wincache.php | 2 +- phpBB/includes/acm/acm_xcache.php | 2 +- phpBB/includes/functions.php | 4 ++-- phpBB/includes/functions_admin.php | 2 +- phpBB/includes/questionnaire/questionnaire.php | 2 +- 14 files changed, 18 insertions(+), 18 deletions(-) diff --git a/phpBB/develop/generate_utf_casefold.php b/phpBB/develop/generate_utf_casefold.php index 73951cb4dc..08f67c3eb6 100644 --- a/phpBB/develop/generate_utf_casefold.php +++ b/phpBB/develop/generate_utf_casefold.php @@ -111,7 +111,7 @@ function my_var_export($var) * Download a file to the develop/ dir * * @param string $url URL of the file to download -* @return void +* @return null */ function download($url) { diff --git a/phpBB/develop/generate_utf_confusables.php b/phpBB/develop/generate_utf_confusables.php index d2ffbcfc65..fd0439a4bb 100644 --- a/phpBB/develop/generate_utf_confusables.php +++ b/phpBB/develop/generate_utf_confusables.php @@ -199,7 +199,7 @@ function my_var_export($var) * Download a file to the develop/ dir * * @param string $url URL of the file to download -* @return void +* @return null */ function download($url) { diff --git a/phpBB/develop/generate_utf_tables.php b/phpBB/develop/generate_utf_tables.php index 6fe5d68ffd..6372270b78 100644 --- a/phpBB/develop/generate_utf_tables.php +++ b/phpBB/develop/generate_utf_tables.php @@ -481,7 +481,7 @@ function my_var_export($var) * Download a file to the develop/ dir * * @param string $url URL of the file to download -* @return void +* @return null */ function download($url) { diff --git a/phpBB/develop/utf_normalizer_test.php b/phpBB/develop/utf_normalizer_test.php index 71f24a716b..b8709888fe 100644 --- a/phpBB/develop/utf_normalizer_test.php +++ b/phpBB/develop/utf_normalizer_test.php @@ -222,7 +222,7 @@ die("\n\nALL TESTS PASSED SUCCESSFULLY\n"); * Download a file to the develop/ dir * * @param string $url URL of the file to download -* @return void +* @return null */ function download($url) { diff --git a/phpBB/docs/auth_api.html b/phpBB/docs/auth_api.html index 29469c21ac..a319460360 100644 --- a/phpBB/docs/auth_api.html +++ b/phpBB/docs/auth_api.html @@ -200,7 +200,7 @@ $user_id = 2; $auth->acl_clear_prefetch($user_id);
      -

      This method returns void.

      +

      This method returns null.

      2.viii. acl_get_list

      diff --git a/phpBB/includes/acm/acm_apc.php b/phpBB/includes/acm/acm_apc.php index 1a487f94ad..205353d3a5 100644 --- a/phpBB/includes/acm/acm_apc.php +++ b/phpBB/includes/acm/acm_apc.php @@ -33,7 +33,7 @@ class acm extends acm_memory /** * Purge cache data * - * @return void + * @return null */ function purge() { diff --git a/phpBB/includes/acm/acm_eaccelerator.php b/phpBB/includes/acm/acm_eaccelerator.php index 645067c199..ecec3ac9a5 100644 --- a/phpBB/includes/acm/acm_eaccelerator.php +++ b/phpBB/includes/acm/acm_eaccelerator.php @@ -37,7 +37,7 @@ class acm extends acm_memory /** * Purge cache data * - * @return void + * @return null */ function purge() { @@ -54,7 +54,7 @@ class acm extends acm_memory /** * Perform cache garbage collection * - * @return void + * @return null */ function tidy() { diff --git a/phpBB/includes/acm/acm_memcache.php b/phpBB/includes/acm/acm_memcache.php index e54fa36c38..70bc219952 100644 --- a/phpBB/includes/acm/acm_memcache.php +++ b/phpBB/includes/acm/acm_memcache.php @@ -71,7 +71,7 @@ class acm extends acm_memory /** * Unload the cache resources * - * @return void + * @return null */ function unload() { @@ -83,7 +83,7 @@ class acm extends acm_memory /** * Purge cache data * - * @return void + * @return null */ function purge() { diff --git a/phpBB/includes/acm/acm_redis.php b/phpBB/includes/acm/acm_redis.php index 41533eaacb..dc11ca7768 100644 --- a/phpBB/includes/acm/acm_redis.php +++ b/phpBB/includes/acm/acm_redis.php @@ -80,7 +80,7 @@ class acm extends acm_memory /** * Unload the cache resources * - * @return void + * @return null */ function unload() { @@ -92,7 +92,7 @@ class acm extends acm_memory /** * Purge cache data * - * @return void + * @return null */ function purge() { diff --git a/phpBB/includes/acm/acm_wincache.php b/phpBB/includes/acm/acm_wincache.php index 0501ab74c5..7faba4f5b6 100644 --- a/phpBB/includes/acm/acm_wincache.php +++ b/phpBB/includes/acm/acm_wincache.php @@ -32,7 +32,7 @@ class acm extends acm_memory /** * Purge cache data * - * @return void + * @return null */ function purge() { diff --git a/phpBB/includes/acm/acm_xcache.php b/phpBB/includes/acm/acm_xcache.php index d0a614660c..e3d83f8bfa 100644 --- a/phpBB/includes/acm/acm_xcache.php +++ b/phpBB/includes/acm/acm_xcache.php @@ -48,7 +48,7 @@ class acm extends acm_memory /** * Purge cache data * - * @return void + * @return null */ function purge() { diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 6e661228b7..571c863839 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -2745,7 +2745,7 @@ function meta_refresh($time, $url, $disable_cd_check = false) * * @param int $code HTTP status code * @param string $message Message for the status code -* @return void +* @return null */ function send_status_line($code, $message) { @@ -4332,7 +4332,7 @@ function phpbb_optionset($bit, $set, $data) * * @param array $param Parameter array, see $param_defaults array. * -* @return void +* @return null */ function phpbb_http_login($param) { diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php index 7352b3d1f3..190185cfcf 100644 --- a/phpBB/includes/functions_admin.php +++ b/phpBB/includes/functions_admin.php @@ -3343,7 +3343,7 @@ function obtain_latest_version_info($force_update = false, $warn_fail = false, $ * @param int $flag The binary flag which is OR-ed with the current column value * @param string $sql_more This string is attached to the sql query generated to update the table. * - * @return void + * @return null */ function enable_bitfield_column_flag($table_name, $column_name, $flag, $sql_more = '') { diff --git a/phpBB/includes/questionnaire/questionnaire.php b/phpBB/includes/questionnaire/questionnaire.php index cbd7638809..3268775cb6 100644 --- a/phpBB/includes/questionnaire/questionnaire.php +++ b/phpBB/includes/questionnaire/questionnaire.php @@ -71,7 +71,7 @@ class phpbb_questionnaire_data_collector /** * Collect info into the data property. * - * @return void + * @return null */ function collect() { From 314462d8352a6b5ea1fd27ce1bb21cb0a8fb1310 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Fri, 9 Nov 2012 22:36:01 +0100 Subject: [PATCH 103/443] [ticket/10184] Disable receiving pms for bots by default PHPBB3-10184 --- phpBB/install/database_update.php | 6 ++++++ phpBB/install/install_install.php | 1 + 2 files changed, 7 insertions(+) diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 399ad3429a..8e23434b5b 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -2171,6 +2171,12 @@ function change_database_data(&$no_updates, $version) } } + // Disable receiving pms for bots + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_allow_pm = 0 + WHERE user_type = ' . USER_IGNORE; + $db->sql_query($sql); + $no_updates = false; break; } diff --git a/phpBB/install/install_install.php b/phpBB/install/install_install.php index 67ebb8b1c5..0575b58d92 100644 --- a/phpBB/install/install_install.php +++ b/phpBB/install/install_install.php @@ -1859,6 +1859,7 @@ class install_install extends module 'user_timezone' => 0, 'user_dateformat' => $lang['default_dateformat'], 'user_allow_massemail' => 0, + 'user_allow_pm' => 0, ); $user_id = user_add($user_row); From ad2d560f3f6ab0232728392b2c1c946f2b07902d Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Fri, 16 Nov 2012 14:32:31 +0100 Subject: [PATCH 104/443] [ticket/10184] Query bots table to get the user_ids of the bots PHPBB3-10184 --- phpBB/install/database_update.php | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 8e23434b5b..983b1b46c4 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -2172,10 +2172,24 @@ function change_database_data(&$no_updates, $version) } // Disable receiving pms for bots - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_allow_pm = 0 - WHERE user_type = ' . USER_IGNORE; - $db->sql_query($sql); + $sql = 'SELECT user_id + FROM ' . BOTS_TABLE; + $result = $db->sql_query($sql); + + $bot_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $bot_user_ids[] = (int) $row['user_id']; + } + $db->sql_freeresult($result); + + if (!empty($bot_user_ids)) + { + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_allow_pm = 0 + WHERE ' . $db->sql_in_set('user_id', $bot_user_ids); + _sql($sql, $errored, $error_ary); + } $no_updates = false; break; From d0338531cb2a3a386a3894a1b1b081025f53ea05 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 1 Dec 2012 20:12:31 -0500 Subject: [PATCH 105/443] [ticket/11162] An implementation that actually works. PHPBB3-11162 --- phpBB/includes/functions.php | 73 +++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 8608c6ca4f..13690e79bb 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -1311,12 +1311,75 @@ function tz_select($default = '', $truncate = false) */ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_values, $to_value) { - $db->sql_return_on_error(true); - $condition = $db->sql_in_set($column, $from_values); - $db->sql_query('UPDATE ' . $table . ' SET ' . $column . ' = ' . (int) $to_value. ' WHERE ' . $condition); - $db->sql_return_on_error(false); + $sql = "SELECT $column, user_id + FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $result = $db->sql_query($sql); - $db->sql_query('DELETE FROM ' . $table . ' WHERE ' . $condition); + $old_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $old_user_ids[$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $sql = "SELECT $column, user_id + FROM $table + WHERE $column = '" . (int) $to_value . "'"; + $result = $db->sql_query($sql); + + $new_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $new_user_ids[$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $queries = array(); + $any_found = false; + foreach ($from_values as $from_value) + { + if (!isset($old_user_ids[$from_value])) + { + continue; + } + $any_found = true; + if (empty($new_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value. " + WHERE $column = '" . $db->sql_escape($from_value) . "'"; + $queries[] = $sql; + } + else + { + $different_user_ids = array_diff($old_user_ids[$from_value], $new_user_ids[$to_value]); + if (!empty($different_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value. " + WHERE $column = '" . $db->sql_escape($from_value) . "' + AND " . $db->sql_in_set('user_id', $different_user_ids); + $queries[] = $sql; + } + } + } + + if ($any_found) + { + //$db->sql_transaction('begin'); + + foreach ($queries as $sql) + { + $db->sql_query($sql); + } + + $sql = "DELETE FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $db->sql_query($sql); + + //$db->sql_transaction('commit'); + } } // Functions handling topic/post tracking/marking From 2e947334e563f122c597d7072eddd962453a84ef Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 1 Dec 2012 20:17:01 -0500 Subject: [PATCH 106/443] [ticket/11162] Uncomment transactions. PHPBB3-11162 --- phpBB/includes/functions.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 13690e79bb..a24dcfdf5b 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -1367,7 +1367,7 @@ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_value if ($any_found) { - //$db->sql_transaction('begin'); + $db->sql_transaction('begin'); foreach ($queries as $sql) { @@ -1378,7 +1378,7 @@ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_value WHERE " . $db->sql_in_set($column, $from_values); $db->sql_query($sql); - //$db->sql_transaction('commit'); + $db->sql_transaction('commit'); } } From c2c105df9ff1d8fd48afa1d3abdf23a39584d7ed Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 1 Dec 2012 20:21:29 -0500 Subject: [PATCH 107/443] [ticket/11162] Clarify that only the two tables actually work. PHPBB3-11162 --- phpBB/includes/functions.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index a24dcfdf5b..09487ce10d 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -1302,6 +1302,8 @@ function tz_select($default = '', $truncate = false) * If this results in rows violating uniqueness constraints, the duplicate * rows are eliminated. * +* The only supported tables are bookmarks and topics_watch. +* * @param dbal $db Database object * @param string $table Table on which to perform the update * @param string $column Column whose values to change From 69225bd0a6005e81b7cb58631eb5de7c3d175697 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 1 Dec 2012 20:21:51 -0500 Subject: [PATCH 108/443] [ticket/11162] Use phpbb_update_rows_avoiding_duplicates in mcp. PHPBB3-11162 --- phpBB/includes/mcp/mcp_forum.php | 7 +------ phpBB/includes/mcp/mcp_topic.php | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index b70601b479..913c55a9d1 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -415,12 +415,7 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) $success_msg = 'POSTS_MERGED_SUCCESS'; // If the topic no longer exist, we will update the topic watch table. - // To not let it error out on users watching both topics, we just return on an error... - $db->sql_return_on_error(true); - $db->sql_query('UPDATE ' . TOPICS_WATCH_TABLE . ' SET topic_id = ' . (int) $to_topic_id . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); - $db->sql_return_on_error(false); - - $db->sql_query('DELETE FROM ' . TOPICS_WATCH_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); + phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); // Link to the new topic $return_link .= (($return_link) ? '

      ' : '') . sprintf($user->lang['RETURN_NEW_TOPIC'], '', ''); diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index 7d4edaf362..f40a4bc044 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -620,12 +620,7 @@ function merge_posts($topic_id, $to_topic_id) else { // If the topic no longer exist, we will update the topic watch table. - // To not let it error out on users watching both topics, we just return on an error... - $db->sql_return_on_error(true); - $db->sql_query('UPDATE ' . TOPICS_WATCH_TABLE . ' SET topic_id = ' . (int) $to_topic_id . ' WHERE topic_id = ' . (int) $topic_id); - $db->sql_return_on_error(false); - - $db->sql_query('DELETE FROM ' . TOPICS_WATCH_TABLE . ' WHERE topic_id = ' . (int) $topic_id); + phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); } // Link to the new topic From 05053dacd350c6bacd529df803bdc9876104a278 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 1 Dec 2012 20:24:25 -0500 Subject: [PATCH 109/443] [ticket/11162] Fix inaccurately copy pasted comment. PHPBB3-11162 --- phpBB/includes/mcp/mcp_forum.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index 913c55a9d1..e392bef157 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -414,7 +414,7 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) // Message and return links $success_msg = 'POSTS_MERGED_SUCCESS'; - // If the topic no longer exist, we will update the topic watch table. + // Update the topic watch table. phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); // Link to the new topic From 2fc43e6ed71e4b9abdb76aa179b4e64efaa47ffa Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 1 Dec 2012 23:11:14 -0500 Subject: [PATCH 110/443] [ticket/11162] No whitespace changes in olympus. PHPBB3-11162 --- phpBB/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 09487ce10d..e3feb59d41 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3442,7 +3442,7 @@ function parse_cfg_file($filename, $lines = false) $parsed_items[$key] = $value; } - + if (isset($parsed_items['inherit_from']) && isset($parsed_items['name']) && $parsed_items['inherit_from'] == $parsed_items['name']) { unset($parsed_items['inherit_from']); From 720ef233b122d00ef9d2128c9a0a518ff017b0d7 Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Sat, 1 Dec 2012 22:34:03 -0600 Subject: [PATCH 111/443] [ticket/11219] Only update sequences that are affected by a fixture PHPBB3-11219 --- .../phpbb_database_test_case.php | 18 +++-- ...phpbb_database_test_connection_manager.php | 73 +++++++++++-------- 2 files changed, 55 insertions(+), 36 deletions(-) diff --git a/tests/test_framework/phpbb_database_test_case.php b/tests/test_framework/phpbb_database_test_case.php index 0916679108..429bb92bf1 100644 --- a/tests/test_framework/phpbb_database_test_case.php +++ b/tests/test_framework/phpbb_database_test_case.php @@ -13,6 +13,8 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test protected $test_case_helpers; + protected $fixture_xml_data; + public function __construct($name = NULL, array $data = array(), $dataName = '') { parent::__construct($name, $data, $dataName); @@ -32,10 +34,14 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test { parent::setUp(); - $config = $this->get_database_config(); - $manager = $this->create_connection_manager($config); - $manager->connect(); - $manager->post_setup_synchronisation(); + // Resynchronise tables if a fixture was loaded + if (isset($this->fixture_xml_data)) + { + $config = $this->get_database_config(); + $manager = $this->create_connection_manager($config); + $manager->connect(); + $manager->post_setup_synchronisation($this->fixture_xml_data); + } } public function createXMLDataSet($path) @@ -57,7 +63,9 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test $path = $meta_data['uri']; } - return parent::createXMLDataSet($path); + $this->fixture_xml_data = parent::createXMLDataSet($path); + + return $this->fixture_xml_data; } public function get_test_case_helpers() diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index e79a764e1d..97281a0812 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -429,12 +429,19 @@ class phpbb_database_test_connection_manager /** * Performs synchronisations on the database after a fixture has been loaded + * + * @param PHPUnit_Extensions_Database_DataSet_XmlDataSet $tables Tables contained within the loaded fixture + * + * @return null */ - public function post_setup_synchronisation() + public function post_setup_synchronisation($xmlDataSet) { $this->ensure_connected(__METHOD__); $queries = array(); + // Get escaped versions of the table names used in the fixture + $table_names = array_map(array($this->pdo, 'PDO::quote'), $xmlDataSet->getTableNames()); + switch ($this->config['dbms']) { case 'oracle': @@ -445,7 +452,9 @@ class phpbb_database_test_connection_manager JOIN USER_TRIGGER_COLS tc ON (tc.trigger_name = t.trigger_name) JOIN USER_SEQUENCES s ON (s.sequence_name = d.referenced_name) WHERE d.referenced_type = 'SEQUENCE' - AND d.type = 'TRIGGER'"; + AND d.type = 'TRIGGER' + AND t.table_name IN (" . implode(', ', array_map('strtoupper', $table_names)) . ')'; + $result = $this->pdo->query($sql); while ($row = $result->fetch(PDO::FETCH_ASSOC)) @@ -476,41 +485,43 @@ class phpbb_database_test_connection_manager break; case 'postgres': - // First get the sequences - $sequences = array(); - $sql = "SELECT relname FROM pg_class WHERE relkind = 'S'"; + // Get the sequences attached to the tables + $sql = 'SELECT column_name, table_name FROM information_schema.columns + WHERE table_name IN (' . implode(', ', $table_names) . ") + AND strpos(column_default, '_seq''::regclass') > 0"; $result = $this->pdo->query($sql); + + $setval_queries = array(); while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $sequences[] = $row['relname']; + // Get the columns used in the fixture for this table + $column_names = $xmlDataSet->getTableMetaData($row['table_name'])->getColumns(); + + // Skip sequences that weren't specified in the fixture + if (!in_array($row['column_name'], $column_names)) + { + continue; + } + + // Get the old value if it exists, or use 1 if it doesn't + $sql = "SELECT COALESCE((SELECT MAX({$row['column_name']}) + 1 FROM {$row['table_name']}), 1) AS val"; + $result_max = $this->pdo->query($sql); + $row_max = $result_max->fetch(PDO::FETCH_ASSOC); + + if ($row_max) + { + $seq_name = $this->pdo->quote($row['table_name'] . '_seq'); + $max_val = (int) $row_max['val']; + + // The last parameter is false so that the system doesn't increment it again + $setval_queries[] = "SETVAL($seq_name, $max_val, false)"; + } } - // Now get the name of the column using it - foreach ($sequences as $sequence) + // Combine all of the SETVALs into one query + if (sizeof($setval_queries)) { - $table = str_replace('_seq', '', $sequence); - $sql = "SELECT column_name FROM information_schema.columns - WHERE table_name = '$table' - AND column_default = 'nextval(''$sequence''::regclass)'"; - $result = $this->pdo->query($sql); - $row = $result->fetch(PDO::FETCH_ASSOC); - - // Finally, set the new sequence value - if ($row) - { - $column = $row['column_name']; - - // Get the old value if it exists, or use 1 if it doesn't - $sql = "SELECT COALESCE((SELECT MAX({$column}) + 1 FROM {$table}), 1) AS val"; - $result = $this->pdo->query($sql); - $row = $result->fetch(PDO::FETCH_ASSOC); - - if ($row) - { - // The last parameter is false so that the system doesn't increment it again - $queries[] = "SELECT SETVAL('{$sequence}', {$row['val']}, false)"; - } - } + $queries[] = 'SELECT ' . implode(', ', $setval_queries); } break; } From 6f7e39996c926b0f0080ccdd594fd465c311cb79 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 2 Dec 2012 23:44:49 -0500 Subject: [PATCH 112/443] [ticket/11238] Set goutte version to 0.1.0. PHPBB3-11238 --- phpBB/composer.json | 2 +- phpBB/composer.lock | 463 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 433 insertions(+), 32 deletions(-) diff --git a/phpBB/composer.json b/phpBB/composer.json index c2811ad1d7..8d5dd1d52e 100644 --- a/phpBB/composer.json +++ b/phpBB/composer.json @@ -1,6 +1,6 @@ { "minimum-stability": "beta", "require-dev": { - "fabpot/goutte": "1.0.x-dev" + "fabpot/goutte": "v0.1.0" } } diff --git a/phpBB/composer.lock b/phpBB/composer.lock index 9f2195e70a..a78fff9a14 100644 --- a/phpBB/composer.lock +++ b/phpBB/composer.lock @@ -1,55 +1,456 @@ { - "hash": "a5d02c59e3a91c84c1a96aca0f1ae81a", + "hash": "23352b29002e6d22658e314a8e737f71", "packages": [ - + { + "name": "symfony/event-dispatcher", + "version": "v2.1.4", + "target-dir": "Symfony/Component/EventDispatcher", + "source": { + "type": "git", + "url": "https://github.com/symfony/EventDispatcher", + "reference": "v2.1.4" + }, + "dist": { + "type": "zip", + "url": "https://github.com/symfony/EventDispatcher/archive/v2.1.4.zip", + "reference": "v2.1.4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "symfony/dependency-injection": "2.1.*" + }, + "suggest": { + "symfony/dependency-injection": "2.1.*", + "symfony/http-kernel": "2.1.*" + }, + "time": "2012-11-08 09:51:48", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Symfony\\Component\\EventDispatcher": "" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "http://symfony.com" + } ], "packages-dev": [ { - "package": "fabpot/goutte", - "version": "dev-master", - "alias-pretty-version": "1.0.x-dev", - "alias-version": "1.0.9999999.9999999-dev" + "name": "fabpot/goutte", + "version": "v0.1.0", + "source": { + "type": "git", + "url": "https://github.com/fabpot/Goutte", + "reference": "v0.1.0" + }, + "dist": { + "type": "zip", + "url": "https://github.com/fabpot/Goutte/archive/v0.1.0.zip", + "reference": "v0.1.0", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "ext-curl": "*", + "symfony/browser-kit": "2.1.*", + "symfony/css-selector": "2.1.*", + "symfony/dom-crawler": "2.1.*", + "symfony/finder": "2.1.*", + "symfony/process": "2.1.*", + "guzzle/guzzle": "3.0.*" + }, + "time": "2012-12-02 13:44:35", + "type": "application", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "installation-source": "source", + "autoload": { + "psr-0": { + "Goutte": "." + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "A simple PHP Web Scraper", + "homepage": "https://github.com/fabpot/Goutte", + "keywords": [ + "scraper" + ] }, { - "package": "fabpot/goutte", - "version": "dev-master", - "source-reference": "c2ea8d9a6682d14482e57ede2371001b8a5238d2", - "commit-date": "1340264258" + "name": "guzzle/guzzle", + "version": "v3.0.5", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle", + "reference": "v3.0.5" + }, + "dist": { + "type": "zip", + "url": "https://github.com/guzzle/guzzle/archive/v3.0.5.zip", + "reference": "v3.0.5", + "shasum": "" + }, + "require": { + "php": ">=5.3.2", + "ext-curl": "*", + "symfony/event-dispatcher": "2.1.*" + }, + "replace": { + "guzzle/batch": "self.version", + "guzzle/cache": "self.version", + "guzzle/common": "self.version", + "guzzle/http": "self.version", + "guzzle/inflection": "self.version", + "guzzle/iterator": "self.version", + "guzzle/log": "self.version", + "guzzle/parser": "self.version", + "guzzle/plugin": "self.version", + "guzzle/plugin-async": "self.version", + "guzzle/plugin-backoff": "self.version", + "guzzle/plugin-cache": "self.version", + "guzzle/plugin-cookie": "self.version", + "guzzle/plugin-curlauth": "self.version", + "guzzle/plugin-history": "self.version", + "guzzle/plugin-log": "self.version", + "guzzle/plugin-md5": "self.version", + "guzzle/plugin-mock": "self.version", + "guzzle/plugin-oauth": "self.version", + "guzzle/service": "self.version", + "guzzle/stream": "self.version" + }, + "require-dev": { + "doctrine/common": "*", + "symfony/class-loader": "*", + "monolog/monolog": "1.*", + "zendframework/zend-cache": "2.0.*", + "zendframework/zend-log": "2.0.*", + "zend/zend-log1": "1.12", + "zend/zend-cache1": "1.12", + "phpunit/phpunit": "3.7.*" + }, + "time": "2012-11-19 00:15:33", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Guzzle\\Tests": "tests/", + "Guzzle": "src/" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Guzzle Community", + "homepage": "https://github.com/guzzle/guzzle/contributors" + } + ], + "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "framework", + "curl", + "http", + "rest", + "http client", + "client", + "web service" + ] }, { - "package": "guzzle/guzzle", - "version": "v2.6.6" + "name": "symfony/browser-kit", + "version": "v2.1.4", + "target-dir": "Symfony/Component/BrowserKit", + "source": { + "type": "git", + "url": "https://github.com/symfony/BrowserKit", + "reference": "v2.1.4" + }, + "dist": { + "type": "zip", + "url": "https://github.com/symfony/BrowserKit/archive/v2.1.4.zip", + "reference": "v2.1.4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/dom-crawler": "2.1.*" + }, + "require-dev": { + "symfony/process": "2.1.*", + "symfony/css-selector": "2.1.*" + }, + "suggest": { + "symfony/process": "2.1.*" + }, + "time": "2012-11-08 09:51:48", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Symfony\\Component\\BrowserKit": "" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony BrowserKit Component", + "homepage": "http://symfony.com" }, { - "package": "symfony/browser-kit", - "version": "v2.1.0-BETA3" + "name": "symfony/css-selector", + "version": "v2.1.4", + "target-dir": "Symfony/Component/CssSelector", + "source": { + "type": "git", + "url": "https://github.com/symfony/CssSelector", + "reference": "v2.1.4" + }, + "dist": { + "type": "zip", + "url": "https://github.com/symfony/CssSelector/archive/v2.1.4.zip", + "reference": "v2.1.4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "time": "2012-11-08 09:51:48", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Symfony\\Component\\CssSelector": "" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony CssSelector Component", + "homepage": "http://symfony.com" }, { - "package": "symfony/css-selector", - "version": "v2.1.0-BETA3" + "name": "symfony/dom-crawler", + "version": "v2.1.4", + "target-dir": "Symfony/Component/DomCrawler", + "source": { + "type": "git", + "url": "https://github.com/symfony/DomCrawler", + "reference": "v2.1.4" + }, + "dist": { + "type": "zip", + "url": "https://github.com/symfony/DomCrawler/archive/v2.1.4.zip", + "reference": "v2.1.4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "symfony/css-selector": "2.1.*" + }, + "suggest": { + "symfony/css-selector": "2.1.*" + }, + "time": "2012-11-29 10:32:18", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Symfony\\Component\\DomCrawler": "" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony DomCrawler Component", + "homepage": "http://symfony.com" }, { - "package": "symfony/dom-crawler", - "version": "v2.1.0-BETA3" + "name": "symfony/finder", + "version": "v2.1.4", + "target-dir": "Symfony/Component/Finder", + "source": { + "type": "git", + "url": "https://github.com/symfony/Finder", + "reference": "v2.1.4" + }, + "dist": { + "type": "zip", + "url": "https://github.com/symfony/Finder/archive/v2.1.4.zip", + "reference": "v2.1.4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "time": "2012-11-08 09:51:48", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Symfony\\Component\\Finder": "" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "http://symfony.com" }, { - "package": "symfony/event-dispatcher", - "version": "v2.1.0-BETA3" - }, - { - "package": "symfony/finder", - "version": "v2.1.0-BETA3" - }, - { - "package": "symfony/process", - "version": "v2.1.0-BETA3" + "name": "symfony/process", + "version": "v2.1.4", + "target-dir": "Symfony/Component/Process", + "source": { + "type": "git", + "url": "https://github.com/symfony/Process", + "reference": "v2.1.4" + }, + "dist": { + "type": "zip", + "url": "https://github.com/symfony/Process/archive/v2.1.4.zip", + "reference": "v2.1.4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "time": "2012-11-19 20:53:52", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Symfony\\Component\\Process": "" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "http://symfony.com" } ], "aliases": [ ], "minimum-stability": "beta", - "stability-flags": { - "fabpot/goutte": 20 - } + "stability-flags": [ + + ] } From e845e2ed89f75a5c9f14191f833334d84d389faf Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Tue, 4 Dec 2012 00:40:24 +0100 Subject: [PATCH 113/443] [ticket/11240] Enable PHPUnit's verbose mode so we get a list of skipped tests. PHPBB3-11240 --- travis/phpunit-mysql-travis.xml | 1 + travis/phpunit-postgres-travis.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/travis/phpunit-mysql-travis.xml b/travis/phpunit-mysql-travis.xml index e54b2bb77b..5366494c8b 100644 --- a/travis/phpunit-mysql-travis.xml +++ b/travis/phpunit-mysql-travis.xml @@ -9,6 +9,7 @@ stopOnFailure="false" syntaxCheck="true" strict="true" + verbose="true" bootstrap="../tests/bootstrap.php"> diff --git a/travis/phpunit-postgres-travis.xml b/travis/phpunit-postgres-travis.xml index 55ba996548..0383edd9d6 100644 --- a/travis/phpunit-postgres-travis.xml +++ b/travis/phpunit-postgres-travis.xml @@ -9,6 +9,7 @@ stopOnFailure="false" syntaxCheck="true" strict="true" + verbose="true" bootstrap="../tests/bootstrap.php"> From af2887f3a7f27b33c2ecd14d4baab846b71ddb62 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 03:34:51 -0500 Subject: [PATCH 114/443] [ticket/10716] php parse all php files as part of the test suite. PHPBB3-10716 --- tests/lint_test.php | 49 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 tests/lint_test.php diff --git a/tests/lint_test.php b/tests/lint_test.php new file mode 100644 index 0000000000..57c78ae809 --- /dev/null +++ b/tests/lint_test.php @@ -0,0 +1,49 @@ +check($root); + } + + protected function check($root) + { + $dh = opendir($root); + while (($filename = readdir($dh)) !== false) + { + if ($filename == '.' || $filename == '..' || $filename == 'git') + { + continue; + } + $path = $root . '/' . $filename; + // skip symlinks to avoid infinite loops + if (is_link($path)) + { + continue; + } + if (is_dir($path)) + { + $this->check($path); + } + else if (substr($filename, strlen($filename)-4) == '.php') + { + // assume php binary is called php and it is in PATH + $cmd = 'php -l ' . escapeshellarg($path); + $output = array(); + $status = 1; + exec($cmd, $output, $status); + $output = implode("\n", $output); + $this->assertEquals(0, $status, "php -l failed for $path:\n$output"); + } + } + } +} From 025a95ea909d449e14cb22564983fb005e3f8c06 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 9 Mar 2011 21:50:45 -0500 Subject: [PATCH 115/443] [ticket/10205] Account for potentially missing extensions in dbal. PHPBB3-10205 --- phpBB/includes/db/mssql_odbc.php | 20 +++++++++++++++++++- phpBB/includes/db/mysql.php | 20 +++++++++++++++++++- phpBB/includes/db/mysqli.php | 7 +++++++ phpBB/includes/db/oracle.php | 29 ++++++++++++++++++++++++++++- phpBB/includes/db/sqlite.php | 21 ++++++++++++++++++++- 5 files changed, 93 insertions(+), 4 deletions(-) diff --git a/phpBB/includes/db/mssql_odbc.php b/phpBB/includes/db/mssql_odbc.php index 2ecc42cadf..dabdbd1a44 100644 --- a/phpBB/includes/db/mssql_odbc.php +++ b/phpBB/includes/db/mssql_odbc.php @@ -32,6 +32,7 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); class dbal_mssql_odbc extends dbal { var $last_query_text = ''; + var $connect_error = ''; /** * Connect to server @@ -68,7 +69,24 @@ class dbal_mssql_odbc extends dbal @ini_set('odbc.defaultlrl', $max_size); } - $this->db_connect_id = ($this->persistency) ? @odbc_pconnect($this->server, $this->user, $sqlpassword) : @odbc_connect($this->server, $this->user, $sqlpassword); + if ($this->persistency) + { + if (!function_exists('odbc_pconnect')) + { + $this->connect_error = 'odbc_pconnect function does not exist, is odbc extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @odbc_pconnect($this->server, $this->user, $sqlpassword); + } + else + { + if (!function_exists('odbc_connect')) + { + $this->connect_error = 'odbc_connect function does not exist, is odbc extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @odbc_connect($this->server, $this->user, $sqlpassword); + } return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); } diff --git a/phpBB/includes/db/mysql.php b/phpBB/includes/db/mysql.php index 1ccb785150..ae36fe6425 100644 --- a/phpBB/includes/db/mysql.php +++ b/phpBB/includes/db/mysql.php @@ -30,6 +30,7 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); class dbal_mysql extends dbal { var $multi_insert = true; + var $connect_error = ''; /** * Connect to server @@ -44,7 +45,24 @@ class dbal_mysql extends dbal $this->sql_layer = 'mysql4'; - $this->db_connect_id = ($this->persistency) ? @mysql_pconnect($this->server, $this->user, $sqlpassword) : @mysql_connect($this->server, $this->user, $sqlpassword, $new_link); + if ($this->persistency) + { + if (!function_exists('mysql_pconnect')) + { + $this->connect_error = 'mysql_pconnect function does not exist, is mysql extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @mysql_pconnect($this->server, $this->user, $sqlpassword); + } + else + { + if (!function_exists('mysql_connect')) + { + $this->connect_error = 'mysql_connect function does not exist, is mysql extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @mysql_connect($this->server, $this->user, $sqlpassword, $new_link); + } if ($this->db_connect_id && $this->dbname != '') { diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/mysqli.php index a311b8cda6..98b659723f 100644 --- a/phpBB/includes/db/mysqli.php +++ b/phpBB/includes/db/mysqli.php @@ -27,12 +27,19 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); class dbal_mysqli extends dbal { var $multi_insert = true; + var $connect_error = ''; /** * Connect to server */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false , $new_link = false) { + if (!function_exists('mysqli_connect')) + { + $this->connect_error = 'mysqli_connect function does not exist, is mysqli extension installed?'; + return $this->sql_error(''); + } + // Mysqli extension supports persistent connection since PHP 5.3.0 $this->persistency = (version_compare(PHP_VERSION, '5.3.0', '>=')) ? $persistency : false; $this->user = $sqluser; diff --git a/phpBB/includes/db/oracle.php b/phpBB/includes/db/oracle.php index 62b36aa8bf..42f5de1b24 100644 --- a/phpBB/includes/db/oracle.php +++ b/phpBB/includes/db/oracle.php @@ -25,6 +25,7 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); class dbal_oracle extends dbal { var $last_query_text = ''; + var $connect_error = ''; /** * Connect to server @@ -48,7 +49,33 @@ class dbal_oracle extends dbal $connect = $sqlserver . (($port) ? ':' . $port : '') . '/' . $database; } - $this->db_connect_id = ($new_link) ? @ocinlogon($this->user, $sqlpassword, $connect, 'UTF8') : (($this->persistency) ? @ociplogon($this->user, $sqlpassword, $connect, 'UTF8') : @ocilogon($this->user, $sqlpassword, $connect, 'UTF8')); + if ($new_link) + { + if (!function_exists('ocinlogon')) + { + $this->connect_error = 'ocinlogon function does not exist, is oci extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @ocinlogon($this->user, $sqlpassword, $connect, 'UTF8'); + } + else if ($this->persistency) + { + if (!function_exists('ociplogon')) + { + $this->connect_error = 'ociplogon function does not exist, is oci extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @ociplogon($this->user, $sqlpassword, $connect, 'UTF8'); + } + else + { + if (!function_exists('ocilogon')) + { + $this->connect_error = 'ocilogon function does not exist, is oci extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @ocilogon($this->user, $sqlpassword, $connect, 'UTF8')); + } return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); } diff --git a/phpBB/includes/db/sqlite.php b/phpBB/includes/db/sqlite.php index 8de72fd394..be0ad4fc8f 100644 --- a/phpBB/includes/db/sqlite.php +++ b/phpBB/includes/db/sqlite.php @@ -25,6 +25,8 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); */ class dbal_sqlite extends dbal { + var $connect_error = ''; + /** * Connect to server */ @@ -36,7 +38,24 @@ class dbal_sqlite extends dbal $this->dbname = $database; $error = ''; - $this->db_connect_id = ($this->persistency) ? @sqlite_popen($this->server, 0666, $error) : @sqlite_open($this->server, 0666, $error); + if ($this->persistency) + { + if (!function_exists('sqlite_popen')) + { + $this->connect_error = 'sqlite_popen function does not exist, is sqlite extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @sqlite_popen($this->server, 0666, $error); + } + else + { + if (!function_exists('sqlite_open')) + { + $this->connect_error = 'sqlite_open function does not exist, is sqlite extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @sqlite_open($this->server, 0666, $error); + } if ($this->db_connect_id) { From 1a7e2211c35218094e30ddc399d4aa6b45fe75f4 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 04:06:30 -0500 Subject: [PATCH 116/443] [ticket/10205] Avoid calling mysqli functions when mysqli is missing. PHPBB3-10205 --- phpBB/includes/db/mysqli.php | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/mysqli.php index 98b659723f..cd82a12b58 100644 --- a/phpBB/includes/db/mysqli.php +++ b/phpBB/includes/db/mysqli.php @@ -425,10 +425,20 @@ class dbal_mysqli extends dbal { if (!$this->db_connect_id) { - return array( - 'message' => @mysqli_connect_error(), - 'code' => @mysqli_connect_errno() - ); + if (function_exists('mysqli_connect_error')) + { + return array( + 'message' => @mysqli_connect_error(), + 'code' => @mysqli_connect_errno(), + ); + } + else + { + return array( + 'message' => $this->connect_error, + 'code' => '', + ); + } } return array( From 9f549e8249acbd82b68e961a6e0a31de47d9ca32 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 04:50:41 -0500 Subject: [PATCH 117/443] [ticket/10205] Fix remaining db drivers. PHPBB3-10205 --- phpBB/includes/db/mssql.php | 58 +++++++++++++++++++------------- phpBB/includes/db/mssql_odbc.php | 18 +++++++--- phpBB/includes/db/mysql.php | 18 +++++++--- phpBB/includes/db/oracle.php | 24 +++++++++---- phpBB/includes/db/sqlite.php | 18 +++++++--- 5 files changed, 93 insertions(+), 43 deletions(-) diff --git a/phpBB/includes/db/mssql.php b/phpBB/includes/db/mssql.php index b7178593dc..bc0a870885 100644 --- a/phpBB/includes/db/mssql.php +++ b/phpBB/includes/db/mssql.php @@ -355,34 +355,44 @@ class dbal_mssql extends dbal */ function _sql_error() { - $error = array( - 'message' => @mssql_get_last_message(), - 'code' => '' - ); - - // Get error code number - $result_id = @mssql_query('SELECT @@ERROR as code', $this->db_connect_id); - if ($result_id) + if (function_exists('mssql_get_last_message')) { - $row = @mssql_fetch_assoc($result_id); - $error['code'] = $row['code']; - @mssql_free_result($result_id); - } + $error = array( + 'message' => @mssql_get_last_message(), + 'code' => '' + ); - // Get full error message if possible - $sql = 'SELECT CAST(description as varchar(255)) as message - FROM master.dbo.sysmessages - WHERE error = ' . $error['code']; - $result_id = @mssql_query($sql); - - if ($result_id) - { - $row = @mssql_fetch_assoc($result_id); - if (!empty($row['message'])) + // Get error code number + $result_id = @mssql_query('SELECT @@ERROR as code', $this->db_connect_id); + if ($result_id) { - $error['message'] .= '
      ' . $row['message']; + $row = @mssql_fetch_assoc($result_id); + $error['code'] = $row['code']; + @mssql_free_result($result_id); } - @mssql_free_result($result_id); + + // Get full error message if possible + $sql = 'SELECT CAST(description as varchar(255)) as message + FROM master.dbo.sysmessages + WHERE error = ' . $error['code']; + $result_id = @mssql_query($sql); + + if ($result_id) + { + $row = @mssql_fetch_assoc($result_id); + if (!empty($row['message'])) + { + $error['message'] .= '
      ' . $row['message']; + } + @mssql_free_result($result_id); + } + } + else + { + $error = array( + 'message' => $this->connect_error, + 'code' => '', + ); } return $error; diff --git a/phpBB/includes/db/mssql_odbc.php b/phpBB/includes/db/mssql_odbc.php index dabdbd1a44..e1234389df 100644 --- a/phpBB/includes/db/mssql_odbc.php +++ b/phpBB/includes/db/mssql_odbc.php @@ -360,10 +360,20 @@ class dbal_mssql_odbc extends dbal */ function _sql_error() { - return array( - 'message' => @odbc_errormsg(), - 'code' => @odbc_error() - ); + if (function_exists('odbc_errormsg')) + { + return array( + 'message' => @odbc_errormsg(), + 'code' => @odbc_error() + ); + } + else + { + return array( + 'message' => $this->connect_error, + 'code' => '', + ); + } } /** diff --git a/phpBB/includes/db/mysql.php b/phpBB/includes/db/mysql.php index ae36fe6425..7314e92087 100644 --- a/phpBB/includes/db/mysql.php +++ b/phpBB/includes/db/mysql.php @@ -439,10 +439,20 @@ class dbal_mysql extends dbal { if (!$this->db_connect_id) { - return array( - 'message' => @mysql_error(), - 'code' => @mysql_errno() - ); + if (function_exists('mysql_error')) + { + return array( + 'message' => @mysql_error(), + 'code' => @mysql_errno() + ); + } + else + { + return array( + 'message' => $this->connect_error, + 'code' => '', + ); + } } return array( diff --git a/phpBB/includes/db/oracle.php b/phpBB/includes/db/oracle.php index 42f5de1b24..b234d8b45e 100644 --- a/phpBB/includes/db/oracle.php +++ b/phpBB/includes/db/oracle.php @@ -674,17 +674,27 @@ class dbal_oracle extends dbal */ function _sql_error() { - $error = @ocierror(); - $error = (!$error) ? @ocierror($this->query_result) : $error; - $error = (!$error) ? @ocierror($this->db_connect_id) : $error; - - if ($error) + if (function_exists('ocierror')) { - $this->last_error_result = $error; + $error = @ocierror(); + $error = (!$error) ? @ocierror($this->query_result) : $error; + $error = (!$error) ? @ocierror($this->db_connect_id) : $error; + + if ($error) + { + $this->last_error_result = $error; + } + else + { + $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); + } } else { - $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); + $error = array( + 'message' => $this->connect_error, + 'code' => '', + ); } return $error; diff --git a/phpBB/includes/db/sqlite.php b/phpBB/includes/db/sqlite.php index be0ad4fc8f..3c9b2cce34 100644 --- a/phpBB/includes/db/sqlite.php +++ b/phpBB/includes/db/sqlite.php @@ -300,10 +300,20 @@ class dbal_sqlite extends dbal */ function _sql_error() { - return array( - 'message' => @sqlite_error_string(@sqlite_last_error($this->db_connect_id)), - 'code' => @sqlite_last_error($this->db_connect_id) - ); + if (function_exists('sqlite_error_string')) + { + return array( + 'message' => @sqlite_error_string(@sqlite_last_error($this->db_connect_id)), + 'code' => @sqlite_last_error($this->db_connect_id) + ); + } + else + { + return array( + 'message' => $this->connect_error, + 'code' => '', + ); + } } /** From 4133fae99ec4146a01c67f6a6b3020020d1c6464 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 13:58:14 -0500 Subject: [PATCH 118/443] [ticket/10716] Only lint on php 5.3+. PHPBB3-10716 --- tests/lint_test.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/lint_test.php b/tests/lint_test.php index 57c78ae809..1642b571dd 100644 --- a/tests/lint_test.php +++ b/tests/lint_test.php @@ -11,6 +11,11 @@ class phpbb_lint_test extends phpbb_test_case { public function test_lint() { + if (version_compare(PHP_VERSION, '5.3.0', '<')) + { + $this->markTestSkipped('phpBB uses PHP 5.3 syntax in some files, linting on PHP < 5.3 will fail'); + } + $root = dirname(__FILE__) . '/..'; $this->check($root); } From 40db60e45f3d7af01a96f9da6b36db2606b3d147 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 16:07:02 -0500 Subject: [PATCH 119/443] [ticket/10205] Fix a parse error in oracle driver. PHPBB3-10205 --- phpBB/includes/db/oracle.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/db/oracle.php b/phpBB/includes/db/oracle.php index b234d8b45e..4a7a4ecc8c 100644 --- a/phpBB/includes/db/oracle.php +++ b/phpBB/includes/db/oracle.php @@ -74,7 +74,7 @@ class dbal_oracle extends dbal $this->connect_error = 'ocilogon function does not exist, is oci extension installed?'; return $this->sql_error(''); } - $this->db_connect_id = @ocilogon($this->user, $sqlpassword, $connect, 'UTF8')); + $this->db_connect_id = @ocilogon($this->user, $sqlpassword, $connect, 'UTF8'); } return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); From de2fe1a308b08af868f22d6d9c0b7007f66de676 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 16:12:31 -0500 Subject: [PATCH 120/443] [ticket/10205] Convert mssqlnative driver to the same logic. PHPBB3-10205 --- phpBB/includes/db/mssqlnative.php | 52 +++++++++++++++++++------------ 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php index 3ad0ff3e11..e5de30faf6 100644 --- a/phpBB/includes/db/mssqlnative.php +++ b/phpBB/includes/db/mssqlnative.php @@ -199,16 +199,18 @@ class dbal_mssqlnative extends dbal var $m_insert_id = NULL; var $last_query_text = ''; var $query_options = array(); + var $connect_error = ''; /** * Connect to server */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) { - # Test for driver support, to avoid suppressed fatal error + // Test for driver support, to avoid suppressed fatal error if (!function_exists('sqlsrv_connect')) { - trigger_error('Native MS SQL Server driver for PHP is missing or needs to be updated. Version 1.1 or later is required to install phpBB3. You can download the driver from: http://www.microsoft.com/sqlserver/2005/en/us/PHP-Driver.aspx\n', E_USER_ERROR); + $this->connect_error = 'Native MS SQL Server driver for PHP is missing or needs to be updated. Version 1.1 or later is required to install phpBB3. You can download the driver from: http://www.microsoft.com/sqlserver/2005/en/us/PHP-Driver.aspx'; + return $this->sql_error(''); } //set up connection variables @@ -514,31 +516,41 @@ class dbal_mssqlnative extends dbal */ function _sql_error() { - $errors = @sqlsrv_errors(SQLSRV_ERR_ERRORS); - $error_message = ''; - $code = 0; - - if ($errors != null) + if (function_exists('sqlsrv_errors')) { - foreach ($errors as $error) + $errors = @sqlsrv_errors(SQLSRV_ERR_ERRORS); + $error_message = ''; + $code = 0; + + if ($errors != null) { - $error_message .= "SQLSTATE: ".$error[ 'SQLSTATE']."\n"; - $error_message .= "code: ".$error[ 'code']."\n"; - $code = $error['code']; - $error_message .= "message: ".$error[ 'message']."\n"; + foreach ($errors as $error) + { + $error_message .= "SQLSTATE: ".$error[ 'SQLSTATE']."\n"; + $error_message .= "code: ".$error[ 'code']."\n"; + $code = $error['code']; + $error_message .= "message: ".$error[ 'message']."\n"; + } + $this->last_error_result = $error_message; + $error = $this->last_error_result; } - $this->last_error_result = $error_message; - $error = $this->last_error_result; + else + { + $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); + } + + return array( + 'message' => $error, + 'code' => $code, + ); } else { - $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); + return array( + 'message' => $this->connect_error, + 'code' => '', + ); } - - return array( - 'message' => $error, - 'code' => $code, - ); } /** From dc521692f3c6d65b842a42f68bc727c8a36c9042 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 16:14:39 -0500 Subject: [PATCH 121/443] [ticket/10205] Check for function existence in mssql connect method. PHPBB3-10205 --- phpBB/includes/db/mssql.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/phpBB/includes/db/mssql.php b/phpBB/includes/db/mssql.php index bc0a870885..3792e82aa0 100644 --- a/phpBB/includes/db/mssql.php +++ b/phpBB/includes/db/mssql.php @@ -25,11 +25,19 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); */ class dbal_mssql extends dbal { + var $connect_error = ''; + /** * Connect to server */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) { + if (!function_exists('mssql_connect')) + { + $this->connect_error = 'mssql_connect function does not exist, is mssql extension installed?'; + return $this->sql_error(''); + } + $this->persistency = $persistency; $this->user = $sqluser; $this->dbname = $database; From f3c043a5696610ed1312a734b3f3ed1b613fc4f4 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 16:29:37 -0500 Subject: [PATCH 122/443] [ticket/10205] Test failed connection attempts. PHPBB3-10205 --- tests/dbal/connect_test.php | 44 +++++++++++++++++++++++++++++++++++++ tests/fixtures/empty.xml | 5 +++++ 2 files changed, 49 insertions(+) create mode 100644 tests/dbal/connect_test.php create mode 100644 tests/fixtures/empty.xml diff --git a/tests/dbal/connect_test.php b/tests/dbal/connect_test.php new file mode 100644 index 0000000000..4964f24ba2 --- /dev/null +++ b/tests/dbal/connect_test.php @@ -0,0 +1,44 @@ +createXMLDataSet(dirname(__FILE__) . '/../fixtures/empty.xml'); + } + + public function test_failing_connect() + { + global $phpbb_root_path, $phpEx; + + $config = $this->get_database_config(); + + require_once dirname(__FILE__) . '/../../phpBB/includes/db/' . $config['dbms'] . '.php'; + $dbal = 'dbal_' . $config['dbms']; + $db = new $dbal(); + + // Failure to connect results in a trigger_error call in dbal. + // phpunit converts triggered errors to exceptions. + // In particular there should be no fatals here. + try + { + $db->sql_connect($config['dbhost'], 'phpbbogus', 'phpbbogus', 'phpbbogus', $config['dbport']); + $this->assertFalse(true); + } catch (Exception $e) + { + // should have a legitimate message + $this->assertNotEmpty($e->getMessage()); + } + + return $db; + } +} diff --git a/tests/fixtures/empty.xml b/tests/fixtures/empty.xml new file mode 100644 index 0000000000..96eb1ab483 --- /dev/null +++ b/tests/fixtures/empty.xml @@ -0,0 +1,5 @@ + + + +
      +
      From 2d3882c4124e928dccd050da3d3ccafa54b9ff20 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 16:32:57 -0500 Subject: [PATCH 123/443] [ticket/10205] Delete stray return. PHPBB3-10205 --- tests/dbal/connect_test.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/dbal/connect_test.php b/tests/dbal/connect_test.php index 4964f24ba2..cefd76aa16 100644 --- a/tests/dbal/connect_test.php +++ b/tests/dbal/connect_test.php @@ -38,7 +38,5 @@ class phpbb_dbal_connect_test extends phpbb_database_test_case // should have a legitimate message $this->assertNotEmpty($e->getMessage()); } - - return $db; } } From 8897efe087195ba31920c6b3aadbe8ea1b393c12 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 16:42:58 -0500 Subject: [PATCH 124/443] [ticket/10716] Exclude our dependencies from linting. PHPBB3-10716 --- tests/lint_test.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/lint_test.php b/tests/lint_test.php index 1642b571dd..67b7413cb4 100644 --- a/tests/lint_test.php +++ b/tests/lint_test.php @@ -9,6 +9,17 @@ class phpbb_lint_test extends phpbb_test_case { + static protected $exclude; + + static public function setUpBeforeClass() + { + self::$exclude = array( + // PHP Fatal error: Cannot declare class Container because the name is already in use in /var/www/projects/phpbb3/tests/../phpBB/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services1-1.php on line 20 + // https://gist.github.com/e003913ffd493da63cbc + dirname(__FILE__) . '/../phpBB/vendor', + ); + } + public function test_lint() { if (version_compare(PHP_VERSION, '5.3.0', '<')) @@ -35,7 +46,7 @@ class phpbb_lint_test extends phpbb_test_case { continue; } - if (is_dir($path)) + if (is_dir($path) && !in_array($path, self::$exclude)) { $this->check($path); } From bdc3ddf2bcec3caa9047d03e954c9de82f4916aa Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 17:19:25 -0500 Subject: [PATCH 125/443] [ticket/10491] Set up functional tests sensibly. PHPBB_FUNCTIONAL_URL goes into setup before class. Drop PHPBB_FUNCTIONAL_URL check in board installation and silent return if it is not set. Take board installation out of constructor. Install board in setup method. PHPBB3-10491 --- .../phpbb_functional_test_case.php | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 7c03f874e9..85019a5e31 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -33,11 +33,27 @@ class phpbb_functional_test_case extends phpbb_test_case static protected $config = array(); static protected $already_installed = false; - public function setUp() + static public function setUpBeforeClass() { + parent::setUpBeforeClass(); + + self::$config = phpbb_test_case_helpers::get_test_config(); + if (!isset(self::$config['phpbb_functional_url'])) { - $this->markTestSkipped('phpbb_functional_url was not set in test_config and wasn\'t set as PHPBB_FUNCTIONAL_URL environment variable either.'); + self::markTestSkipped('phpbb_functional_url was not set in test_config and wasn\'t set as PHPBB_FUNCTIONAL_URL environment variable either.'); + } + } + + public function setUp() + { + parent::setUp(); + + if (!static::$already_installed) + { + $this->install_board(); + $this->bootstrap(); + static::$already_installed = true; } $this->cookieJar = new CookieJar; @@ -91,26 +107,12 @@ class phpbb_functional_test_case extends phpbb_test_case $this->backupStaticAttributesBlacklist += array( 'phpbb_functional_test_case' => array('config', 'already_installed'), ); - - if (!static::$already_installed) - { - $this->install_board(); - $this->bootstrap(); - static::$already_installed = true; - } } protected function install_board() { global $phpbb_root_path, $phpEx; - self::$config = phpbb_test_case_helpers::get_test_config(); - - if (!isset(self::$config['phpbb_functional_url'])) - { - return; - } - self::$config['table_prefix'] = 'phpbb_'; $this->recreate_database(self::$config); @@ -158,6 +160,7 @@ class phpbb_functional_test_case extends phpbb_test_case // end data $content = $this->do_request('install'); + $this->assertNotSame(false, $content); $this->assertContains('Welcome to Installation', $content); $this->do_request('create_table', $data); From 38d2868ba8db0f6e24fdfb7bbdfef4925a97770c Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 17:37:46 -0500 Subject: [PATCH 126/443] [ticket/10491] Move board installation into setup before class. Functional posting test already assumed that board is installed once per test case and not once per test. PHPBB3-10491 --- .../phpbb_functional_test_case.php | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 85019a5e31..66f4b6db65 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -31,7 +31,6 @@ class phpbb_functional_test_case extends phpbb_test_case protected $lang = array(); static protected $config = array(); - static protected $already_installed = false; static public function setUpBeforeClass() { @@ -43,18 +42,15 @@ class phpbb_functional_test_case extends phpbb_test_case { self::markTestSkipped('phpbb_functional_url was not set in test_config and wasn\'t set as PHPBB_FUNCTIONAL_URL environment variable either.'); } + + self::install_board(); } public function setUp() { parent::setUp(); - if (!static::$already_installed) - { - $this->install_board(); - $this->bootstrap(); - static::$already_installed = true; - } + $this->bootstrap(); $this->cookieJar = new CookieJar; $this->client = new Goutte\Client(array(), null, $this->cookieJar); @@ -109,12 +105,12 @@ class phpbb_functional_test_case extends phpbb_test_case ); } - protected function install_board() + static protected function install_board() { global $phpbb_root_path, $phpEx; self::$config['table_prefix'] = 'phpbb_'; - $this->recreate_database(self::$config); + self::recreate_database(self::$config); if (file_exists($phpbb_root_path . "config.$phpEx")) { @@ -159,20 +155,20 @@ class phpbb_functional_test_case extends phpbb_test_case )); // end data - $content = $this->do_request('install'); - $this->assertNotSame(false, $content); - $this->assertContains('Welcome to Installation', $content); + $content = self::do_request('install'); + self::assertNotSame(false, $content); + self::assertContains('Welcome to Installation', $content); - $this->do_request('create_table', $data); + self::do_request('create_table', $data); - $this->do_request('config_file', $data); + self::do_request('config_file', $data); file_put_contents($phpbb_root_path . "config.$phpEx", phpbb_create_config_file_data($data, self::$config['dbms'], array(), true, true)); - $this->do_request('final', $data); + self::do_request('final', $data); copy($phpbb_root_path . "config.$phpEx", $phpbb_root_path . "config_test.$phpEx"); } - private function do_request($sub, $post_data = null) + static private function do_request($sub, $post_data = null) { $context = null; From 8ea52b56197cc9a234d6b0ce3ddd10820feb6dd1 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 17:43:36 -0500 Subject: [PATCH 127/443] [ticket/10716] Skip test if php is not in PATH. PHPBB3-10716 --- tests/lint_test.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/lint_test.php b/tests/lint_test.php index 67b7413cb4..d73ab7fedd 100644 --- a/tests/lint_test.php +++ b/tests/lint_test.php @@ -13,6 +13,14 @@ class phpbb_lint_test extends phpbb_test_case static public function setUpBeforeClass() { + $output = array(); + $status = 1; + exec('php -v', $output, $status); + if ($status) + { + self::markTestSkipped("php is not in PATH or broken: $output"); + } + self::$exclude = array( // PHP Fatal error: Cannot declare class Container because the name is already in use in /var/www/projects/phpbb3/tests/../phpBB/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services1-1.php on line 20 // https://gist.github.com/e003913ffd493da63cbc From fb261e19ffc3bf19477510fa3877a8d9ea251655 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 18:52:27 -0500 Subject: [PATCH 128/443] [ticket/10716] Collect standard error from executed php process. php executes everything via a shell. The standard error of this top level shell is not captured by exec/shell_exec/popen/etc. and there is no way to capture it. proc_open might work but it is a nightmare to use and without multiplexing reads from standard error and standard output it can deadlock. Thus the solution in this commit. Put the command into a subshell and redirect standard error to standard output for the subshell. PHPBB3-10716 --- tests/lint_test.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/lint_test.php b/tests/lint_test.php index d73ab7fedd..905067072d 100644 --- a/tests/lint_test.php +++ b/tests/lint_test.php @@ -15,9 +15,10 @@ class phpbb_lint_test extends phpbb_test_case { $output = array(); $status = 1; - exec('php -v', $output, $status); + exec('(php -v) 2>&1', $output, $status); if ($status) { + $output = implode("\n", $output); self::markTestSkipped("php is not in PATH or broken: $output"); } @@ -61,7 +62,7 @@ class phpbb_lint_test extends phpbb_test_case else if (substr($filename, strlen($filename)-4) == '.php') { // assume php binary is called php and it is in PATH - $cmd = 'php -l ' . escapeshellarg($path); + $cmd = '(php -l ' . escapeshellarg($path) . ') 2>&1'; $output = array(); $status = 1; exec($cmd, $output, $status); From 29c4da6162902d3c0d766a8acb17e5a2cf02f901 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 19:00:42 -0500 Subject: [PATCH 129/443] [ticket/10205] Add some columns to the empty fixture file for mssqlnative. Supposedly it choked on the version without any columns thusly: phpbb_dbal_connect_test::test_failing_connect PDOException: SQLSTATE[HY090]: [Microsoft][ODBC Driver Manager] Invalid string or buffer length PHPBB3-10205 --- tests/fixtures/empty.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/fixtures/empty.xml b/tests/fixtures/empty.xml index 96eb1ab483..195e30e38d 100644 --- a/tests/fixtures/empty.xml +++ b/tests/fixtures/empty.xml @@ -1,5 +1,9 @@ - +
      + session_id + session_user_id + session_ip + session_browser
      From 89c9c9d4b0daa7308fd015e8a6fca6386a8b8016 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 21:22:33 -0500 Subject: [PATCH 130/443] [ticket/10205] Cosmetic changes. PHPBB3-10205 --- phpBB/includes/db/mssql.php | 2 +- phpBB/includes/db/mssql_odbc.php | 2 +- phpBB/includes/db/mssqlnative.php | 6 +++--- phpBB/includes/db/mysql.php | 4 ++-- phpBB/includes/db/sqlite.php | 2 +- tests/dbal/connect_test.php | 3 ++- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/phpBB/includes/db/mssql.php b/phpBB/includes/db/mssql.php index 3792e82aa0..2dd95c2508 100644 --- a/phpBB/includes/db/mssql.php +++ b/phpBB/includes/db/mssql.php @@ -367,7 +367,7 @@ class dbal_mssql extends dbal { $error = array( 'message' => @mssql_get_last_message(), - 'code' => '' + 'code' => '', ); // Get error code number diff --git a/phpBB/includes/db/mssql_odbc.php b/phpBB/includes/db/mssql_odbc.php index e1234389df..47792d74ab 100644 --- a/phpBB/includes/db/mssql_odbc.php +++ b/phpBB/includes/db/mssql_odbc.php @@ -364,7 +364,7 @@ class dbal_mssql_odbc extends dbal { return array( 'message' => @odbc_errormsg(), - 'code' => @odbc_error() + 'code' => @odbc_error(), ); } else diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php index e5de30faf6..41ac0a1784 100644 --- a/phpBB/includes/db/mssqlnative.php +++ b/phpBB/includes/db/mssqlnative.php @@ -526,10 +526,10 @@ class dbal_mssqlnative extends dbal { foreach ($errors as $error) { - $error_message .= "SQLSTATE: ".$error[ 'SQLSTATE']."\n"; - $error_message .= "code: ".$error[ 'code']."\n"; + $error_message .= "SQLSTATE: " . $error[ 'SQLSTATE'] . "\n"; + $error_message .= "code: " . $error[ 'code'] . "\n"; $code = $error['code']; - $error_message .= "message: ".$error[ 'message']."\n"; + $error_message .= "message: " . $error[ 'message'] . "\n"; } $this->last_error_result = $error_message; $error = $this->last_error_result; diff --git a/phpBB/includes/db/mysql.php b/phpBB/includes/db/mysql.php index 7314e92087..0125be0917 100644 --- a/phpBB/includes/db/mysql.php +++ b/phpBB/includes/db/mysql.php @@ -443,7 +443,7 @@ class dbal_mysql extends dbal { return array( 'message' => @mysql_error(), - 'code' => @mysql_errno() + 'code' => @mysql_errno(), ); } else @@ -457,7 +457,7 @@ class dbal_mysql extends dbal return array( 'message' => @mysql_error($this->db_connect_id), - 'code' => @mysql_errno($this->db_connect_id) + 'code' => @mysql_errno($this->db_connect_id), ); } diff --git a/phpBB/includes/db/sqlite.php b/phpBB/includes/db/sqlite.php index 3c9b2cce34..199b4eed23 100644 --- a/phpBB/includes/db/sqlite.php +++ b/phpBB/includes/db/sqlite.php @@ -304,7 +304,7 @@ class dbal_sqlite extends dbal { return array( 'message' => @sqlite_error_string(@sqlite_last_error($this->db_connect_id)), - 'code' => @sqlite_last_error($this->db_connect_id) + 'code' => @sqlite_last_error($this->db_connect_id), ); } else diff --git a/tests/dbal/connect_test.php b/tests/dbal/connect_test.php index cefd76aa16..505ce28fa1 100644 --- a/tests/dbal/connect_test.php +++ b/tests/dbal/connect_test.php @@ -33,7 +33,8 @@ class phpbb_dbal_connect_test extends phpbb_database_test_case { $db->sql_connect($config['dbhost'], 'phpbbogus', 'phpbbogus', 'phpbbogus', $config['dbport']); $this->assertFalse(true); - } catch (Exception $e) + } + catch (Exception $e) { // should have a legitimate message $this->assertNotEmpty($e->getMessage()); From 597dea1e047b94f0a862f7f6e650771ffc780141 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 21:32:02 -0500 Subject: [PATCH 131/443] [ticket/10205] Rewrite _sql_error implementations to have a single return. PHPBB3-10205 --- phpBB/includes/db/mssql_odbc.php | 6 ++++-- phpBB/includes/db/mssqlnative.php | 6 ++++-- phpBB/includes/db/mysql.php | 18 +++++++++++------- phpBB/includes/db/mysqli.php | 18 +++++++++++------- phpBB/includes/db/sqlite.php | 6 ++++-- 5 files changed, 34 insertions(+), 20 deletions(-) diff --git a/phpBB/includes/db/mssql_odbc.php b/phpBB/includes/db/mssql_odbc.php index 47792d74ab..04501cce8b 100644 --- a/phpBB/includes/db/mssql_odbc.php +++ b/phpBB/includes/db/mssql_odbc.php @@ -362,18 +362,20 @@ class dbal_mssql_odbc extends dbal { if (function_exists('odbc_errormsg')) { - return array( + $error = array( 'message' => @odbc_errormsg(), 'code' => @odbc_error(), ); } else { - return array( + $error = array( 'message' => $this->connect_error, 'code' => '', ); } + + return $error; } /** diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php index 41ac0a1784..b91372ac61 100644 --- a/phpBB/includes/db/mssqlnative.php +++ b/phpBB/includes/db/mssqlnative.php @@ -539,18 +539,20 @@ class dbal_mssqlnative extends dbal $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); } - return array( + $error = array( 'message' => $error, 'code' => $code, ); } else { - return array( + $error = array( 'message' => $this->connect_error, 'code' => '', ); } + + return $error; } /** diff --git a/phpBB/includes/db/mysql.php b/phpBB/includes/db/mysql.php index 0125be0917..e638531f51 100644 --- a/phpBB/includes/db/mysql.php +++ b/phpBB/includes/db/mysql.php @@ -437,28 +437,32 @@ class dbal_mysql extends dbal */ function _sql_error() { - if (!$this->db_connect_id) + if ($this->db_connect_id) + { + $error = array( + 'message' => @mysql_error($this->db_connect_id), + 'code' => @mysql_errno($this->db_connect_id), + ); + } + else { if (function_exists('mysql_error')) { - return array( + $error = array( 'message' => @mysql_error(), 'code' => @mysql_errno(), ); } else { - return array( + $error = array( 'message' => $this->connect_error, 'code' => '', ); } } - return array( - 'message' => @mysql_error($this->db_connect_id), - 'code' => @mysql_errno($this->db_connect_id), - ); + return $error; } /** diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/mysqli.php index cd82a12b58..b2a43d35f9 100644 --- a/phpBB/includes/db/mysqli.php +++ b/phpBB/includes/db/mysqli.php @@ -423,28 +423,32 @@ class dbal_mysqli extends dbal */ function _sql_error() { - if (!$this->db_connect_id) + if ($this->db_connect_id) + { + $error = array( + 'message' => @mysqli_error($this->db_connect_id), + 'code' => @mysqli_errno($this->db_connect_id) + ); + } + else { if (function_exists('mysqli_connect_error')) { - return array( + $error = array( 'message' => @mysqli_connect_error(), 'code' => @mysqli_connect_errno(), ); } else { - return array( + $error = array( 'message' => $this->connect_error, 'code' => '', ); } } - return array( - 'message' => @mysqli_error($this->db_connect_id), - 'code' => @mysqli_errno($this->db_connect_id) - ); + return $error; } /** diff --git a/phpBB/includes/db/sqlite.php b/phpBB/includes/db/sqlite.php index 199b4eed23..557b057cce 100644 --- a/phpBB/includes/db/sqlite.php +++ b/phpBB/includes/db/sqlite.php @@ -302,18 +302,20 @@ class dbal_sqlite extends dbal { if (function_exists('sqlite_error_string')) { - return array( + $error = array( 'message' => @sqlite_error_string(@sqlite_last_error($this->db_connect_id)), 'code' => @sqlite_last_error($this->db_connect_id), ); } else { - return array( + $error = array( 'message' => $this->connect_error, 'code' => '', ); } + + return $error; } /** From 5120f36a258ffcbffd5c10e9a1056d64ea794a16 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 21:33:13 -0500 Subject: [PATCH 132/443] [ticket/10205] Reduce nesting in mysql drivers. PHPBB3-10205 --- phpBB/includes/db/mysql.php | 25 +++++++++++-------------- phpBB/includes/db/mysqli.php | 25 +++++++++++-------------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/phpBB/includes/db/mysql.php b/phpBB/includes/db/mysql.php index e638531f51..252cb20bd4 100644 --- a/phpBB/includes/db/mysql.php +++ b/phpBB/includes/db/mysql.php @@ -444,22 +444,19 @@ class dbal_mysql extends dbal 'code' => @mysql_errno($this->db_connect_id), ); } + else if (function_exists('mysql_error')) + { + $error = array( + 'message' => @mysql_error(), + 'code' => @mysql_errno(), + ); + } else { - if (function_exists('mysql_error')) - { - $error = array( - 'message' => @mysql_error(), - 'code' => @mysql_errno(), - ); - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } + $error = array( + 'message' => $this->connect_error, + 'code' => '', + ); } return $error; diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/mysqli.php index b2a43d35f9..69f1d26a40 100644 --- a/phpBB/includes/db/mysqli.php +++ b/phpBB/includes/db/mysqli.php @@ -430,22 +430,19 @@ class dbal_mysqli extends dbal 'code' => @mysqli_errno($this->db_connect_id) ); } + else if (function_exists('mysqli_connect_error')) + { + $error = array( + 'message' => @mysqli_connect_error(), + 'code' => @mysqli_connect_errno(), + ); + } else { - if (function_exists('mysqli_connect_error')) - { - $error = array( - 'message' => @mysqli_connect_error(), - 'code' => @mysqli_connect_errno(), - ); - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } + $error = array( + 'message' => $this->connect_error, + 'code' => '', + ); } return $error; From 0f96b1aad378b1fc40620ea57df5ee89224fd5eb Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 23:35:34 -0500 Subject: [PATCH 133/443] [ticket/11162] Move to a separate file to avoid blowing out functions.php. PHPBB3-11162 --- phpBB/includes/functions.php | 87 --------------- phpBB/includes/functions_tricky_update.php | 103 ++++++++++++++++++ .../fixtures/duplicates.xml | 0 .../update_rows_avoiding_duplicates_test.php | 2 +- 4 files changed, 104 insertions(+), 88 deletions(-) create mode 100644 phpBB/includes/functions_tricky_update.php rename tests/{functions => functions_tricky_update}/fixtures/duplicates.xml (100%) rename tests/{functions => functions_tricky_update}/update_rows_avoiding_duplicates_test.php (98%) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index e3feb59d41..65d8be32ad 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -1297,93 +1297,6 @@ function tz_select($default = '', $truncate = false) return $tz_select; } -/** -* Updates rows in given table from a set of values to a new value. -* If this results in rows violating uniqueness constraints, the duplicate -* rows are eliminated. -* -* The only supported tables are bookmarks and topics_watch. -* -* @param dbal $db Database object -* @param string $table Table on which to perform the update -* @param string $column Column whose values to change -* @param array $from_values An array of values that should be changed -* @param int $to_value The new value -* @return null -*/ -function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_values, $to_value) -{ - $sql = "SELECT $column, user_id - FROM $table - WHERE " . $db->sql_in_set($column, $from_values); - $result = $db->sql_query($sql); - - $old_user_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $old_user_ids[$row[$column]][] = $row['user_id']; - } - $db->sql_freeresult($result); - - $sql = "SELECT $column, user_id - FROM $table - WHERE $column = '" . (int) $to_value . "'"; - $result = $db->sql_query($sql); - - $new_user_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $new_user_ids[$row[$column]][] = $row['user_id']; - } - $db->sql_freeresult($result); - - $queries = array(); - $any_found = false; - foreach ($from_values as $from_value) - { - if (!isset($old_user_ids[$from_value])) - { - continue; - } - $any_found = true; - if (empty($new_user_ids)) - { - $sql = "UPDATE $table - SET $column = " . (int) $to_value. " - WHERE $column = '" . $db->sql_escape($from_value) . "'"; - $queries[] = $sql; - } - else - { - $different_user_ids = array_diff($old_user_ids[$from_value], $new_user_ids[$to_value]); - if (!empty($different_user_ids)) - { - $sql = "UPDATE $table - SET $column = " . (int) $to_value. " - WHERE $column = '" . $db->sql_escape($from_value) . "' - AND " . $db->sql_in_set('user_id', $different_user_ids); - $queries[] = $sql; - } - } - } - - if ($any_found) - { - $db->sql_transaction('begin'); - - foreach ($queries as $sql) - { - $db->sql_query($sql); - } - - $sql = "DELETE FROM $table - WHERE " . $db->sql_in_set($column, $from_values); - $db->sql_query($sql); - - $db->sql_transaction('commit'); - } -} - // Functions handling topic/post tracking/marking /** diff --git a/phpBB/includes/functions_tricky_update.php b/phpBB/includes/functions_tricky_update.php new file mode 100644 index 0000000000..a5b9fdacd0 --- /dev/null +++ b/phpBB/includes/functions_tricky_update.php @@ -0,0 +1,103 @@ +sql_in_set($column, $from_values); + $result = $db->sql_query($sql); + + $old_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $old_user_ids[$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $sql = "SELECT $column, user_id + FROM $table + WHERE $column = '" . (int) $to_value . "'"; + $result = $db->sql_query($sql); + + $new_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $new_user_ids[$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $queries = array(); + $any_found = false; + foreach ($from_values as $from_value) + { + if (!isset($old_user_ids[$from_value])) + { + continue; + } + $any_found = true; + if (empty($new_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value. " + WHERE $column = '" . $db->sql_escape($from_value) . "'"; + $queries[] = $sql; + } + else + { + $different_user_ids = array_diff($old_user_ids[$from_value], $new_user_ids[$to_value]); + if (!empty($different_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value. " + WHERE $column = '" . $db->sql_escape($from_value) . "' + AND " . $db->sql_in_set('user_id', $different_user_ids); + $queries[] = $sql; + } + } + } + + if ($any_found) + { + $db->sql_transaction('begin'); + + foreach ($queries as $sql) + { + $db->sql_query($sql); + } + + $sql = "DELETE FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $db->sql_query($sql); + + $db->sql_transaction('commit'); + } +} diff --git a/tests/functions/fixtures/duplicates.xml b/tests/functions_tricky_update/fixtures/duplicates.xml similarity index 100% rename from tests/functions/fixtures/duplicates.xml rename to tests/functions_tricky_update/fixtures/duplicates.xml diff --git a/tests/functions/update_rows_avoiding_duplicates_test.php b/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php similarity index 98% rename from tests/functions/update_rows_avoiding_duplicates_test.php rename to tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php index 0d68e22d4a..6940122393 100644 --- a/tests/functions/update_rows_avoiding_duplicates_test.php +++ b/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php @@ -7,7 +7,7 @@ * */ -require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/functions_tricky_update.php'; class phpbb_update_rows_avoiding_duplicates_test extends phpbb_database_test_case { From abca64b1dfbe11f73675a3e5457fb9f0038f1cb6 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 23:37:14 -0500 Subject: [PATCH 134/443] [ticket/11162] Add includes. PHPBB3-11162 --- phpBB/includes/mcp/mcp_forum.php | 4 ++++ phpBB/includes/mcp/mcp_topic.php | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index e392bef157..3603224735 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -415,6 +415,10 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) $success_msg = 'POSTS_MERGED_SUCCESS'; // Update the topic watch table. + if (!function_exists('phpbb_update_rows_avoiding_duplicates')) + { + include($phpbb_root_path . 'includes/functions_tricky_update.' . $phpEx); + } phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); // Link to the new topic diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index f40a4bc044..1fb3cb9d73 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -620,6 +620,10 @@ function merge_posts($topic_id, $to_topic_id) else { // If the topic no longer exist, we will update the topic watch table. + if (!function_exists('phpbb_update_rows_avoiding_duplicates')) + { + include($phpbb_root_path . 'includes/functions_tricky_update.' . $phpEx); + } phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); } From 58951ef1057bd5f0d1098f9536eb8a84c532833c Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 23:37:57 -0500 Subject: [PATCH 135/443] [ticket/11162] The test is not at all trivial. PHPBB3-11162 --- .../update_rows_avoiding_duplicates_test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php b/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php index 6940122393..4849605e9c 100644 --- a/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php +++ b/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php @@ -53,7 +53,7 @@ class phpbb_update_rows_avoiding_duplicates_test extends phpbb_database_test_cas /** * @dataProvider fixture_data */ - public function test_trivial_update($description, $from, $to, $expected_result_count) + public function test_update($description, $from, $to, $expected_result_count) { $db = $this->new_dbal(); From efe122b03200155479920890defc2a3dc689bdd7 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 4 Dec 2012 23:40:30 -0500 Subject: [PATCH 136/443] [ticket/11162] This test really only works for bookmarks. PHPBB3-11162 --- .../fixtures/bookmarks_duplicates.xml | 47 +++++++++++++++++++ ...icates.xml => topics_watch_duplicates.xml} | 0 .../update_rows_avoiding_duplicates_test.php | 6 +-- 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 tests/functions_tricky_update/fixtures/bookmarks_duplicates.xml rename tests/functions_tricky_update/fixtures/{duplicates.xml => topics_watch_duplicates.xml} (100%) diff --git a/tests/functions_tricky_update/fixtures/bookmarks_duplicates.xml b/tests/functions_tricky_update/fixtures/bookmarks_duplicates.xml new file mode 100644 index 0000000000..d49f76b073 --- /dev/null +++ b/tests/functions_tricky_update/fixtures/bookmarks_duplicates.xml @@ -0,0 +1,47 @@ + + + + user_id + topic_id + + + + 1 + 1 + + + + + 2 + 2 + + + 3 + 3 + + + + + 1 + 4 + + + 1 + 5 + + + + + 1 + 6 + + + 1 + 7 + + + 2 + 6 + +
      +
      diff --git a/tests/functions_tricky_update/fixtures/duplicates.xml b/tests/functions_tricky_update/fixtures/topics_watch_duplicates.xml similarity index 100% rename from tests/functions_tricky_update/fixtures/duplicates.xml rename to tests/functions_tricky_update/fixtures/topics_watch_duplicates.xml diff --git a/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php b/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php index 4849605e9c..6142997408 100644 --- a/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php +++ b/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php @@ -13,7 +13,7 @@ class phpbb_update_rows_avoiding_duplicates_test extends phpbb_database_test_cas { public function getDataSet() { - return $this->createXMLDataSet(dirname(__FILE__).'/fixtures/duplicates.xml'); + return $this->createXMLDataSet(dirname(__FILE__).'/fixtures/bookmarks_duplicates.xml'); } public static function fixture_data() @@ -57,10 +57,10 @@ class phpbb_update_rows_avoiding_duplicates_test extends phpbb_database_test_cas { $db = $this->new_dbal(); - phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $from, $to); + phpbb_update_rows_avoiding_duplicates($db, BOOKMARKS_TABLE, 'topic_id', $from, $to); $sql = 'SELECT COUNT(*) AS remaining_rows - FROM ' . TOPICS_WATCH_TABLE . ' + FROM ' . BOOKMARKS_TABLE . ' WHERE topic_id = ' . (int) $to; $result = $db->sql_query($sql); $result_count = $db->sql_fetchfield('remaining_rows'); From 6872104aa95a9f2aad565189e25bbf54abc3ca2c Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 5 Dec 2012 00:07:01 -0500 Subject: [PATCH 137/443] [ticket/11162] Account for notify_status. PHPBB3-11162 --- phpBB/includes/functions_tricky_update.php | 111 +++++++++++++++++- .../fixtures/topics_watch_duplicates.xml | 38 ++++-- ...avoiding_duplicates_notify_status_test.php | 100 ++++++++++++++++ 3 files changed, 239 insertions(+), 10 deletions(-) create mode 100644 tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php diff --git a/phpBB/includes/functions_tricky_update.php b/phpBB/includes/functions_tricky_update.php index a5b9fdacd0..cf922d7014 100644 --- a/phpBB/includes/functions_tricky_update.php +++ b/phpBB/includes/functions_tricky_update.php @@ -20,7 +20,7 @@ if (!defined('IN_PHPBB')) * If this results in rows violating uniqueness constraints, the duplicate * rows are eliminated. * -* The only supported tables are bookmarks and topics_watch. +* The only supported table is bookmarks. * * @param dbal $db Database object * @param string $table Table on which to perform the update @@ -67,7 +67,7 @@ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_value if (empty($new_user_ids)) { $sql = "UPDATE $table - SET $column = " . (int) $to_value. " + SET $column = " . (int) $to_value . " WHERE $column = '" . $db->sql_escape($from_value) . "'"; $queries[] = $sql; } @@ -77,7 +77,7 @@ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_value if (!empty($different_user_ids)) { $sql = "UPDATE $table - SET $column = " . (int) $to_value. " + SET $column = " . (int) $to_value . " WHERE $column = '" . $db->sql_escape($from_value) . "' AND " . $db->sql_in_set('user_id', $different_user_ids); $queries[] = $sql; @@ -101,3 +101,108 @@ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_value $db->sql_transaction('commit'); } } + +/** +* Updates rows in given table from a set of values to a new value. +* If this results in rows violating uniqueness constraints, the duplicate +* rows are merged respecting notify_status (0 takes precedence over 1). +* +* The only supported table is topics_watch. +* +* @param dbal $db Database object +* @param string $table Table on which to perform the update +* @param string $column Column whose values to change +* @param array $from_values An array of values that should be changed +* @param int $to_value The new value +* @return null +*/ +function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $column, $from_values, $to_value) +{ + $sql = "SELECT $column, user_id, notify_status + FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $result = $db->sql_query($sql); + + $old_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $old_user_ids[(int) $row['notify_status']][$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $sql = "SELECT $column, user_id + FROM $table + WHERE $column = '" . (int) $to_value . "'"; + $result = $db->sql_query($sql); + + $new_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $new_user_ids[$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $queries = array(); + $any_found = false; + $extra_updates = array( + 0 => 'notify_status = 0', + 1 => '', + ); + foreach ($from_values as $from_value) + { + foreach ($extra_updates as $notify_status => $extra_update) { + if (!isset($old_user_ids[$notify_status][$from_value])) + { + continue; + } + $any_found = true; + if (empty($new_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value . " + WHERE $column = '" . $db->sql_escape($from_value) . "'"; + $queries[] = $sql; + } + else + { + $different_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $new_user_ids[$to_value]); + if (!empty($different_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value . " + WHERE $column = '" . $db->sql_escape($from_value) . "' + AND " . $db->sql_in_set('user_id', $different_user_ids); + $queries[] = $sql; + } + + if ($extra_update) { + $same_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $different_user_ids); + if (!empty($same_user_ids)) + { + $sql = "UPDATE $table + SET $extra_update + WHERE $column = '" . (int) $to_value . "' + AND " . $db->sql_in_set('user_id', $same_user_ids); + $queries[] = $sql; + } + } + } + } + } + + if ($any_found) + { + $db->sql_transaction('begin'); + + foreach ($queries as $sql) + { + $db->sql_query($sql); + } + + $sql = "DELETE FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $db->sql_query($sql); + + $db->sql_transaction('commit'); + } +} diff --git a/tests/functions_tricky_update/fixtures/topics_watch_duplicates.xml b/tests/functions_tricky_update/fixtures/topics_watch_duplicates.xml index bc08016a8f..c387bb737a 100644 --- a/tests/functions_tricky_update/fixtures/topics_watch_duplicates.xml +++ b/tests/functions_tricky_update/fixtures/topics_watch_duplicates.xml @@ -14,17 +14,17 @@ - 2 + 1 2 1 + 2 3 - 3 - 1 + 0 - + 1 4 @@ -36,20 +36,44 @@ 1 - + 1 6 - 1 + 0 1 7 1 + + + + 1 + 8 + 1 + + + 1 + 9 + 0 + + + + + 1 + 10 + 0 + + + 1 + 11 + 1 + 2 - 6 + 10 1 diff --git a/tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php b/tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php new file mode 100644 index 0000000000..aa739c5f04 --- /dev/null +++ b/tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php @@ -0,0 +1,100 @@ +createXMLDataSet(dirname(__FILE__).'/fixtures/topics_watch_duplicates.xml'); + } + + public static function fixture_data() + { + return array( + // description + // from array + // to value + // expected count with to value post update + // expected notify_status values + array( + 'trivial', + array(1), + 1000, + 1, + 1, + ), + array( + 'no conflict', + array(2), + 3, + 2, + 1, + ), + array( + 'conflict, same notify status', + array(4), + 5, + 1, + 1, + ), + array( + 'conflict, notify status 0 into 1', + array(6), + 7, + 1, + 0, + ), + array( + 'conflict, notify status 1 into 0', + array(8), + 9, + 1, + 0, + ), + array( + 'conflict and no conflict', + array(10), + 11, + 2, + 0, + ), + ); + } + + /** + * @dataProvider fixture_data + */ + public function test_update($description, $from, $to, $expected_result_count, $expected_notify_status) + { + $db = $this->new_dbal(); + + phpbb_update_rows_avoiding_duplicates_notify_status($db, TOPICS_WATCH_TABLE, 'topic_id', $from, $to); + + $sql = 'SELECT COUNT(*) AS remaining_rows + FROM ' . TOPICS_WATCH_TABLE . ' + WHERE topic_id = ' . (int) $to; + $result = $db->sql_query($sql); + $result_count = $db->sql_fetchfield('remaining_rows'); + $db->sql_freeresult($result); + + $this->assertEquals($expected_result_count, $result_count); + + // user id of 1 is the user being updated + $sql = 'SELECT notify_status + FROM ' . TOPICS_WATCH_TABLE . ' + WHERE topic_id = ' . (int) $to . ' AND user_id = 1'; + $result = $db->sql_query($sql); + $notify_status = $db->sql_fetchfield('notify_status'); + $db->sql_freeresult($result); + + $this->assertEquals($expected_notify_status, $notify_status); + } +} From 1a411c5658da769e28b03332ed618d5e701dab79 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 5 Dec 2012 00:10:02 -0500 Subject: [PATCH 138/443] [ticket/11162] Use correct functions. PHPBB3-11162 --- phpBB/includes/mcp/mcp_forum.php | 4 ++-- phpBB/includes/mcp/mcp_topic.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index 3603224735..cd938e83a0 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -415,11 +415,11 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) $success_msg = 'POSTS_MERGED_SUCCESS'; // Update the topic watch table. - if (!function_exists('phpbb_update_rows_avoiding_duplicates')) + if (!function_exists('phpbb_update_rows_avoiding_duplicates_notify_status')) { include($phpbb_root_path . 'includes/functions_tricky_update.' . $phpEx); } - phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); + phpbb_update_rows_avoiding_duplicates_notify_status($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); // Link to the new topic $return_link .= (($return_link) ? '

      ' : '') . sprintf($user->lang['RETURN_NEW_TOPIC'], '', ''); diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index 1fb3cb9d73..29dabdd2a2 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -620,11 +620,11 @@ function merge_posts($topic_id, $to_topic_id) else { // If the topic no longer exist, we will update the topic watch table. - if (!function_exists('phpbb_update_rows_avoiding_duplicates')) + if (!function_exists('phpbb_update_rows_avoiding_duplicates_notify_status')) { include($phpbb_root_path . 'includes/functions_tricky_update.' . $phpEx); } - phpbb_update_rows_avoiding_duplicates($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); + phpbb_update_rows_avoiding_duplicates_notify_status($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); } // Link to the new topic From 03f819862f15efa2ef64331b23394086746d09be Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 5 Dec 2012 00:41:47 -0500 Subject: [PATCH 139/443] [ticket/10602] Use last_queue_run for its intended purpose. We keep the last queue run time around, therefore for determining whether enough time has passed since the last run we can simply use this config variable. When there is no queue file we consider a queue run successful. Previously queue.php ("cache file") modification time would be used for determining whether enough time has passed since last queue run. The problem was that modification time would be updated whenever anything was added to the queue, creating a situation where if queue is processed less frequently than it is added to that email would not be sent. PHPBB3-10602 --- phpBB/includes/functions_messenger.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php index 6549693333..ae0f7823cc 100644 --- a/phpBB/includes/functions_messenger.php +++ b/phpBB/includes/functions_messenger.php @@ -715,14 +715,19 @@ class queue $lock_fp = $this->lock(); - set_config('last_queue_run', time(), true); - - if (!file_exists($this->cache_file) || filemtime($this->cache_file) > time() - $config['queue_interval']) + if (!file_exists($this->cache_file) || $config['last_queue_run'] > time() - $config['queue_interval']) { + if (!file_exists($this->cache_file)) + { + set_config('last_queue_run', time(), true); + } + $this->unlock($lock_fp); return; } + set_config('last_queue_run', time(), true); + include($this->cache_file); foreach ($this->queue_data as $object => $data_ary) From 1e50116c54ec7ffbaba4622d5481207423ef2bbe Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 5 Dec 2012 00:57:24 -0500 Subject: [PATCH 140/443] [ticket/10602] Avoid a race condition. PHPBB3-10602 --- phpBB/includes/functions_messenger.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php index ae0f7823cc..e837811c86 100644 --- a/phpBB/includes/functions_messenger.php +++ b/phpBB/includes/functions_messenger.php @@ -715,9 +715,11 @@ class queue $lock_fp = $this->lock(); - if (!file_exists($this->cache_file) || $config['last_queue_run'] > time() - $config['queue_interval']) + // avoid races, check file existence once + $have_cache_file = file_exists($this->cache_file); + if (!$have_cache_file || $config['last_queue_run'] > time() - $config['queue_interval']) { - if (!file_exists($this->cache_file)) + if (!$have_cache_file) { set_config('last_queue_run', time(), true); } From 94ebc5707836d931e24e77f5ce1b3a16d0410fb8 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 5 Dec 2012 10:40:42 -0500 Subject: [PATCH 141/443] [ticket/11162] Newlines to LF. PHPBB3-11162 --- phpBB/includes/functions_tricky_update.php | 416 ++++++++++----------- 1 file changed, 208 insertions(+), 208 deletions(-) diff --git a/phpBB/includes/functions_tricky_update.php b/phpBB/includes/functions_tricky_update.php index cf922d7014..c8fcb9b6f0 100644 --- a/phpBB/includes/functions_tricky_update.php +++ b/phpBB/includes/functions_tricky_update.php @@ -1,208 +1,208 @@ -sql_in_set($column, $from_values); - $result = $db->sql_query($sql); - - $old_user_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $old_user_ids[$row[$column]][] = $row['user_id']; - } - $db->sql_freeresult($result); - - $sql = "SELECT $column, user_id - FROM $table - WHERE $column = '" . (int) $to_value . "'"; - $result = $db->sql_query($sql); - - $new_user_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $new_user_ids[$row[$column]][] = $row['user_id']; - } - $db->sql_freeresult($result); - - $queries = array(); - $any_found = false; - foreach ($from_values as $from_value) - { - if (!isset($old_user_ids[$from_value])) - { - continue; - } - $any_found = true; - if (empty($new_user_ids)) - { - $sql = "UPDATE $table - SET $column = " . (int) $to_value . " - WHERE $column = '" . $db->sql_escape($from_value) . "'"; - $queries[] = $sql; - } - else - { - $different_user_ids = array_diff($old_user_ids[$from_value], $new_user_ids[$to_value]); - if (!empty($different_user_ids)) - { - $sql = "UPDATE $table - SET $column = " . (int) $to_value . " - WHERE $column = '" . $db->sql_escape($from_value) . "' - AND " . $db->sql_in_set('user_id', $different_user_ids); - $queries[] = $sql; - } - } - } - - if ($any_found) - { - $db->sql_transaction('begin'); - - foreach ($queries as $sql) - { - $db->sql_query($sql); - } - - $sql = "DELETE FROM $table - WHERE " . $db->sql_in_set($column, $from_values); - $db->sql_query($sql); - - $db->sql_transaction('commit'); - } -} - -/** -* Updates rows in given table from a set of values to a new value. -* If this results in rows violating uniqueness constraints, the duplicate -* rows are merged respecting notify_status (0 takes precedence over 1). -* -* The only supported table is topics_watch. -* -* @param dbal $db Database object -* @param string $table Table on which to perform the update -* @param string $column Column whose values to change -* @param array $from_values An array of values that should be changed -* @param int $to_value The new value -* @return null -*/ -function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $column, $from_values, $to_value) -{ - $sql = "SELECT $column, user_id, notify_status - FROM $table - WHERE " . $db->sql_in_set($column, $from_values); - $result = $db->sql_query($sql); - - $old_user_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $old_user_ids[(int) $row['notify_status']][$row[$column]][] = $row['user_id']; - } - $db->sql_freeresult($result); - - $sql = "SELECT $column, user_id - FROM $table - WHERE $column = '" . (int) $to_value . "'"; - $result = $db->sql_query($sql); - - $new_user_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $new_user_ids[$row[$column]][] = $row['user_id']; - } - $db->sql_freeresult($result); - - $queries = array(); - $any_found = false; - $extra_updates = array( - 0 => 'notify_status = 0', - 1 => '', - ); - foreach ($from_values as $from_value) - { - foreach ($extra_updates as $notify_status => $extra_update) { - if (!isset($old_user_ids[$notify_status][$from_value])) - { - continue; - } - $any_found = true; - if (empty($new_user_ids)) - { - $sql = "UPDATE $table - SET $column = " . (int) $to_value . " - WHERE $column = '" . $db->sql_escape($from_value) . "'"; - $queries[] = $sql; - } - else - { - $different_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $new_user_ids[$to_value]); - if (!empty($different_user_ids)) - { - $sql = "UPDATE $table - SET $column = " . (int) $to_value . " - WHERE $column = '" . $db->sql_escape($from_value) . "' - AND " . $db->sql_in_set('user_id', $different_user_ids); - $queries[] = $sql; - } - - if ($extra_update) { - $same_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $different_user_ids); - if (!empty($same_user_ids)) - { - $sql = "UPDATE $table - SET $extra_update - WHERE $column = '" . (int) $to_value . "' - AND " . $db->sql_in_set('user_id', $same_user_ids); - $queries[] = $sql; - } - } - } - } - } - - if ($any_found) - { - $db->sql_transaction('begin'); - - foreach ($queries as $sql) - { - $db->sql_query($sql); - } - - $sql = "DELETE FROM $table - WHERE " . $db->sql_in_set($column, $from_values); - $db->sql_query($sql); - - $db->sql_transaction('commit'); - } -} +sql_in_set($column, $from_values); + $result = $db->sql_query($sql); + + $old_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $old_user_ids[$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $sql = "SELECT $column, user_id + FROM $table + WHERE $column = '" . (int) $to_value . "'"; + $result = $db->sql_query($sql); + + $new_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $new_user_ids[$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $queries = array(); + $any_found = false; + foreach ($from_values as $from_value) + { + if (!isset($old_user_ids[$from_value])) + { + continue; + } + $any_found = true; + if (empty($new_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value . " + WHERE $column = '" . $db->sql_escape($from_value) . "'"; + $queries[] = $sql; + } + else + { + $different_user_ids = array_diff($old_user_ids[$from_value], $new_user_ids[$to_value]); + if (!empty($different_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value . " + WHERE $column = '" . $db->sql_escape($from_value) . "' + AND " . $db->sql_in_set('user_id', $different_user_ids); + $queries[] = $sql; + } + } + } + + if ($any_found) + { + $db->sql_transaction('begin'); + + foreach ($queries as $sql) + { + $db->sql_query($sql); + } + + $sql = "DELETE FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $db->sql_query($sql); + + $db->sql_transaction('commit'); + } +} + +/** +* Updates rows in given table from a set of values to a new value. +* If this results in rows violating uniqueness constraints, the duplicate +* rows are merged respecting notify_status (0 takes precedence over 1). +* +* The only supported table is topics_watch. +* +* @param dbal $db Database object +* @param string $table Table on which to perform the update +* @param string $column Column whose values to change +* @param array $from_values An array of values that should be changed +* @param int $to_value The new value +* @return null +*/ +function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $column, $from_values, $to_value) +{ + $sql = "SELECT $column, user_id, notify_status + FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $result = $db->sql_query($sql); + + $old_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $old_user_ids[(int) $row['notify_status']][$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $sql = "SELECT $column, user_id + FROM $table + WHERE $column = '" . (int) $to_value . "'"; + $result = $db->sql_query($sql); + + $new_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $new_user_ids[$row[$column]][] = $row['user_id']; + } + $db->sql_freeresult($result); + + $queries = array(); + $any_found = false; + $extra_updates = array( + 0 => 'notify_status = 0', + 1 => '', + ); + foreach ($from_values as $from_value) + { + foreach ($extra_updates as $notify_status => $extra_update) { + if (!isset($old_user_ids[$notify_status][$from_value])) + { + continue; + } + $any_found = true; + if (empty($new_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value . " + WHERE $column = '" . $db->sql_escape($from_value) . "'"; + $queries[] = $sql; + } + else + { + $different_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $new_user_ids[$to_value]); + if (!empty($different_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value . " + WHERE $column = '" . $db->sql_escape($from_value) . "' + AND " . $db->sql_in_set('user_id', $different_user_ids); + $queries[] = $sql; + } + + if ($extra_update) { + $same_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $different_user_ids); + if (!empty($same_user_ids)) + { + $sql = "UPDATE $table + SET $extra_update + WHERE $column = '" . (int) $to_value . "' + AND " . $db->sql_in_set('user_id', $same_user_ids); + $queries[] = $sql; + } + } + } + } + } + + if ($any_found) + { + $db->sql_transaction('begin'); + + foreach ($queries as $sql) + { + $db->sql_query($sql); + } + + $sql = "DELETE FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $db->sql_query($sql); + + $db->sql_transaction('commit'); + } +} From 16966f52d37e4ebdca4f3846c81dfa85b193501e Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 5 Dec 2012 10:41:08 -0500 Subject: [PATCH 142/443] [ticket/11162] Reformat. PHPBB3-11162 --- phpBB/includes/functions_tricky_update.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/phpBB/includes/functions_tricky_update.php b/phpBB/includes/functions_tricky_update.php index c8fcb9b6f0..10321618b2 100644 --- a/phpBB/includes/functions_tricky_update.php +++ b/phpBB/includes/functions_tricky_update.php @@ -150,7 +150,8 @@ function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $colum ); foreach ($from_values as $from_value) { - foreach ($extra_updates as $notify_status => $extra_update) { + foreach ($extra_updates as $notify_status => $extra_update) + { if (!isset($old_user_ids[$notify_status][$from_value])) { continue; @@ -174,8 +175,9 @@ function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $colum AND " . $db->sql_in_set('user_id', $different_user_ids); $queries[] = $sql; } - - if ($extra_update) { + + if ($extra_update) + { $same_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $different_user_ids); if (!empty($same_user_ids)) { From fe87d441eeb54bf5efb56a0f69f42848d9ef53d5 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 5 Dec 2012 10:44:36 -0500 Subject: [PATCH 143/443] [ticket/11162] Review comments fixed. PHPBB3-11162 --- phpBB/includes/functions_tricky_update.php | 12 ++++++------ ...e_rows_avoiding_duplicates_notify_status_test.php | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/phpBB/includes/functions_tricky_update.php b/phpBB/includes/functions_tricky_update.php index 10321618b2..05cb65e68d 100644 --- a/phpBB/includes/functions_tricky_update.php +++ b/phpBB/includes/functions_tricky_update.php @@ -39,19 +39,19 @@ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_value $old_user_ids = array(); while ($row = $db->sql_fetchrow($result)) { - $old_user_ids[$row[$column]][] = $row['user_id']; + $old_user_ids[$row[$column]][] = (int) $row['user_id']; } $db->sql_freeresult($result); $sql = "SELECT $column, user_id FROM $table - WHERE $column = '" . (int) $to_value . "'"; + WHERE $column = " . (int) $to_value; $result = $db->sql_query($sql); $new_user_ids = array(); while ($row = $db->sql_fetchrow($result)) { - $new_user_ids[$row[$column]][] = $row['user_id']; + $new_user_ids[$row[$column]][] = (int) $row['user_id']; } $db->sql_freeresult($result); @@ -126,19 +126,19 @@ function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $colum $old_user_ids = array(); while ($row = $db->sql_fetchrow($result)) { - $old_user_ids[(int) $row['notify_status']][$row[$column]][] = $row['user_id']; + $old_user_ids[(int) $row['notify_status']][$row[$column]][] = (int) $row['user_id']; } $db->sql_freeresult($result); $sql = "SELECT $column, user_id FROM $table - WHERE $column = '" . (int) $to_value . "'"; + WHERE $column = " . (int) $to_value; $result = $db->sql_query($sql); $new_user_ids = array(); while ($row = $db->sql_fetchrow($result)) { - $new_user_ids[$row[$column]][] = $row['user_id']; + $new_user_ids[$row[$column]][] = (int) $row['user_id']; } $db->sql_freeresult($result); diff --git a/tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php b/tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php index aa739c5f04..9052585552 100644 --- a/tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php +++ b/tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php @@ -90,7 +90,8 @@ class phpbb_update_rows_avoiding_duplicates_notify_status_test extends phpbb_dat // user id of 1 is the user being updated $sql = 'SELECT notify_status FROM ' . TOPICS_WATCH_TABLE . ' - WHERE topic_id = ' . (int) $to . ' AND user_id = 1'; + WHERE topic_id = ' . (int) $to . ' + AND user_id = 1'; $result = $db->sql_query($sql); $notify_status = $db->sql_fetchfield('notify_status'); $db->sql_freeresult($result); From f5de11438c471a76fc5c5f3a4b8c4c29d07ed734 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 5 Dec 2012 10:47:26 -0500 Subject: [PATCH 144/443] [ticket/11162] Use empty($queries). PHPBB3-11162 --- phpBB/includes/functions_tricky_update.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/phpBB/includes/functions_tricky_update.php b/phpBB/includes/functions_tricky_update.php index 05cb65e68d..664c246888 100644 --- a/phpBB/includes/functions_tricky_update.php +++ b/phpBB/includes/functions_tricky_update.php @@ -56,14 +56,12 @@ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_value $db->sql_freeresult($result); $queries = array(); - $any_found = false; foreach ($from_values as $from_value) { if (!isset($old_user_ids[$from_value])) { continue; } - $any_found = true; if (empty($new_user_ids)) { $sql = "UPDATE $table @@ -85,7 +83,7 @@ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_value } } - if ($any_found) + if (!empty($queries)) { $db->sql_transaction('begin'); @@ -143,7 +141,6 @@ function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $colum $db->sql_freeresult($result); $queries = array(); - $any_found = false; $extra_updates = array( 0 => 'notify_status = 0', 1 => '', @@ -156,7 +153,6 @@ function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $colum { continue; } - $any_found = true; if (empty($new_user_ids)) { $sql = "UPDATE $table @@ -192,7 +188,7 @@ function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $colum } } - if ($any_found) + if (!empty($queries)) { $db->sql_transaction('begin'); From af064cdaad357f705fc7c80f4d018d57cffa8d33 Mon Sep 17 00:00:00 2001 From: Senky Date: Wed, 16 May 2012 23:02:20 +0200 Subject: [PATCH 145/443] [ticket/10841] Modifying style and language selectors in UCP Commit also deletes all unnecessary blank spaces at the end of the lines in both ucp_prefs_personal.html PHPBB3-10841 --- phpBB/includes/ucp/ucp_prefs.php | 30 +++++++++++++ .../template/ucp_prefs_personal.html | 42 ++++++++++--------- .../template/ucp_prefs_personal.html | 18 ++++---- 3 files changed, 62 insertions(+), 28 deletions(-) diff --git a/phpBB/includes/ucp/ucp_prefs.php b/phpBB/includes/ucp/ucp_prefs.php index 17d7d23f02..19e1b45787 100644 --- a/phpBB/includes/ucp/ucp_prefs.php +++ b/phpBB/includes/ucp/ucp_prefs.php @@ -134,6 +134,33 @@ class ucp_prefs } $dateformat_options .= '>' . $user->lang['CUSTOM_DATEFORMAT'] . ''; + // check for count of installed languages + $sql = 'SELECT lang_id + FROM ' . LANG_TABLE; + $result = $db->sql_query($sql); + if( $db->sql_affectedrows() > 1 ) + { + $s_more_languages = true; + } + else + { + $s_more_languages = false; + } + + // check for count of installed and active styles + $sql = 'SELECT style_id + FROM ' . STYLES_TABLE . ' + WHERE style_active = 1'; + $result = $db->sql_query($sql); + if( $db->sql_affectedrows() > 1 ) + { + $s_more_styles = true; + } + else + { + $s_more_styles = false; + } + $template->assign_vars(array( 'ERROR' => (sizeof($error)) ? implode('
      ', $error) : '', @@ -155,6 +182,9 @@ class ucp_prefs 'DEFAULT_DATEFORMAT' => $config['default_dateformat'], 'A_DEFAULT_DATEFORMAT' => addslashes($config['default_dateformat']), + 'S_MORE_LANGUAGES' => $s_more_languages, + 'S_MORE_STYLES' => $s_more_styles, + 'S_LANG_OPTIONS' => language_select($data['lang']), 'S_STYLE_OPTIONS' => ($config['override_user_style']) ? '' : style_select($data['style']), 'S_TZ_OPTIONS' => tz_select($data['tz'], true), diff --git a/phpBB/styles/prosilver/template/ucp_prefs_personal.html b/phpBB/styles/prosilver/template/ucp_prefs_personal.html index 9022346627..416343e57d 100644 --- a/phpBB/styles/prosilver/template/ucp_prefs_personal.html +++ b/phpBB/styles/prosilver/template/ucp_prefs_personal.html @@ -12,21 +12,21 @@
      - +
      - +

      {L_ALLOW_PM_EXPLAIN}
      - +
      @@ -34,17 +34,17 @@

      {L_HIDE_ONLINE_EXPLAIN}
      - +
      - +
      - - + +
      @@ -52,22 +52,24 @@
      - +
      - +
      -
      -
      -
      -
      - + +
      +
      +
      +
      + +
      @@ -80,7 +82,7 @@
      - +
      @@ -97,9 +99,9 @@
    - +
    - {S_HIDDEN_FIELDS}  + {S_HIDDEN_FIELDS}  {S_FORM_TOKEN}
    @@ -113,9 +115,9 @@ function customDates() { var e = document.getElementById('dateoptions'); - + e.selectedIndex = e.length - 1; - + // Loop and match date_format in menu for (var i = 0; i < e.length; i++) { @@ -125,7 +127,7 @@ break; } } - + // Show/hide custom field if (e.selectedIndex == e.length - 1) { diff --git a/phpBB/styles/subsilver2/template/ucp_prefs_personal.html b/phpBB/styles/subsilver2/template/ucp_prefs_personal.html index e2266b7d38..c604671c5c 100644 --- a/phpBB/styles/subsilver2/template/ucp_prefs_personal.html +++ b/phpBB/styles/subsilver2/template/ucp_prefs_personal.html @@ -29,43 +29,45 @@ {ERROR} - + {L_SHOW_EMAIL}: checked="checked" />{L_YES}   checked="checked" />{L_NO} - + {L_ADMIN_EMAIL}: checked="checked" />{L_YES}   checked="checked" />{L_NO} - + {L_ALLOW_PM}:
    {L_ALLOW_PM_EXPLAIN} checked="checked" />{L_YES}   checked="checked" />{L_NO} - + {L_HIDE_ONLINE}:
    {L_HIDE_ONLINE_EXPLAIN} checked="checked" />{L_YES}   checked="checked" />{L_NO} - + {L_NOTIFY_METHOD}:
    {L_NOTIFY_METHOD_EXPLAIN} checked="checked" />{L_NOTIFY_METHOD_EMAIL}   checked="checked" />{L_NOTIFY_METHOD_IM}   checked="checked" />{L_NOTIFY_METHOD_BOTH} - + {L_NOTIFY_ON_PM}: checked="checked" />{L_YES}   checked="checked" />{L_NO} - + {L_POPUP_ON_PM}: checked="checked" />{L_YES}   checked="checked" />{L_NO} + {L_BOARD_LANGUAGE}: - + + {L_BOARD_STYLE}: From dd6983b14bba4326d824b3abb130eafc5e8f666c Mon Sep 17 00:00:00 2001 From: Senky Date: Thu, 17 May 2012 20:01:44 +0200 Subject: [PATCH 146/443] [ticket/10841] changing affectedrows check to COUNT in sql this sould reduce load and be faster. Also freeresult functions added PHPBB3-10841 --- phpBB/includes/ucp/ucp_prefs.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/phpBB/includes/ucp/ucp_prefs.php b/phpBB/includes/ucp/ucp_prefs.php index 19e1b45787..b95d2d4ee8 100644 --- a/phpBB/includes/ucp/ucp_prefs.php +++ b/phpBB/includes/ucp/ucp_prefs.php @@ -134,11 +134,11 @@ class ucp_prefs } $dateformat_options .= '>' . $user->lang['CUSTOM_DATEFORMAT'] . ''; - // check for count of installed languages - $sql = 'SELECT lang_id + // check if there are any user-selectable languages + $sql = 'SELECT COUNT(lang_id) as languages_count FROM ' . LANG_TABLE; $result = $db->sql_query($sql); - if( $db->sql_affectedrows() > 1 ) + if( $db->sql_fetchfield('languages_count') > 1 ) { $s_more_languages = true; } @@ -146,13 +146,14 @@ class ucp_prefs { $s_more_languages = false; } + $db->sql_freeresult($result); - // check for count of installed and active styles - $sql = 'SELECT style_id + // check if there are any user-selectable styles + $sql = 'SELECT COUNT(style_id) as styles_count FROM ' . STYLES_TABLE . ' WHERE style_active = 1'; $result = $db->sql_query($sql); - if( $db->sql_affectedrows() > 1 ) + if( $db->sql_fetchfield('styles_count') > 1 ) { $s_more_styles = true; } @@ -160,6 +161,7 @@ class ucp_prefs { $s_more_styles = false; } + $db->sql_freeresult($result); $template->assign_vars(array( 'ERROR' => (sizeof($error)) ? implode('
    ', $error) : '', From f7508c3f042091f163a87829a051312fa58630f1 Mon Sep 17 00:00:00 2001 From: Senky Date: Wed, 7 Nov 2012 10:28:25 +0100 Subject: [PATCH 147/443] [ticket/10841] removing unnecessary spacing PHPBB3-10841 --- phpBB/includes/ucp/ucp_prefs.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpBB/includes/ucp/ucp_prefs.php b/phpBB/includes/ucp/ucp_prefs.php index b95d2d4ee8..e84c7e662a 100644 --- a/phpBB/includes/ucp/ucp_prefs.php +++ b/phpBB/includes/ucp/ucp_prefs.php @@ -138,7 +138,7 @@ class ucp_prefs $sql = 'SELECT COUNT(lang_id) as languages_count FROM ' . LANG_TABLE; $result = $db->sql_query($sql); - if( $db->sql_fetchfield('languages_count') > 1 ) + if($db->sql_fetchfield('languages_count') > 1) { $s_more_languages = true; } @@ -153,7 +153,7 @@ class ucp_prefs FROM ' . STYLES_TABLE . ' WHERE style_active = 1'; $result = $db->sql_query($sql); - if( $db->sql_fetchfield('styles_count') > 1 ) + if($db->sql_fetchfield('styles_count') > 1) { $s_more_styles = true; } From 120accb9d4b2a89ca05f712a54427e072584c2f9 Mon Sep 17 00:00:00 2001 From: Senky Date: Thu, 8 Nov 2012 17:30:58 +0100 Subject: [PATCH 148/443] [ticket/10841] adding space after if PHPBB3-10841 --- phpBB/includes/ucp/ucp_prefs.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpBB/includes/ucp/ucp_prefs.php b/phpBB/includes/ucp/ucp_prefs.php index e84c7e662a..c6e43b831c 100644 --- a/phpBB/includes/ucp/ucp_prefs.php +++ b/phpBB/includes/ucp/ucp_prefs.php @@ -138,7 +138,7 @@ class ucp_prefs $sql = 'SELECT COUNT(lang_id) as languages_count FROM ' . LANG_TABLE; $result = $db->sql_query($sql); - if($db->sql_fetchfield('languages_count') > 1) + if ($db->sql_fetchfield('languages_count') > 1) { $s_more_languages = true; } @@ -153,7 +153,7 @@ class ucp_prefs FROM ' . STYLES_TABLE . ' WHERE style_active = 1'; $result = $db->sql_query($sql); - if($db->sql_fetchfield('styles_count') > 1) + if ($db->sql_fetchfield('styles_count') > 1) { $s_more_styles = true; } From 0793f8e2e60453db8de1ff8e231a36b2c9024f3d Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 5 Dec 2012 11:54:49 -0500 Subject: [PATCH 149/443] [ticket/10841] Revert whitespace changes. PHPBB3-10841 --- .../template/ucp_prefs_personal.html | 26 +++++++++---------- .../template/ucp_prefs_personal.html | 14 +++++----- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/phpBB/styles/prosilver/template/ucp_prefs_personal.html b/phpBB/styles/prosilver/template/ucp_prefs_personal.html index 416343e57d..01e0c9ba28 100644 --- a/phpBB/styles/prosilver/template/ucp_prefs_personal.html +++ b/phpBB/styles/prosilver/template/ucp_prefs_personal.html @@ -12,21 +12,21 @@
    - +
    - +

    {L_ALLOW_PM_EXPLAIN}
    - +
    @@ -34,17 +34,17 @@

    {L_HIDE_ONLINE_EXPLAIN}
    - +
    - +
    - - + +
    @@ -82,7 +82,7 @@
    - +
    @@ -99,9 +99,9 @@ - +
    - {S_HIDDEN_FIELDS}  + {S_HIDDEN_FIELDS}  {S_FORM_TOKEN}
    @@ -115,9 +115,9 @@ function customDates() { var e = document.getElementById('dateoptions'); - + e.selectedIndex = e.length - 1; - + // Loop and match date_format in menu for (var i = 0; i < e.length; i++) { @@ -127,7 +127,7 @@ break; } } - + // Show/hide custom field if (e.selectedIndex == e.length - 1) { diff --git a/phpBB/styles/subsilver2/template/ucp_prefs_personal.html b/phpBB/styles/subsilver2/template/ucp_prefs_personal.html index c604671c5c..4cd0f37a80 100644 --- a/phpBB/styles/subsilver2/template/ucp_prefs_personal.html +++ b/phpBB/styles/subsilver2/template/ucp_prefs_personal.html @@ -29,35 +29,35 @@ {ERROR} - + {L_SHOW_EMAIL}: checked="checked" />{L_YES}   checked="checked" />{L_NO} - + {L_ADMIN_EMAIL}: checked="checked" />{L_YES}   checked="checked" />{L_NO} - + {L_ALLOW_PM}:
    {L_ALLOW_PM_EXPLAIN} checked="checked" />{L_YES}   checked="checked" />{L_NO} - + {L_HIDE_ONLINE}:
    {L_HIDE_ONLINE_EXPLAIN} checked="checked" />{L_YES}   checked="checked" />{L_NO} - + {L_NOTIFY_METHOD}:
    {L_NOTIFY_METHOD_EXPLAIN} checked="checked" />{L_NOTIFY_METHOD_EMAIL}   checked="checked" />{L_NOTIFY_METHOD_IM}   checked="checked" />{L_NOTIFY_METHOD_BOTH} - + {L_NOTIFY_ON_PM}: checked="checked" />{L_YES}   checked="checked" />{L_NO} - + {L_POPUP_ON_PM}: checked="checked" />{L_YES}   checked="checked" />{L_NO} From a8e74f5292aaa74e2035dd5f3ab972f0201a1fe7 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 5 Dec 2012 12:02:30 -0500 Subject: [PATCH 150/443] [ticket/10841] Revert more whitespace changes. PHPBB3-10841 --- phpBB/styles/prosilver/template/ucp_prefs_personal.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpBB/styles/prosilver/template/ucp_prefs_personal.html b/phpBB/styles/prosilver/template/ucp_prefs_personal.html index 01e0c9ba28..600319fc72 100644 --- a/phpBB/styles/prosilver/template/ucp_prefs_personal.html +++ b/phpBB/styles/prosilver/template/ucp_prefs_personal.html @@ -52,14 +52,14 @@
    - +
    - +
    From dc649ad3cd8ea4520ad3694027679d6312c9495f Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 5 Dec 2012 11:34:16 -0500 Subject: [PATCH 151/443] [ticket/11248] Line endings to LF. PHPBB3-11248 --- tests/session/append_sid_test.php | 101 +++++++++++++++--------------- 1 file changed, 50 insertions(+), 51 deletions(-) diff --git a/tests/session/append_sid_test.php b/tests/session/append_sid_test.php index 88f6f0718e..ce7bf71215 100644 --- a/tests/session/append_sid_test.php +++ b/tests/session/append_sid_test.php @@ -1,51 +1,50 @@ - 1, 'f' => 2), true, false, 'viewtopic.php?t=1&f=2', 'parameters in params-argument as array'), - - // Custom sid parameter - array('viewtopic.php', 't=1&f=2', true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid', 'using session_id'), - - // Testing anchors - array('viewtopic.php?t=1&f=2#anchor', false, true, false, 'viewtopic.php?t=1&f=2#anchor', 'anchor in url-argument'), - array('viewtopic.php', 't=1&f=2#anchor', true, false, 'viewtopic.php?t=1&f=2#anchor', 'anchor in params-argument'), - array('viewtopic.php', array('t' => 1, 'f' => 2, '#' => 'anchor'), true, false, 'viewtopic.php?t=1&f=2#anchor', 'anchor in params-argument (array)'), - - // Anchors and custom sid - array('viewtopic.php?t=1&f=2#anchor', false, true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid#anchor', 'anchor in url-argument using session_id'), - array('viewtopic.php', 't=1&f=2#anchor', true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid#anchor', 'anchor in params-argument using session_id'), - array('viewtopic.php', array('t' => 1, 'f' => 2, '#' => 'anchor'), true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid#anchor', 'anchor in params-argument (array) using session_id'), - - // Empty parameters should not append the ? - array('viewtopic.php', false, true, false, 'viewtopic.php', 'no params using bool false'), - array('viewtopic.php', '', true, false, 'viewtopic.php', 'no params using empty string'), - array('viewtopic.php', array(), true, false, 'viewtopic.php', 'no params using empty array'), - ); - } - - /** - * @dataProvider append_sid_data - */ - public function test_append_sid($url, $params, $is_amp, $session_id, $expected, $description) - { - $this->assertEquals($expected, append_sid($url, $params, $is_amp, $session_id)); - } -} - + 1, 'f' => 2), true, false, 'viewtopic.php?t=1&f=2', 'parameters in params-argument as array'), + + // Custom sid parameter + array('viewtopic.php', 't=1&f=2', true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid', 'using session_id'), + + // Testing anchors + array('viewtopic.php?t=1&f=2#anchor', false, true, false, 'viewtopic.php?t=1&f=2#anchor', 'anchor in url-argument'), + array('viewtopic.php', 't=1&f=2#anchor', true, false, 'viewtopic.php?t=1&f=2#anchor', 'anchor in params-argument'), + array('viewtopic.php', array('t' => 1, 'f' => 2, '#' => 'anchor'), true, false, 'viewtopic.php?t=1&f=2#anchor', 'anchor in params-argument (array)'), + + // Anchors and custom sid + array('viewtopic.php?t=1&f=2#anchor', false, true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid#anchor', 'anchor in url-argument using session_id'), + array('viewtopic.php', 't=1&f=2#anchor', true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid#anchor', 'anchor in params-argument using session_id'), + array('viewtopic.php', array('t' => 1, 'f' => 2, '#' => 'anchor'), true, 'custom-sid', 'viewtopic.php?t=1&f=2&sid=custom-sid#anchor', 'anchor in params-argument (array) using session_id'), + + // Empty parameters should not append the ? + array('viewtopic.php', false, true, false, 'viewtopic.php', 'no params using bool false'), + array('viewtopic.php', '', true, false, 'viewtopic.php', 'no params using empty string'), + array('viewtopic.php', array(), true, false, 'viewtopic.php', 'no params using empty array'), + ); + } + + /** + * @dataProvider append_sid_data + */ + public function test_append_sid($url, $params, $is_amp, $session_id, $expected, $description) + { + $this->assertEquals($expected, append_sid($url, $params, $is_amp, $session_id)); + } +} From dbb54b217b4d0c0669a566f9c950e8331887d276 Mon Sep 17 00:00:00 2001 From: Patrick Webster Date: Wed, 5 Dec 2012 22:57:06 -0600 Subject: [PATCH 152/443] [ticket/11219] Coding guidelines and naming consistency changes PHPBB3-11219 --- tests/dbal/write_sequence_test.php | 2 +- ...phpbb_database_test_connection_manager.php | 24 ++++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/tests/dbal/write_sequence_test.php b/tests/dbal/write_sequence_test.php index d2c30b4e89..8975cfbfb1 100644 --- a/tests/dbal/write_sequence_test.php +++ b/tests/dbal/write_sequence_test.php @@ -13,7 +13,7 @@ class phpbb_dbal_write_sequence_test extends phpbb_database_test_case { public function getDataSet() { - return $this->createXMLDataSet(dirname(__FILE__).'/fixtures/three_users.xml'); + return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/three_users.xml'); } static public function write_sequence_data() diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index 97281a0812..d7c2804aa7 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -430,17 +430,17 @@ class phpbb_database_test_connection_manager /** * Performs synchronisations on the database after a fixture has been loaded * - * @param PHPUnit_Extensions_Database_DataSet_XmlDataSet $tables Tables contained within the loaded fixture + * @param PHPUnit_Extensions_Database_DataSet_XmlDataSet $xml_data_set Information about the tables contained within the loaded fixture * * @return null */ - public function post_setup_synchronisation($xmlDataSet) + public function post_setup_synchronisation($xml_data_set) { $this->ensure_connected(__METHOD__); $queries = array(); // Get escaped versions of the table names used in the fixture - $table_names = array_map(array($this->pdo, 'PDO::quote'), $xmlDataSet->getTableNames()); + $table_names = array_map(array($this->pdo, 'PDO::quote'), $xml_data_set->getTableNames()); switch ($this->config['dbms']) { @@ -469,18 +469,20 @@ class phpbb_database_test_connection_manager continue; } - $maxval = (int)$max_row['MAX']; - $maxval++; + $max_val = (int) $max_row['MAX']; + $max_val++; - // This is not the "proper" way, but the proper way does not allow you to completely reset - // tables with no rows since you have to select the next value to make the change go into effct. - // You would have to go past the minimum value to set it correctly, but that's illegal. - // Since we have no objects attached to our sequencers (triggers aren't attached), this works fine. + /** + * This is not the "proper" way, but the proper way does not allow you to completely reset + * tables with no rows since you have to select the next value to make the change go into effect. + * You would have to go past the minimum value to set it correctly, but that's illegal. + * Since we have no objects attached to our sequencers (triggers aren't attached), this works fine. + */ $queries[] = 'DROP SEQUENCE ' . $row['SEQUENCE_NAME']; $queries[] = "CREATE SEQUENCE {$row['SEQUENCE_NAME']} MINVALUE {$row['MIN_VALUE']} INCREMENT BY {$row['INCREMENT_BY']} - START WITH $maxval"; + START WITH $max_val"; } break; @@ -495,7 +497,7 @@ class phpbb_database_test_connection_manager while ($row = $result->fetch(PDO::FETCH_ASSOC)) { // Get the columns used in the fixture for this table - $column_names = $xmlDataSet->getTableMetaData($row['table_name'])->getColumns(); + $column_names = $xml_data_set->getTableMetaData($row['table_name'])->getColumns(); // Skip sequences that weren't specified in the fixture if (!in_array($row['column_name'], $column_names)) From 70050020699d9eab9b97bda342e0e928d1591de8 Mon Sep 17 00:00:00 2001 From: Fyorl Date: Sun, 8 Jul 2012 20:22:19 +0100 Subject: [PATCH 153/443] [ticket/10972] Added methods for creating and deleting basic users Modified the login method to allow logging in of an arbitrary user. Also added tests for the new functionality. PHPBB3-10972 --- tests/functional/new_user_test.php | 45 +++++++++++++++++++ .../phpbb_functional_test_case.php | 45 ++++++++++++++++++- 2 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 tests/functional/new_user_test.php diff --git a/tests/functional/new_user_test.php b/tests/functional/new_user_test.php new file mode 100644 index 0000000000..db2f31f450 --- /dev/null +++ b/tests/functional/new_user_test.php @@ -0,0 +1,45 @@ +create_user('user'); + $this->login(); + $crawler = $this->request('GET', 'memberlist.php?sid=' . $this->sid); + $this->assertContains('user', $crawler->filter('#memberlist tr')->eq(1)->text()); + } + + /** + * @depends test_create_user + */ + public function test_delete_user() + { + $this->delete_user('user'); + $this->login(); + $crawler = $this->request('GET', 'memberlist.php?sid=' . $this->sid); + $this->assertEquals(2, $crawler->filter('#memberlist tr')->count()); + } + + /** + * @depends test_delete_user + */ + public function test_login_other() + { + $this->create_user('user'); + $this->login('user'); + $crawler = $this->request('GET', 'index.php'); + $this->assertContains('user', $crawler->filter('.icon-logout')->text()); + $this->delete_user('user'); + } +} diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 7c03f874e9..dfbfe2565e 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -194,7 +194,48 @@ class phpbb_functional_test_case extends phpbb_test_case $db_conn_mgr->recreate_db(); } - protected function login() + /** + * Creates a new user with limited permissions + * + * @param string $username Also doubles up as the user's password + */ + protected function create_user($username) + { + // Required by unique_id + global $config; + + if (!is_array($config)) + { + $config = array(); + } + + $config['rand_seed'] = ''; + $config['rand_seed_last_update'] = time() + 600; + + $db = $this->get_db(); + $query = " + INSERT INTO " . self::$config['table_prefix'] . "users + (user_type, group_id, username, username_clean, user_regdate, user_password, user_email, user_lang, user_style, user_rank, user_colour, user_posts, user_permissions, user_ip, user_birthday, user_lastpage, user_last_confirm_key, user_post_sortby_type, user_post_sortby_dir, user_topic_sortby_type, user_topic_sortby_dir, user_avatar, user_sig, user_sig_bbcode_uid, user_from, user_icq, user_aim, user_yim, user_msnm, user_jabber, user_website, user_occ, user_interests, user_actkey, user_newpasswd) + VALUES + (0, 2, 'user', 'user', 0, '" . phpbb_hash($username) . "', 'nobody@example.com', 'en', 1, 0, '', 1, '', '', '', '', '', 't', 'a', 't', 'd', '', '', '', '', '', '', '', '', '', '', '', '', '', '') + "; + + $db->sql_query($query); + } + + /** + * Deletes a user + * + * @param string $username The username of the user to delete + */ + protected function delete_user($username) + { + $db = $this->get_db(); + $query = "DELETE FROM " . self::$config['table_prefix'] . "users WHERE username = '" . $db->sql_escape($username) . "'"; + $db->sql_query($query); + } + + protected function login($username = 'admin') { $this->add_lang('ucp'); @@ -202,7 +243,7 @@ class phpbb_functional_test_case extends phpbb_test_case $this->assertContains($this->lang('LOGIN_EXPLAIN_UCP'), $crawler->filter('html')->text()); $form = $crawler->selectButton($this->lang('LOGIN'))->form(); - $login = $this->client->submit($form, array('username' => 'admin', 'password' => 'admin')); + $login = $this->client->submit($form, array('username' => $username, 'password' => $username)); $cookies = $this->cookieJar->all(); From cafc7feca12730fce59091bd7a18fb5c3f7ecdc0 Mon Sep 17 00:00:00 2001 From: Fyorl Date: Mon, 9 Jul 2012 00:24:28 +0100 Subject: [PATCH 154/443] [ticket/10972] Moved tests into appropriate places and added comments PHPBB3-10972 --- tests/functional/auth_test.php | 9 ++++ tests/functional/new_user_test.php | 45 ------------------- .../phpbb_functional_test_case.php | 4 ++ 3 files changed, 13 insertions(+), 45 deletions(-) delete mode 100644 tests/functional/new_user_test.php diff --git a/tests/functional/auth_test.php b/tests/functional/auth_test.php index e955dcb4df..e67118d8f9 100644 --- a/tests/functional/auth_test.php +++ b/tests/functional/auth_test.php @@ -21,6 +21,15 @@ class phpbb_functional_auth_test extends phpbb_functional_test_case $this->assertContains($this->lang('LOGOUT_USER', 'admin'), $crawler->filter('.navbar')->text()); } + public function test_login_other() + { + $this->create_user('user'); + $this->login('user'); + $crawler = $this->request('GET', 'index.php'); + $this->assertContains('user', $crawler->filter('.icon-logout')->text()); + $this->delete_user('user'); + } + /** * @depends test_login */ diff --git a/tests/functional/new_user_test.php b/tests/functional/new_user_test.php deleted file mode 100644 index db2f31f450..0000000000 --- a/tests/functional/new_user_test.php +++ /dev/null @@ -1,45 +0,0 @@ -create_user('user'); - $this->login(); - $crawler = $this->request('GET', 'memberlist.php?sid=' . $this->sid); - $this->assertContains('user', $crawler->filter('#memberlist tr')->eq(1)->text()); - } - - /** - * @depends test_create_user - */ - public function test_delete_user() - { - $this->delete_user('user'); - $this->login(); - $crawler = $this->request('GET', 'memberlist.php?sid=' . $this->sid); - $this->assertEquals(2, $crawler->filter('#memberlist tr')->count()); - } - - /** - * @depends test_delete_user - */ - public function test_login_other() - { - $this->create_user('user'); - $this->login('user'); - $crawler = $this->request('GET', 'index.php'); - $this->assertContains('user', $crawler->filter('.icon-logout')->text()); - $this->delete_user('user'); - } -} diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index dfbfe2565e..a72c0940ab 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -197,6 +197,10 @@ class phpbb_functional_test_case extends phpbb_test_case /** * Creates a new user with limited permissions * + * Note that creating two users with the same name results in undefined + * login behaviour. Always call delete_user after running a test that + * requires create_user. + * * @param string $username Also doubles up as the user's password */ protected function create_user($username) From d33accb687ab4266559c12a356e121f3634d780b Mon Sep 17 00:00:00 2001 From: Fyorl Date: Fri, 10 Aug 2012 12:31:53 +0100 Subject: [PATCH 155/443] [ticket/10972] Added explicit checks for creating duplicate users. PHPBB3-10972 --- .../phpbb_functional_test_case.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index a72c0940ab..9bc2c96753 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -30,6 +30,11 @@ class phpbb_functional_test_case extends phpbb_test_case */ protected $lang = array(); + /** + * @var array + */ + protected $created_users = array(); + static protected $config = array(); static protected $already_installed = false; @@ -197,14 +202,18 @@ class phpbb_functional_test_case extends phpbb_test_case /** * Creates a new user with limited permissions * - * Note that creating two users with the same name results in undefined - * login behaviour. Always call delete_user after running a test that + * Always call delete_user after running a test that * requires create_user. * * @param string $username Also doubles up as the user's password */ protected function create_user($username) { + if (isset($this->created_users[$username])) + { + return; + } + // Required by unique_id global $config; @@ -225,6 +234,7 @@ class phpbb_functional_test_case extends phpbb_test_case "; $db->sql_query($query); + $this->created_users[$username] = 1; } /** @@ -234,6 +244,11 @@ class phpbb_functional_test_case extends phpbb_test_case */ protected function delete_user($username) { + if (isset($this->created_users[$username])) + { + unset($this->created_users[$username]); + } + $db = $this->get_db(); $query = "DELETE FROM " . self::$config['table_prefix'] . "users WHERE username = '" . $db->sql_escape($username) . "'"; $db->sql_query($query); From ebdd96592a100139c48204ef133e706c0ac465d1 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 6 Dec 2012 22:45:12 -0500 Subject: [PATCH 156/443] [ticket/10972] Backport get_db from develop. PHPBB3-10972 --- .../phpbb_functional_test_case.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 9bc2c96753..3b6232d091 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -16,7 +16,9 @@ class phpbb_functional_test_case extends phpbb_test_case { protected $client; protected $root_url; + protected $cache = null; + protected $db = null; /** * Session ID for current test's session (each test makes its own) @@ -70,6 +72,23 @@ class phpbb_functional_test_case extends phpbb_test_case { } + protected function get_db() + { + global $phpbb_root_path, $phpEx; + // so we don't reopen an open connection + if (!($this->db instanceof dbal)) + { + if (!class_exists('dbal_' . self::$config['dbms'])) + { + include($phpbb_root_path . 'includes/db/' . self::$config['dbms'] . ".$phpEx"); + } + $sql_db = 'dbal_' . self::$config['dbms']; + $this->db = new $sql_db(); + $this->db->sql_connect(self::$config['dbhost'], self::$config['dbuser'], self::$config['dbpasswd'], self::$config['dbname'], self::$config['dbport']); + } + return $this->db; + } + protected function get_cache_driver() { if (!$this->cache) From 771bb957ab4dee865ce1678eb675c37874d04e98 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 6 Dec 2012 23:41:02 -0500 Subject: [PATCH 157/443] [ticket/10972] Add mock null cache. The mock cache has instrumentation methods and therefore is non-trivial to implement. For those times when we don't care that the cache caches, null cache is a simpler implementation. PHPBB3-10972 --- tests/mock/null_cache.php | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tests/mock/null_cache.php diff --git a/tests/mock/null_cache.php b/tests/mock/null_cache.php new file mode 100644 index 0000000000..aca20ca77b --- /dev/null +++ b/tests/mock/null_cache.php @@ -0,0 +1,42 @@ + Date: Thu, 6 Dec 2012 23:42:13 -0500 Subject: [PATCH 158/443] [ticket/10972] Add destroy method to mock cache. I actually needed the version that destroys tables, therefore I ended up writing a mock null cache. This code is currently unused but will probably be handy at some point. PHPBB3-10972 --- tests/mock/cache.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/mock/cache.php b/tests/mock/cache.php index 650545c3d6..aa0db5ab20 100644 --- a/tests/mock/cache.php +++ b/tests/mock/cache.php @@ -34,6 +34,16 @@ class phpbb_mock_cache $this->data[$var_name] = $var; } + public function destroy($var_name, $table = '') + { + if ($table) + { + throw new Exception('Destroying tables is not implemented yet'); + } + + unset($this->data[$var_name]); + } + /** * Obtain active bots */ @@ -41,7 +51,7 @@ class phpbb_mock_cache { return $this->data['_bots']; } - + /** * Obtain list of word censors. We don't need to parse them here, * that is tested elsewhere. From fb5c4440e598f2a775a52299a06e903d3cee5398 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 6 Dec 2012 23:43:22 -0500 Subject: [PATCH 159/443] [ticket/10972] Tweak user addition. Always add users, do not keep track of which users have been added. The tests should know whether users they want exist or not. Use more unique user names in tests for robustness. Added some more assertions here and there. PHPBB3-10972 --- tests/functional/auth_test.php | 12 ++-- .../phpbb_functional_test_case.php | 59 +++++++++++-------- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/tests/functional/auth_test.php b/tests/functional/auth_test.php index e67118d8f9..3e218ebd77 100644 --- a/tests/functional/auth_test.php +++ b/tests/functional/auth_test.php @@ -18,16 +18,18 @@ class phpbb_functional_auth_test extends phpbb_functional_test_case // check for logout link $crawler = $this->request('GET', 'index.php'); + $this->assert_response_success(); $this->assertContains($this->lang('LOGOUT_USER', 'admin'), $crawler->filter('.navbar')->text()); } public function test_login_other() { - $this->create_user('user'); - $this->login('user'); + $this->create_user('anothertestuser'); + $this->login('anothertestuser'); $crawler = $this->request('GET', 'index.php'); - $this->assertContains('user', $crawler->filter('.icon-logout')->text()); - $this->delete_user('user'); + $this->assert_response_success(); + $this->assertContains('anothertestuser', $crawler->filter('.icon-logout')->text()); + $this->delete_user('anothertestuser'); } /** @@ -40,10 +42,12 @@ class phpbb_functional_auth_test extends phpbb_functional_test_case // logout $crawler = $this->request('GET', 'ucp.php?sid=' . $this->sid . '&mode=logout'); + $this->assert_response_success(); $this->assertContains($this->lang('LOGOUT_REDIRECT'), $crawler->filter('#message')->text()); // look for a register link, which should be visible only when logged out $crawler = $this->request('GET', 'index.php'); + $this->assert_response_success(); $this->assertContains($this->lang('REGISTER'), $crawler->filter('.navbar')->text()); } } diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 3b6232d091..b17b2dcd5f 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -32,11 +32,6 @@ class phpbb_functional_test_case extends phpbb_test_case */ protected $lang = array(); - /** - * @var array - */ - protected $created_users = array(); - static protected $config = array(); static protected $already_installed = false; @@ -225,14 +220,10 @@ class phpbb_functional_test_case extends phpbb_test_case * requires create_user. * * @param string $username Also doubles up as the user's password + * @return int ID of created user */ protected function create_user($username) { - if (isset($this->created_users[$username])) - { - return; - } - // Required by unique_id global $config; @@ -243,17 +234,36 @@ class phpbb_functional_test_case extends phpbb_test_case $config['rand_seed'] = ''; $config['rand_seed_last_update'] = time() + 600; - - $db = $this->get_db(); - $query = " - INSERT INTO " . self::$config['table_prefix'] . "users - (user_type, group_id, username, username_clean, user_regdate, user_password, user_email, user_lang, user_style, user_rank, user_colour, user_posts, user_permissions, user_ip, user_birthday, user_lastpage, user_last_confirm_key, user_post_sortby_type, user_post_sortby_dir, user_topic_sortby_type, user_topic_sortby_dir, user_avatar, user_sig, user_sig_bbcode_uid, user_from, user_icq, user_aim, user_yim, user_msnm, user_jabber, user_website, user_occ, user_interests, user_actkey, user_newpasswd) - VALUES - (0, 2, 'user', 'user', 0, '" . phpbb_hash($username) . "', 'nobody@example.com', 'en', 1, 0, '', 1, '', '', '', '', '', 't', 'a', 't', 'd', '', '', '', '', '', '', '', '', '', '', '', '', '', '') - "; - $db->sql_query($query); - $this->created_users[$username] = 1; + // Required by user_add + global $db, $cache; + $db = $this->get_db(); + if (!function_exists('phpbb_mock_null_cache')) + { + require_once(__DIR__ . '/../mock/null_cache.php'); + } + $cache = new phpbb_mock_null_cache; + + if (!function_exists('utf_clean_string')) + { + require_once(__DIR__ . '/../../phpBB/includes/utf/utf_tools.php'); + } + if (!function_exists('user_add')) + { + require_once(__DIR__ . '/../../phpBB/includes/functions_user.php'); + } + + $user_row = array( + 'username' => $username, + 'group_id' => 2, + 'user_email' => 'nobody@example.com', + 'user_type' => 0, + 'user_lang' => 'en', + 'user_timezone' => 0, + 'user_dateformat' => '', + 'user_password' => phpbb_hash($username), + ); + return user_add($user_row); } /** @@ -263,11 +273,6 @@ class phpbb_functional_test_case extends phpbb_test_case */ protected function delete_user($username) { - if (isset($this->created_users[$username])) - { - unset($this->created_users[$username]); - } - $db = $this->get_db(); $query = "DELETE FROM " . self::$config['table_prefix'] . "users WHERE username = '" . $db->sql_escape($username) . "'"; $db->sql_query($query); @@ -281,7 +286,9 @@ class phpbb_functional_test_case extends phpbb_test_case $this->assertContains($this->lang('LOGIN_EXPLAIN_UCP'), $crawler->filter('html')->text()); $form = $crawler->selectButton($this->lang('LOGIN'))->form(); - $login = $this->client->submit($form, array('username' => $username, 'password' => $username)); + $crawler = $this->client->submit($form, array('username' => $username, 'password' => $username)); + $this->assert_response_success(); + $this->assertContains($this->lang('LOGIN_REDIRECT'), $crawler->filter('html')->text()); $cookies = $this->cookieJar->all(); From ff993ba9d30f5de49e5231647c5bb76d95c357f8 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 6 Dec 2012 23:47:19 -0500 Subject: [PATCH 160/443] [ticket/10972] Drop user deletion. Users should not be deleted in tests that test user creation. Tests should use unique user names to avoid collisions. User deletion should use user_remove anyway. PHPBB3-10972 --- tests/functional/auth_test.php | 1 - .../test_framework/phpbb_functional_test_case.php | 15 --------------- 2 files changed, 16 deletions(-) diff --git a/tests/functional/auth_test.php b/tests/functional/auth_test.php index 3e218ebd77..662b1bd38b 100644 --- a/tests/functional/auth_test.php +++ b/tests/functional/auth_test.php @@ -29,7 +29,6 @@ class phpbb_functional_auth_test extends phpbb_functional_test_case $crawler = $this->request('GET', 'index.php'); $this->assert_response_success(); $this->assertContains('anothertestuser', $crawler->filter('.icon-logout')->text()); - $this->delete_user('anothertestuser'); } /** diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index b17b2dcd5f..71e88fbcf6 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -216,9 +216,6 @@ class phpbb_functional_test_case extends phpbb_test_case /** * Creates a new user with limited permissions * - * Always call delete_user after running a test that - * requires create_user. - * * @param string $username Also doubles up as the user's password * @return int ID of created user */ @@ -266,18 +263,6 @@ class phpbb_functional_test_case extends phpbb_test_case return user_add($user_row); } - /** - * Deletes a user - * - * @param string $username The username of the user to delete - */ - protected function delete_user($username) - { - $db = $this->get_db(); - $query = "DELETE FROM " . self::$config['table_prefix'] . "users WHERE username = '" . $db->sql_escape($username) . "'"; - $db->sql_query($query); - } - protected function login($username = 'admin') { $this->add_lang('ucp'); From 2bc2cb1f6f78ef8cc2037941501d5389af009cd7 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Mon, 10 Dec 2012 06:42:43 -0500 Subject: [PATCH 161/443] [ticket/10491] Install board once per test run. This is how things used to be. Installing for each test class brings 3-4x performance penalty compared to installing once for the entire test run. However, with a single installation for all tests an individual test can see different data when it is invoked by itself vs when it is executed as part of the entire test suite. PHPBB3-10491 --- tests/test_framework/phpbb_functional_test_case.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 66f4b6db65..1e835fcc35 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -31,6 +31,7 @@ class phpbb_functional_test_case extends phpbb_test_case protected $lang = array(); static protected $config = array(); + static protected $already_installed = false; static public function setUpBeforeClass() { @@ -43,7 +44,11 @@ class phpbb_functional_test_case extends phpbb_test_case self::markTestSkipped('phpbb_functional_url was not set in test_config and wasn\'t set as PHPBB_FUNCTIONAL_URL environment variable either.'); } - self::install_board(); + if (!self::$already_installed) + { + self::install_board(); + self::$already_installed = true; + } } public function setUp() From e2c67a8e42beefe1631a90feeb2215e2137c944b Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 12 Dec 2012 21:46:38 -0500 Subject: [PATCH 162/443] [ticket/11162] Rename tricky updates to database helper. PHPBB3-11162 --- ...unctions_tricky_update.php => functions_database_helper.php} | 0 phpBB/includes/mcp/mcp_forum.php | 2 +- phpBB/includes/mcp/mcp_topic.php | 2 +- .../fixtures/bookmarks_duplicates.xml | 0 .../fixtures/topics_watch_duplicates.xml | 0 .../update_rows_avoiding_duplicates_notify_status_test.php | 2 +- .../update_rows_avoiding_duplicates_test.php | 2 +- 7 files changed, 4 insertions(+), 4 deletions(-) rename phpBB/includes/{functions_tricky_update.php => functions_database_helper.php} (100%) rename tests/{functions_tricky_update => functions_database_helper}/fixtures/bookmarks_duplicates.xml (100%) rename tests/{functions_tricky_update => functions_database_helper}/fixtures/topics_watch_duplicates.xml (100%) rename tests/{functions_tricky_update => functions_database_helper}/update_rows_avoiding_duplicates_notify_status_test.php (98%) rename tests/{functions_tricky_update => functions_database_helper}/update_rows_avoiding_duplicates_test.php (98%) diff --git a/phpBB/includes/functions_tricky_update.php b/phpBB/includes/functions_database_helper.php similarity index 100% rename from phpBB/includes/functions_tricky_update.php rename to phpBB/includes/functions_database_helper.php diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index cd938e83a0..db9fbd90bd 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -417,7 +417,7 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) // Update the topic watch table. if (!function_exists('phpbb_update_rows_avoiding_duplicates_notify_status')) { - include($phpbb_root_path . 'includes/functions_tricky_update.' . $phpEx); + include($phpbb_root_path . 'includes/functions_database_helper.' . $phpEx); } phpbb_update_rows_avoiding_duplicates_notify_status($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index 29dabdd2a2..66d0c7a47e 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -622,7 +622,7 @@ function merge_posts($topic_id, $to_topic_id) // If the topic no longer exist, we will update the topic watch table. if (!function_exists('phpbb_update_rows_avoiding_duplicates_notify_status')) { - include($phpbb_root_path . 'includes/functions_tricky_update.' . $phpEx); + include($phpbb_root_path . 'includes/functions_database_helper.' . $phpEx); } phpbb_update_rows_avoiding_duplicates_notify_status($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); } diff --git a/tests/functions_tricky_update/fixtures/bookmarks_duplicates.xml b/tests/functions_database_helper/fixtures/bookmarks_duplicates.xml similarity index 100% rename from tests/functions_tricky_update/fixtures/bookmarks_duplicates.xml rename to tests/functions_database_helper/fixtures/bookmarks_duplicates.xml diff --git a/tests/functions_tricky_update/fixtures/topics_watch_duplicates.xml b/tests/functions_database_helper/fixtures/topics_watch_duplicates.xml similarity index 100% rename from tests/functions_tricky_update/fixtures/topics_watch_duplicates.xml rename to tests/functions_database_helper/fixtures/topics_watch_duplicates.xml diff --git a/tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php b/tests/functions_database_helper/update_rows_avoiding_duplicates_notify_status_test.php similarity index 98% rename from tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php rename to tests/functions_database_helper/update_rows_avoiding_duplicates_notify_status_test.php index 9052585552..6c0f2da1e1 100644 --- a/tests/functions_tricky_update/update_rows_avoiding_duplicates_notify_status_test.php +++ b/tests/functions_database_helper/update_rows_avoiding_duplicates_notify_status_test.php @@ -7,7 +7,7 @@ * */ -require_once dirname(__FILE__) . '/../../phpBB/includes/functions_tricky_update.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/functions_database_helper.php'; class phpbb_update_rows_avoiding_duplicates_notify_status_test extends phpbb_database_test_case { diff --git a/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php b/tests/functions_database_helper/update_rows_avoiding_duplicates_test.php similarity index 98% rename from tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php rename to tests/functions_database_helper/update_rows_avoiding_duplicates_test.php index 6142997408..2f01d29d15 100644 --- a/tests/functions_tricky_update/update_rows_avoiding_duplicates_test.php +++ b/tests/functions_database_helper/update_rows_avoiding_duplicates_test.php @@ -7,7 +7,7 @@ * */ -require_once dirname(__FILE__) . '/../../phpBB/includes/functions_tricky_update.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/functions_database_helper.php'; class phpbb_update_rows_avoiding_duplicates_test extends phpbb_database_test_case { From 1441b70ae8e97782ae63c479b0635c1622078a48 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 12 Dec 2012 21:47:48 -0500 Subject: [PATCH 163/443] [ticket/10491] Make recreate_database static. PHPBB3-10491 --- tests/test_framework/phpbb_functional_test_case.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 1e835fcc35..71bb994f21 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -192,7 +192,7 @@ class phpbb_functional_test_case extends phpbb_test_case return file_get_contents(self::$config['phpbb_functional_url'] . 'install/index.php?mode=install&sub=' . $sub, false, $context); } - private function recreate_database($config) + static private function recreate_database($config) { $db_conn_mgr = new phpbb_database_test_connection_manager($config); $db_conn_mgr->recreate_db(); From a686910958c0ca6eb64c7be10d60d1ebe15999c9 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 13 Dec 2012 03:07:25 -0500 Subject: [PATCH 164/443] [ticket/11162] Reformat. PHPBB3-11162 --- .../update_rows_avoiding_duplicates_notify_status_test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functions_database_helper/update_rows_avoiding_duplicates_notify_status_test.php b/tests/functions_database_helper/update_rows_avoiding_duplicates_notify_status_test.php index 6c0f2da1e1..d4881daf7e 100644 --- a/tests/functions_database_helper/update_rows_avoiding_duplicates_notify_status_test.php +++ b/tests/functions_database_helper/update_rows_avoiding_duplicates_notify_status_test.php @@ -91,7 +91,7 @@ class phpbb_update_rows_avoiding_duplicates_notify_status_test extends phpbb_dat $sql = 'SELECT notify_status FROM ' . TOPICS_WATCH_TABLE . ' WHERE topic_id = ' . (int) $to . ' - AND user_id = 1'; + AND user_id = 1'; $result = $db->sql_query($sql); $notify_status = $db->sql_fetchfield('notify_status'); $db->sql_freeresult($result); From 789c04b90025cf230b3b965ece8022104128c92c Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 13 Dec 2012 15:42:00 -0500 Subject: [PATCH 165/443] [ticket/11265] Add assertions for board installation success. PHPBB3-11265 --- .../test_framework/phpbb_functional_test_case.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 93a4ab2fbf..8ab6469e9a 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -183,12 +183,20 @@ class phpbb_functional_test_case extends phpbb_test_case self::assertNotSame(false, $content); self::assertContains('Welcome to Installation', $content); - self::do_request('create_table', $data); + $content = self::do_request('create_table', $data); + self::assertNotSame(false, $content); + self::assertContains('The database tables used by phpBB', $content); + // 3.0 or 3.1 + self::assertContains('have been created and populated with some initial data.', $content); - self::do_request('config_file', $data); + $content = self::do_request('config_file', $data); + self::assertNotSame(false, $content); + self::assertContains('Configuration file', $content); file_put_contents($phpbb_root_path . "config.$phpEx", phpbb_create_config_file_data($data, self::$config['dbms'], array(), true, true)); - self::do_request('final', $data); + $content = self::do_request('final', $data); + self::assertNotSame(false, $content); + self::assertContains('You have successfully installed', $content); copy($phpbb_root_path . "config.$phpEx", $phpbb_root_path . "config_test.$phpEx"); } From 845bf6a6384b758c78229738db69845604f02437 Mon Sep 17 00:00:00 2001 From: Nathan Guse Date: Thu, 13 Dec 2012 12:56:09 -0600 Subject: [PATCH 166/443] [ticket/11262] Add .lock in cache directory to .gitignore PHPBB3-11262 --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4093aeb56d..c757210654 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ /phpunit.xml /phpBB/cache/*.html /phpBB/cache/*.php -/phpBB/cache/queue.php.lock +/phpBB/cache/*.lock /phpBB/composer.phar /phpBB/config.php /phpBB/config_dev.php From abcc59fca6bd5d899adbec248ba60db6c013e6a2 Mon Sep 17 00:00:00 2001 From: Nathaniel Guse Date: Mon, 3 Sep 2012 15:10:08 -0500 Subject: [PATCH 167/443] [ticket/8610] Update Bookmarks when merging topics Update bookmarks to the new topic when merging multiple topics using the merge_topics function. PHPBB3-8610 --- phpBB/includes/mcp/mcp_forum.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index b70601b479..865e464e81 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -422,6 +422,14 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) $db->sql_query('DELETE FROM ' . TOPICS_WATCH_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); + // If the topic no longer exist, we will update the bookmarks table. + // To not let it error out on users who bookmarked both topics, we just return on an error... + $db->sql_return_on_error(true); + $db->sql_query('UPDATE ' . BOOKMARKS_TABLE . ' SET topic_id = ' . (int) $to_topic_id . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); + $db->sql_return_on_error(false); + + $db->sql_query('DELETE FROM ' . BOOKMARKS_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); + // Link to the new topic $return_link .= (($return_link) ? '

    ' : '') . sprintf($user->lang['RETURN_NEW_TOPIC'], '', ''); } @@ -444,4 +452,4 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) } } -?> \ No newline at end of file +?> From 8dd2a151cc53a5482fcf462736cf5c2eabccf599 Mon Sep 17 00:00:00 2001 From: Nathaniel Guse Date: Mon, 3 Sep 2012 15:18:30 -0500 Subject: [PATCH 168/443] [ticket/8610] Update Bookmarks when forking topics Update bookmarks to the new topic when forking topics using the mcp_fork_topic function. PHPBB3-8610 --- phpBB/includes/mcp/mcp_main.php | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/phpBB/includes/mcp/mcp_main.php b/phpBB/includes/mcp/mcp_main.php index ffede11d37..f7c49539ea 100644 --- a/phpBB/includes/mcp/mcp_main.php +++ b/phpBB/includes/mcp/mcp_main.php @@ -1251,6 +1251,26 @@ function mcp_fork_topic($topic_ids) { $db->sql_multi_insert(TOPICS_WATCH_TABLE, $sql_ary); } + + $sql = 'SELECT user_id + FROM ' . BOOKMARKS_TABLE . ' + WHERE topic_id = ' . $topic_id; + $result = $db->sql_query($sql); + + $sql_ary = array(); + while ($row = $db->sql_fetchrow($result)) + { + $sql_ary[] = array( + 'topic_id' => (int) $new_topic_id, + 'user_id' => (int) $row['user_id'], + ); + } + $db->sql_freeresult($result); + + if (sizeof($sql_ary)) + { + $db->sql_multi_insert(BOOKMARKS_TABLE, $sql_ary); + } } // Sync new topics, parent forums and board stats @@ -1314,4 +1334,4 @@ function mcp_fork_topic($topic_ids) } } -?> \ No newline at end of file +?> From 05d7decdd35eac3b58807b9ced318421a6ce15da Mon Sep 17 00:00:00 2001 From: Nathaniel Guse Date: Mon, 3 Sep 2012 15:30:52 -0500 Subject: [PATCH 169/443] [ticket/8610] Update Bookmarks when merging posts into another topic Update bookmarks to the new topic when merging posts into another topic using the merge_posts function. PHPBB3-8610 --- phpBB/includes/mcp/mcp_topic.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index 7d4edaf362..36cfe1e355 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -626,6 +626,14 @@ function merge_posts($topic_id, $to_topic_id) $db->sql_return_on_error(false); $db->sql_query('DELETE FROM ' . TOPICS_WATCH_TABLE . ' WHERE topic_id = ' . (int) $topic_id); + + // If the topic no longer exist, we will update the bookmarks table. + // To not let it error out on users who bookmarked both topics, we just return on an error... + $db->sql_return_on_error(true); + $db->sql_query('UPDATE ' . BOOKMARKS_TABLE . ' SET topic_id = ' . (int) $to_topic_id . ' WHERE topic_id = ' . (int) $topic_id); + $db->sql_return_on_error(false); + + $db->sql_query('DELETE FROM ' . BOOKMARKS_TABLE . ' WHERE topic_id = ' . (int) $topic_id); } // Link to the new topic @@ -650,4 +658,4 @@ function merge_posts($topic_id, $to_topic_id) } } -?> \ No newline at end of file +?> From 5a88bd1bf103537aece6713145fd13288cf3c329 Mon Sep 17 00:00:00 2001 From: Nathaniel Guse Date: Mon, 3 Sep 2012 15:35:06 -0500 Subject: [PATCH 170/443] [ticket/8610] Update Bookmarks and Subscriptions when splitting topics Update bookmarks and subscriptions to add bookmarks/subscriptions to the new topic when using the split_topic function PHPBB3-8610 --- phpBB/includes/mcp/mcp_forum.php | 12 +++++-- phpBB/includes/mcp/mcp_topic.php | 56 ++++++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index 865e464e81..ce709e7f71 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -98,6 +98,9 @@ function mcp_forum_view($id, $mode, $action, $forum_info) $forum_topics = ($total == -1) ? $forum_info['forum_topics'] : $total; $limit_time_sql = ($sort_days) ? 'AND t.topic_last_post_time >= ' . (time() - ($sort_days * 86400)) : ''; + $base_url = $url . "&i=$id&action=$action&mode=$mode&sd=$sort_dir&sk=$sort_key&st=$sort_days" . (($merge_select) ? $selected_ids : ''); + phpbb_generate_template_pagination($template, $base_url, 'pagination', 'start', $forum_topics, $topics_per_page, $start); + $template->assign_vars(array( 'ACTION' => $action, 'FORUM_NAME' => $forum_info['forum_name'], @@ -425,10 +428,15 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) // If the topic no longer exist, we will update the bookmarks table. // To not let it error out on users who bookmarked both topics, we just return on an error... $db->sql_return_on_error(true); - $db->sql_query('UPDATE ' . BOOKMARKS_TABLE . ' SET topic_id = ' . (int) $to_topic_id . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); + $sql = 'UPDATE ' . BOOKMARKS_TABLE . ' + SET topic_id = ' . (int) $to_topic_id . ' + WHERE ' . $db->sql_in_set('topic_id', $topic_ids); + $db->sql_query($sql); $db->sql_return_on_error(false); - $db->sql_query('DELETE FROM ' . BOOKMARKS_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); + $sql = 'DELETE FROM ' . BOOKMARKS_TABLE . ' + WHERE ' . $db->sql_in_set('topic_id', $topic_ids); + $db->sql_query($sql); // Link to the new topic $return_link .= (($return_link) ? '

    ' : '') . sprintf($user->lang['RETURN_NEW_TOPIC'], '', ''); diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index 36cfe1e355..f0775f9137 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -307,6 +307,12 @@ function mcp_topic_view($id, $mode, $action) 'post_ids' => $post_id_list, )); + $base_url = append_sid("{$phpbb_root_path}mcp.$phpEx", "i=$id&t={$topic_info['topic_id']}&mode=$mode&action=$action&to_topic_id=$to_topic_id&posts_per_page=$posts_per_page&st=$sort_days&sk=$sort_key&sd=$sort_dir"); + if ($posts_per_page) + { + phpbb_generate_template_pagination($template, $base_url, 'pagination', 'start', $total, $posts_per_page, $start); + } + $template->assign_vars(array( 'TOPIC_TITLE' => $topic_info['topic_title'], 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $topic_info['forum_id'] . '&t=' . $topic_info['topic_id']), @@ -517,6 +523,47 @@ function split_topic($action, $topic_id, $to_forum_id, $subject) WHERE post_id = {$post_id_list[0]}"; $db->sql_query($sql); + $sql = 'SELECT user_id, notify_status + FROM ' . TOPICS_WATCH_TABLE . ' + WHERE topic_id = ' . $topic_id; + $result = $db->sql_query($sql); + + $sql_ary = array(); + while ($row = $db->sql_fetchrow($result)) + { + $sql_ary[] = array( + 'topic_id' => (int) $to_topic_id, + 'user_id' => (int) $row['user_id'], + 'notify_status' => (int) $row['notify_status'], + ); + } + $db->sql_freeresult($result); + + if (sizeof($sql_ary)) + { + $db->sql_multi_insert(TOPICS_WATCH_TABLE, $sql_ary); + } + + $sql = 'SELECT user_id + FROM ' . BOOKMARKS_TABLE . ' + WHERE topic_id = ' . $topic_id; + $result = $db->sql_query($sql); + + $sql_ary = array(); + while ($row = $db->sql_fetchrow($result)) + { + $sql_ary[] = array( + 'topic_id' => (int) $to_topic_id, + 'user_id' => (int) $row['user_id'], + ); + } + $db->sql_freeresult($result); + + if (sizeof($sql_ary)) + { + $db->sql_multi_insert(BOOKMARKS_TABLE, $sql_ary); + } + $success_msg = 'TOPIC_SPLIT_SUCCESS'; // Update forum statistics @@ -630,10 +677,15 @@ function merge_posts($topic_id, $to_topic_id) // If the topic no longer exist, we will update the bookmarks table. // To not let it error out on users who bookmarked both topics, we just return on an error... $db->sql_return_on_error(true); - $db->sql_query('UPDATE ' . BOOKMARKS_TABLE . ' SET topic_id = ' . (int) $to_topic_id . ' WHERE topic_id = ' . (int) $topic_id); + $sql = 'UPDATE ' . BOOKMARKS_TABLE . ' + SET topic_id = ' . (int) $to_topic_id . ' + WHERE topic_id = ' . (int) $topic_id; + $db->sql_query($sql); $db->sql_return_on_error(false); - $db->sql_query('DELETE FROM ' . BOOKMARKS_TABLE . ' WHERE topic_id = ' . (int) $topic_id); + $sql = 'DELETE FROM ' . BOOKMARKS_TABLE . ' + WHERE topic_id = ' . (int) $topic_id; + $db->sql_query($sql); } // Link to the new topic From 71bcc58feecd49fe05f6b7e0e2bca8a94424f240 Mon Sep 17 00:00:00 2001 From: Nathan Guse Date: Tue, 30 Oct 2012 12:27:02 -0500 Subject: [PATCH 171/443] [ticket/8610] Add some comments PHPBB3-8610 --- phpBB/includes/mcp/mcp_main.php | 2 ++ phpBB/includes/mcp/mcp_topic.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/phpBB/includes/mcp/mcp_main.php b/phpBB/includes/mcp/mcp_main.php index f7c49539ea..cce4db8b4d 100644 --- a/phpBB/includes/mcp/mcp_main.php +++ b/phpBB/includes/mcp/mcp_main.php @@ -1231,6 +1231,7 @@ function mcp_fork_topic($topic_ids) } } + // Copy topic subscriptions to new topic $sql = 'SELECT user_id, notify_status FROM ' . TOPICS_WATCH_TABLE . ' WHERE topic_id = ' . $topic_id; @@ -1252,6 +1253,7 @@ function mcp_fork_topic($topic_ids) $db->sql_multi_insert(TOPICS_WATCH_TABLE, $sql_ary); } + // Copy bookmarks to new topic $sql = 'SELECT user_id FROM ' . BOOKMARKS_TABLE . ' WHERE topic_id = ' . $topic_id; diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index f0775f9137..28f5c6a41d 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -523,6 +523,7 @@ function split_topic($action, $topic_id, $to_forum_id, $subject) WHERE post_id = {$post_id_list[0]}"; $db->sql_query($sql); + // Copy topic subscriptions to new topic $sql = 'SELECT user_id, notify_status FROM ' . TOPICS_WATCH_TABLE . ' WHERE topic_id = ' . $topic_id; @@ -544,6 +545,7 @@ function split_topic($action, $topic_id, $to_forum_id, $subject) $db->sql_multi_insert(TOPICS_WATCH_TABLE, $sql_ary); } + // Copy bookmarks to new topic $sql = 'SELECT user_id FROM ' . BOOKMARKS_TABLE . ' WHERE topic_id = ' . $topic_id; From 5c614ff6249c441637103ba0b78338f878057479 Mon Sep 17 00:00:00 2001 From: Nathan Guse Date: Thu, 13 Dec 2012 20:30:16 -0600 Subject: [PATCH 172/443] [ticket/8610] Revert some funky merging I did from rebase PHPBB3-8610 --- phpBB/includes/mcp/mcp_forum.php | 5 +---- phpBB/includes/mcp/mcp_main.php | 2 +- phpBB/includes/mcp/mcp_topic.php | 8 +------- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index ce709e7f71..78239698a9 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -98,9 +98,6 @@ function mcp_forum_view($id, $mode, $action, $forum_info) $forum_topics = ($total == -1) ? $forum_info['forum_topics'] : $total; $limit_time_sql = ($sort_days) ? 'AND t.topic_last_post_time >= ' . (time() - ($sort_days * 86400)) : ''; - $base_url = $url . "&i=$id&action=$action&mode=$mode&sd=$sort_dir&sk=$sort_key&st=$sort_days" . (($merge_select) ? $selected_ids : ''); - phpbb_generate_template_pagination($template, $base_url, 'pagination', 'start', $forum_topics, $topics_per_page, $start); - $template->assign_vars(array( 'ACTION' => $action, 'FORUM_NAME' => $forum_info['forum_name'], @@ -460,4 +457,4 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) } } -?> +?> \ No newline at end of file diff --git a/phpBB/includes/mcp/mcp_main.php b/phpBB/includes/mcp/mcp_main.php index cce4db8b4d..0cef8933fc 100644 --- a/phpBB/includes/mcp/mcp_main.php +++ b/phpBB/includes/mcp/mcp_main.php @@ -1336,4 +1336,4 @@ function mcp_fork_topic($topic_ids) } } -?> +?> \ No newline at end of file diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index 28f5c6a41d..ba11b04884 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -307,12 +307,6 @@ function mcp_topic_view($id, $mode, $action) 'post_ids' => $post_id_list, )); - $base_url = append_sid("{$phpbb_root_path}mcp.$phpEx", "i=$id&t={$topic_info['topic_id']}&mode=$mode&action=$action&to_topic_id=$to_topic_id&posts_per_page=$posts_per_page&st=$sort_days&sk=$sort_key&sd=$sort_dir"); - if ($posts_per_page) - { - phpbb_generate_template_pagination($template, $base_url, 'pagination', 'start', $total, $posts_per_page, $start); - } - $template->assign_vars(array( 'TOPIC_TITLE' => $topic_info['topic_title'], 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $topic_info['forum_id'] . '&t=' . $topic_info['topic_id']), @@ -712,4 +706,4 @@ function merge_posts($topic_id, $to_topic_id) } } -?> +?> \ No newline at end of file From a50907250e487675baf9ac77be564b6ccb72b056 Mon Sep 17 00:00:00 2001 From: Nathan Guse Date: Thu, 13 Dec 2012 20:42:10 -0600 Subject: [PATCH 173/443] [ticket/8610] Use phpbb_update_rows_avoiding_duplicates PHPBB3-8610 --- phpBB/includes/mcp/mcp_forum.php | 16 +++++----------- phpBB/includes/mcp/mcp_topic.php | 12 +----------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index 78239698a9..097f67487d 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -423,17 +423,11 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) $db->sql_query('DELETE FROM ' . TOPICS_WATCH_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); // If the topic no longer exist, we will update the bookmarks table. - // To not let it error out on users who bookmarked both topics, we just return on an error... - $db->sql_return_on_error(true); - $sql = 'UPDATE ' . BOOKMARKS_TABLE . ' - SET topic_id = ' . (int) $to_topic_id . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); - $db->sql_return_on_error(false); - - $sql = 'DELETE FROM ' . BOOKMARKS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); + if (!function_exists('phpbb_update_rows_avoiding_duplicates')) + { + include($phpbb_root_path . 'includes/functions_database_helper.' . $phpEx); + } + phpbb_update_rows_avoiding_duplicates($db, BOOKMARKS_TABLE, 'topic_id', $topic_ids, $to_topic_id); // Link to the new topic $return_link .= (($return_link) ? '

    ' : '') . sprintf($user->lang['RETURN_NEW_TOPIC'], '', ''); diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index ba11b04884..29d7a0e41b 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -671,17 +671,7 @@ function merge_posts($topic_id, $to_topic_id) $db->sql_query('DELETE FROM ' . TOPICS_WATCH_TABLE . ' WHERE topic_id = ' . (int) $topic_id); // If the topic no longer exist, we will update the bookmarks table. - // To not let it error out on users who bookmarked both topics, we just return on an error... - $db->sql_return_on_error(true); - $sql = 'UPDATE ' . BOOKMARKS_TABLE . ' - SET topic_id = ' . (int) $to_topic_id . ' - WHERE topic_id = ' . (int) $topic_id; - $db->sql_query($sql); - $db->sql_return_on_error(false); - - $sql = 'DELETE FROM ' . BOOKMARKS_TABLE . ' - WHERE topic_id = ' . (int) $topic_id; - $db->sql_query($sql); + phpbb_update_rows_avoiding_duplicates($db, BOOKMARKS_TABLE, 'topic_id', $topic_id, $to_topic_id); } // Link to the new topic From 9eb9fa2b9d117b919dfcc1e37d6c1186841b4fe7 Mon Sep 17 00:00:00 2001 From: Nathan Guse Date: Thu, 13 Dec 2012 22:38:17 -0600 Subject: [PATCH 174/443] [ticket/8610] Create helper functions to create topic/post in functional tests This will be used to test splitting/copying/merging/etc in functional tests Also convert functional posting_test.php to use these functions PHPBB3-8610 --- tests/functional/posting_test.php | 89 ++------------- .../phpbb_functional_test_case.php | 101 ++++++++++++++++++ 2 files changed, 112 insertions(+), 78 deletions(-) diff --git a/tests/functional/posting_test.php b/tests/functional/posting_test.php index f54a3591b2..6aa7a46974 100644 --- a/tests/functional/posting_test.php +++ b/tests/functional/posting_test.php @@ -15,88 +15,21 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case public function test_post_new_topic() { $this->login(); - $this->add_lang('posting'); - $crawler = $this->request('GET', 'posting.php?mode=post&f=2&sid=' . $this->sid); - $this->assertContains($this->lang('POST_TOPIC'), $crawler->filter('html')->text()); + // Test creating topic + $post = $this->create_topic(2, 'Test Topic 1', 'This is a test topic posted by the testing framework.'); - $hidden_fields = array(); - $hidden_fields[] = $crawler->filter('[type="hidden"]')->each(function ($node, $i) { - return array('name' => $node->getAttribute('name'), 'value' => $node->getAttribute('value')); - }); + $crawler = $this->request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}"); + $this->assertContains('This is a test topic posted by the testing framework.', $crawler->filter('html')->text()); - $test_message = 'This is a test topic posted by the testing framework.'; - $form_data = array( - 'subject' => 'Test Topic 1', - 'message' => $test_message, - 'post' => true, - 'f' => 2, - 'mode' => 'post', - 'sid' => $this->sid, - ); + // Test creating a reply + $post2 = $this->create_post(2, $post['topic_id'], 'Re: Test Topic 1', 'This is a test post posted by the testing framework.'); - foreach ($hidden_fields as $fields) - { - foreach($fields as $field) - { - $form_data[$field['name']] = $field['value']; - } - } + $crawler = $this->request('GET', "viewtopic.php?t={$post2['topic_id']}&sid={$this->sid}"); + $this->assertContains('This is a test post posted by the testing framework.', $crawler->filter('html')->text()); - // Bypass time restriction that said that if the lastclick time (i.e. time when the form was opened) - // is not at least 2 seconds before submission, cancel the form - $form_data['lastclick'] = 0; - - // I use a request because the form submission method does not allow you to send data that is not - // contained in one of the actual form fields that the browser sees (i.e. it ignores "hidden" inputs) - // Instead, I send it as a request with the submit button "post" set to true. - $crawler = $this->client->request('POST', 'posting.php', $form_data); - $this->assertContains($this->lang('POST_STORED'), $crawler->filter('html')->text()); - - $crawler = $this->request('GET', 'viewtopic.php?t=2&sid=' . $this->sid); - $this->assertContains($test_message, $crawler->filter('html')->text()); - } - - public function test_post_reply() - { - $this->login(); - $this->add_lang('posting'); - - $crawler = $this->request('GET', 'posting.php?mode=reply&t=2&f=2&sid=' . $this->sid); - $this->assertContains($this->lang('POST_REPLY'), $crawler->filter('html')->text()); - - $hidden_fields = array(); - $hidden_fields[] = $crawler->filter('[type="hidden"]')->each(function ($node, $i) { - return array('name' => $node->getAttribute('name'), 'value' => $node->getAttribute('value')); - }); - - $test_message = 'This is a test post posted by the testing framework.'; - $form_data = array( - 'subject' => 'Re: Test Topic 1', - 'message' => $test_message, - 'post' => true, - 't' => 2, - 'f' => 2, - 'mode' => 'reply', - 'sid' => $this->sid, - ); - - foreach ($hidden_fields as $fields) - { - foreach($fields as $field) - { - $form_data[$field['name']] = $field['value']; - } - } - - // For reasoning behind the following command, see the test_post_new_topic() test - $form_data['lastclick'] = 0; - - // Submit the post - $crawler = $this->client->request('POST', 'posting.php', $form_data); - $this->assertContains($this->lang('POST_STORED'), $crawler->filter('html')->text()); - - $crawler = $this->request('GET', 'viewtopic.php?t=2&sid=' . $this->sid); - $this->assertContains($test_message, $crawler->filter('html')->text()); + // Test quoting a message + $crawler = $this->request('GET', "posting.php?mode=quote&f=2&t={$post2['topic_id']}&p={$post2['post_id']}&sid={$this->sid}"); + $this->assertContains('This is a test post posted by the testing framework.', $crawler->filter('html')->text()); } } diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 8ab6469e9a..e6a9023a3b 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -275,6 +275,107 @@ class phpbb_functional_test_case extends phpbb_test_case return user_add($user_row); } + /** + * Creates a topic + * + * Be sure to login before creating + * + * @param int $forum_id + * @param string $subject + * @param string $message + * @param array $additional_form_data Any additional form data to be sent in the request + * @return array post_id, topic_id + */ + protected function create_topic($forum_id, $subject, $message, $additional_form_data = array()) + { + $posting_url = "posting.php?mode=post&f={$forum_id}&sid={$this->sid}"; + + $form_data = array_merge(array( + 'subject' => $subject, + 'message' => $message, + 'post' => true, + ), $additional_form_data); + + return $this->submit_post($posting_url, 'POST_TOPIC', $form_data); + } + + /** + * Creates a post + * + * Be sure to login before creating + * + * @param int $forum_id + * @param string $subject + * @param string $message + * @param array $additional_form_data Any additional form data to be sent in the request + * @return array post_id, topic_id + */ + protected function create_post($forum_id, $topic_id, $subject, $message, $additional_form_data = array()) + { + $posting_url = "posting.php?mode=reply&f={$forum_id}&t={$topic_id}&sid={$this->sid}"; + + $form_data = array_merge(array( + 'subject' => $subject, + 'message' => $message, + 'post' => true, + ), $additional_form_data); + + return $this->submit_post($posting_url, 'POST_REPLY', $form_data); + } + + /** + * Helper for submitting posts + * + * @param string $posting_url + * @param string $posting_contains + * @param array $form_data + * @return array post_id, topic_id + */ + protected function submit_post($posting_url, $posting_contains, $form_data) + { + $this->add_lang('posting'); + + $crawler = $this->request('GET', $posting_url); + $this->assertContains($this->lang($posting_contains), $crawler->filter('html')->text()); + + $hidden_fields = array( + $crawler->filter('[type="hidden"]')->each(function ($node, $i) { + return array('name' => $node->getAttribute('name'), 'value' => $node->getAttribute('value')); + }), + ); + + foreach ($hidden_fields as $fields) + { + foreach($fields as $field) + { + $form_data[$field['name']] = $field['value']; + } + } + + // Bypass time restriction that said that if the lastclick time (i.e. time when the form was opened) + // is not at least 2 seconds before submission, cancel the form + $form_data['lastclick'] = 0; + + // I use a request because the form submission method does not allow you to send data that is not + // contained in one of the actual form fields that the browser sees (i.e. it ignores "hidden" inputs) + // Instead, I send it as a request with the submit button "post" set to true. + $crawler = $this->client->request('POST', $posting_url, $form_data); + $this->assertContains($this->lang('POST_STORED'), $crawler->filter('html')->text()); + + $url = $crawler->selectLink(str_replace('%s', '', $this->lang['VIEW_MESSAGE']))->link()->getUri(); + + $matches = $topic_id = $post_id = false; + preg_match_all('#&t=([0-9]+)(&p=([0-9]+))?#', $url, $matches); + + $topic_id = (int) (isset($matches[1][0])) ? $matches[1][0] : 0; + $post_id = (int) (isset($matches[3][0])) ? $matches[3][0] : 0; + + return array( + 'topic_id' => $topic_id, + 'post_id' => $post_id, + ); + } + protected function login($username = 'admin') { $this->add_lang('ucp'); From d739745ea4ccc224b6b7fb686339138733c2203d Mon Sep 17 00:00:00 2001 From: Nathan Guse Date: Thu, 13 Dec 2012 23:09:45 -0600 Subject: [PATCH 175/443] [ticket/8610] Move posting helpers to separate file This is to prevent cluttering up the functional test case class more PHPBB3-8610 --- tests/functional/posting_test.php | 8 +- .../phpbb_functional_test_case.php | 115 ++--------------- tests/test_framework/posting_helpers.php | 119 ++++++++++++++++++ 3 files changed, 137 insertions(+), 105 deletions(-) create mode 100644 tests/test_framework/posting_helpers.php diff --git a/tests/functional/posting_test.php b/tests/functional/posting_test.php index 6aa7a46974..dd078286d6 100644 --- a/tests/functional/posting_test.php +++ b/tests/functional/posting_test.php @@ -15,15 +15,19 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case public function test_post_new_topic() { $this->login(); + + include(__DIR__ . './../test_framework/posting_helpers.php'); + + $posting_helper = new phpbb_test_framework_posting_helpers($this); // Test creating topic - $post = $this->create_topic(2, 'Test Topic 1', 'This is a test topic posted by the testing framework.'); + $post = $posting_helper->create_topic(2, 'Test Topic 1', 'This is a test topic posted by the testing framework.'); $crawler = $this->request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}"); $this->assertContains('This is a test topic posted by the testing framework.', $crawler->filter('html')->text()); // Test creating a reply - $post2 = $this->create_post(2, $post['topic_id'], 'Re: Test Topic 1', 'This is a test post posted by the testing framework.'); + $post2 = $posting_helper->create_post(2, $post['topic_id'], 'Re: Test Topic 1', 'This is a test post posted by the testing framework.'); $crawler = $this->request('GET', "viewtopic.php?t={$post2['topic_id']}&sid={$this->sid}"); $this->assertContains('This is a test post posted by the testing framework.', $crawler->filter('html')->text()); diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index e6a9023a3b..097db62e29 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -275,107 +275,6 @@ class phpbb_functional_test_case extends phpbb_test_case return user_add($user_row); } - /** - * Creates a topic - * - * Be sure to login before creating - * - * @param int $forum_id - * @param string $subject - * @param string $message - * @param array $additional_form_data Any additional form data to be sent in the request - * @return array post_id, topic_id - */ - protected function create_topic($forum_id, $subject, $message, $additional_form_data = array()) - { - $posting_url = "posting.php?mode=post&f={$forum_id}&sid={$this->sid}"; - - $form_data = array_merge(array( - 'subject' => $subject, - 'message' => $message, - 'post' => true, - ), $additional_form_data); - - return $this->submit_post($posting_url, 'POST_TOPIC', $form_data); - } - - /** - * Creates a post - * - * Be sure to login before creating - * - * @param int $forum_id - * @param string $subject - * @param string $message - * @param array $additional_form_data Any additional form data to be sent in the request - * @return array post_id, topic_id - */ - protected function create_post($forum_id, $topic_id, $subject, $message, $additional_form_data = array()) - { - $posting_url = "posting.php?mode=reply&f={$forum_id}&t={$topic_id}&sid={$this->sid}"; - - $form_data = array_merge(array( - 'subject' => $subject, - 'message' => $message, - 'post' => true, - ), $additional_form_data); - - return $this->submit_post($posting_url, 'POST_REPLY', $form_data); - } - - /** - * Helper for submitting posts - * - * @param string $posting_url - * @param string $posting_contains - * @param array $form_data - * @return array post_id, topic_id - */ - protected function submit_post($posting_url, $posting_contains, $form_data) - { - $this->add_lang('posting'); - - $crawler = $this->request('GET', $posting_url); - $this->assertContains($this->lang($posting_contains), $crawler->filter('html')->text()); - - $hidden_fields = array( - $crawler->filter('[type="hidden"]')->each(function ($node, $i) { - return array('name' => $node->getAttribute('name'), 'value' => $node->getAttribute('value')); - }), - ); - - foreach ($hidden_fields as $fields) - { - foreach($fields as $field) - { - $form_data[$field['name']] = $field['value']; - } - } - - // Bypass time restriction that said that if the lastclick time (i.e. time when the form was opened) - // is not at least 2 seconds before submission, cancel the form - $form_data['lastclick'] = 0; - - // I use a request because the form submission method does not allow you to send data that is not - // contained in one of the actual form fields that the browser sees (i.e. it ignores "hidden" inputs) - // Instead, I send it as a request with the submit button "post" set to true. - $crawler = $this->client->request('POST', $posting_url, $form_data); - $this->assertContains($this->lang('POST_STORED'), $crawler->filter('html')->text()); - - $url = $crawler->selectLink(str_replace('%s', '', $this->lang['VIEW_MESSAGE']))->link()->getUri(); - - $matches = $topic_id = $post_id = false; - preg_match_all('#&t=([0-9]+)(&p=([0-9]+))?#', $url, $matches); - - $topic_id = (int) (isset($matches[1][0])) ? $matches[1][0] : 0; - $post_id = (int) (isset($matches[3][0])) ? $matches[3][0] : 0; - - return array( - 'topic_id' => $topic_id, - 'post_id' => $post_id, - ); - } - protected function login($username = 'admin') { $this->add_lang('ucp'); @@ -400,7 +299,7 @@ class phpbb_functional_test_case extends phpbb_test_case } } - protected function add_lang($lang_file) + public function add_lang($lang_file) { if (is_array($lang_file)) { @@ -422,7 +321,7 @@ class phpbb_functional_test_case extends phpbb_test_case $this->lang = array_merge($this->lang, $lang); } - protected function lang() + public function lang() { $args = func_get_args(); $key = $args[0]; @@ -451,4 +350,14 @@ class phpbb_functional_test_case extends phpbb_test_case $content = $this->client->getResponse()->getContent(); $this->assertNotContains('Fatal error:', $content); } + + public function get_sid() + { + return $this->sid; + } + + public function get_client() + { + return $this->client; + } } diff --git a/tests/test_framework/posting_helpers.php b/tests/test_framework/posting_helpers.php new file mode 100644 index 0000000000..329cf5a1b4 --- /dev/null +++ b/tests/test_framework/posting_helpers.php @@ -0,0 +1,119 @@ +test_case = $test_case; + } + + /** + * Creates a topic + * + * Be sure to login before creating + * + * @param int $forum_id + * @param string $subject + * @param string $message + * @param array $additional_form_data Any additional form data to be sent in the request + * @return array post_id, topic_id + */ + public function create_topic($forum_id, $subject, $message, $additional_form_data = array()) + { + $posting_url = "posting.php?mode=post&f={$forum_id}&sid={$this->test_case->get_sid()}"; + + $form_data = array_merge(array( + 'subject' => $subject, + 'message' => $message, + 'post' => true, + ), $additional_form_data); + + return $this->submit_post($posting_url, 'POST_TOPIC', $form_data); + } + + /** + * Creates a post + * + * Be sure to login before creating + * + * @param int $forum_id + * @param string $subject + * @param string $message + * @param array $additional_form_data Any additional form data to be sent in the request + * @return array post_id, topic_id + */ + public function create_post($forum_id, $topic_id, $subject, $message, $additional_form_data = array()) + { + $posting_url = "posting.php?mode=reply&f={$forum_id}&t={$topic_id}&sid={$this->test_case->get_sid()}"; + + $form_data = array_merge(array( + 'subject' => $subject, + 'message' => $message, + 'post' => true, + ), $additional_form_data); + + return $this->submit_post($posting_url, 'POST_REPLY', $form_data); + } + + /** + * Helper for submitting posts + * + * @param string $posting_url + * @param string $posting_contains + * @param array $form_data + * @return array post_id, topic_id + */ + protected function submit_post($posting_url, $posting_contains, $form_data) + { + $this->test_case->add_lang('posting'); + + $crawler = $this->test_case->request('GET', $posting_url); + $this->test_case->assertContains($this->test_case->lang($posting_contains), $crawler->filter('html')->text()); + + $hidden_fields = array( + $crawler->filter('[type="hidden"]')->each(function ($node, $i) { + return array('name' => $node->getAttribute('name'), 'value' => $node->getAttribute('value')); + }), + ); + + foreach ($hidden_fields as $fields) + { + foreach($fields as $field) + { + $form_data[$field['name']] = $field['value']; + } + } + + // Bypass time restriction that said that if the lastclick time (i.e. time when the form was opened) + // is not at least 2 seconds before submission, cancel the form + $form_data['lastclick'] = 0; + + // I use a request because the form submission method does not allow you to send data that is not + // contained in one of the actual form fields that the browser sees (i.e. it ignores "hidden" inputs) + // Instead, I send it as a request with the submit button "post" set to true. + $crawler = $this->test_case->get_client()->request('POST', $posting_url, $form_data); + $this->test_case->assertContains($this->test_case->lang('POST_STORED'), $crawler->filter('html')->text()); + + $url = $crawler->selectLink($this->test_case->lang('VIEW_MESSAGE', '', ''))->link()->getUri(); + + $matches = $topic_id = $post_id = false; + preg_match_all('#&t=([0-9]+)(&p=([0-9]+))?#', $url, $matches); + + $topic_id = (int) (isset($matches[1][0])) ? $matches[1][0] : 0; + $post_id = (int) (isset($matches[3][0])) ? $matches[3][0] : 0; + + return array( + 'topic_id' => $topic_id, + 'post_id' => $post_id, + ); + } +} From 175b6deb6d263a3184d4b51cb1f00137cadc542e Mon Sep 17 00:00:00 2001 From: Nathan Guse Date: Sat, 15 Dec 2012 16:22:54 -0600 Subject: [PATCH 176/443] [ticket/8610] Do not use requests to submit posts except in posting_test.php Moving my functional test functions from posting_helpers.php to posting_test.php since it is a bit nicer and more reusable if posting_test.php is to be expanded in the future. PHPBB3-8610 --- tests/functional/posting_test.php | 112 ++++++++++++++++- .../phpbb_functional_test_case.php | 14 +-- tests/test_framework/posting_helpers.php | 119 ------------------ 3 files changed, 108 insertions(+), 137 deletions(-) delete mode 100644 tests/test_framework/posting_helpers.php diff --git a/tests/functional/posting_test.php b/tests/functional/posting_test.php index dd078286d6..d05207edf0 100644 --- a/tests/functional/posting_test.php +++ b/tests/functional/posting_test.php @@ -15,25 +15,125 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case public function test_post_new_topic() { $this->login(); - - include(__DIR__ . './../test_framework/posting_helpers.php'); - - $posting_helper = new phpbb_test_framework_posting_helpers($this); // Test creating topic - $post = $posting_helper->create_topic(2, 'Test Topic 1', 'This is a test topic posted by the testing framework.'); + $post = $this->create_topic(2, 'Test Topic 1', 'This is a test topic posted by the testing framework.'); $crawler = $this->request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}"); $this->assertContains('This is a test topic posted by the testing framework.', $crawler->filter('html')->text()); // Test creating a reply - $post2 = $posting_helper->create_post(2, $post['topic_id'], 'Re: Test Topic 1', 'This is a test post posted by the testing framework.'); + $post2 = $this->create_post(2, $post['topic_id'], 'Re: Test Topic 1', 'This is a test post posted by the testing framework.'); $crawler = $this->request('GET', "viewtopic.php?t={$post2['topic_id']}&sid={$this->sid}"); $this->assertContains('This is a test post posted by the testing framework.', $crawler->filter('html')->text()); // Test quoting a message $crawler = $this->request('GET', "posting.php?mode=quote&f=2&t={$post2['topic_id']}&p={$post2['post_id']}&sid={$this->sid}"); + $this->assert_response_success(); $this->assertContains('This is a test post posted by the testing framework.', $crawler->filter('html')->text()); } + + /** + * Creates a topic + * + * Be sure to login before creating + * + * @param int $forum_id + * @param string $subject + * @param string $message + * @param array $additional_form_data Any additional form data to be sent in the request + * @return array post_id, topic_id + */ + public function create_topic($forum_id, $subject, $message, $additional_form_data = array()) + { + $posting_url = "posting.php?mode=post&f={$forum_id}&sid={$this->sid}"; + + $form_data = array_merge(array( + 'subject' => $subject, + 'message' => $message, + 'post' => true, + ), $additional_form_data); + + return $this->submit_post($posting_url, 'POST_TOPIC', $form_data); + } + + /** + * Creates a post + * + * Be sure to login before creating + * + * @param int $forum_id + * @param string $subject + * @param string $message + * @param array $additional_form_data Any additional form data to be sent in the request + * @return array post_id, topic_id + */ + public function create_post($forum_id, $topic_id, $subject, $message, $additional_form_data = array()) + { + $posting_url = "posting.php?mode=reply&f={$forum_id}&t={$topic_id}&sid={$this->sid}"; + + $form_data = array_merge(array( + 'subject' => $subject, + 'message' => $message, + 'post' => true, + ), $additional_form_data); + + return $this->submit_post($posting_url, 'POST_REPLY', $form_data); + } + + /** + * Helper for submitting posts + * + * @param string $posting_url + * @param string $posting_contains + * @param array $form_data + * @return array post_id, topic_id + */ + protected function submit_post($posting_url, $posting_contains, $form_data) + { + $this->add_lang('posting'); + + $crawler = $this->request('GET', $posting_url); + $this->assert_response_success(); + $this->assertContains($this->lang($posting_contains), $crawler->filter('html')->text()); + + $hidden_fields = array( + $crawler->filter('[type="hidden"]')->each(function ($node, $i) { + return array('name' => $node->getAttribute('name'), 'value' => $node->getAttribute('value')); + }), + ); + + foreach ($hidden_fields as $fields) + { + foreach($fields as $field) + { + $form_data[$field['name']] = $field['value']; + } + } + + // Bypass time restriction that said that if the lastclick time (i.e. time when the form was opened) + // is not at least 2 seconds before submission, cancel the form + $form_data['lastclick'] = 0; + + // I use a request because the form submission method does not allow you to send data that is not + // contained in one of the actual form fields that the browser sees (i.e. it ignores "hidden" inputs) + // Instead, I send it as a request with the submit button "post" set to true. + $crawler = $this->client->request('POST', $posting_url, $form_data); + $this->assert_response_success(); + $this->assertContains($this->lang('POST_STORED'), $crawler->filter('html')->text()); + + $url = $crawler->selectLink($this->lang('VIEW_MESSAGE', '', ''))->link()->getUri(); + + $matches = $topic_id = $post_id = false; + preg_match_all('#&t=([0-9]+)(&p=([0-9]+))?#', $url, $matches); + + $topic_id = (int) (isset($matches[1][0])) ? $matches[1][0] : 0; + $post_id = (int) (isset($matches[3][0])) ? $matches[3][0] : 0; + + return array( + 'topic_id' => $topic_id, + 'post_id' => $post_id, + ); + } } diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 097db62e29..8ab6469e9a 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -299,7 +299,7 @@ class phpbb_functional_test_case extends phpbb_test_case } } - public function add_lang($lang_file) + protected function add_lang($lang_file) { if (is_array($lang_file)) { @@ -321,7 +321,7 @@ class phpbb_functional_test_case extends phpbb_test_case $this->lang = array_merge($this->lang, $lang); } - public function lang() + protected function lang() { $args = func_get_args(); $key = $args[0]; @@ -350,14 +350,4 @@ class phpbb_functional_test_case extends phpbb_test_case $content = $this->client->getResponse()->getContent(); $this->assertNotContains('Fatal error:', $content); } - - public function get_sid() - { - return $this->sid; - } - - public function get_client() - { - return $this->client; - } } diff --git a/tests/test_framework/posting_helpers.php b/tests/test_framework/posting_helpers.php deleted file mode 100644 index 329cf5a1b4..0000000000 --- a/tests/test_framework/posting_helpers.php +++ /dev/null @@ -1,119 +0,0 @@ -test_case = $test_case; - } - - /** - * Creates a topic - * - * Be sure to login before creating - * - * @param int $forum_id - * @param string $subject - * @param string $message - * @param array $additional_form_data Any additional form data to be sent in the request - * @return array post_id, topic_id - */ - public function create_topic($forum_id, $subject, $message, $additional_form_data = array()) - { - $posting_url = "posting.php?mode=post&f={$forum_id}&sid={$this->test_case->get_sid()}"; - - $form_data = array_merge(array( - 'subject' => $subject, - 'message' => $message, - 'post' => true, - ), $additional_form_data); - - return $this->submit_post($posting_url, 'POST_TOPIC', $form_data); - } - - /** - * Creates a post - * - * Be sure to login before creating - * - * @param int $forum_id - * @param string $subject - * @param string $message - * @param array $additional_form_data Any additional form data to be sent in the request - * @return array post_id, topic_id - */ - public function create_post($forum_id, $topic_id, $subject, $message, $additional_form_data = array()) - { - $posting_url = "posting.php?mode=reply&f={$forum_id}&t={$topic_id}&sid={$this->test_case->get_sid()}"; - - $form_data = array_merge(array( - 'subject' => $subject, - 'message' => $message, - 'post' => true, - ), $additional_form_data); - - return $this->submit_post($posting_url, 'POST_REPLY', $form_data); - } - - /** - * Helper for submitting posts - * - * @param string $posting_url - * @param string $posting_contains - * @param array $form_data - * @return array post_id, topic_id - */ - protected function submit_post($posting_url, $posting_contains, $form_data) - { - $this->test_case->add_lang('posting'); - - $crawler = $this->test_case->request('GET', $posting_url); - $this->test_case->assertContains($this->test_case->lang($posting_contains), $crawler->filter('html')->text()); - - $hidden_fields = array( - $crawler->filter('[type="hidden"]')->each(function ($node, $i) { - return array('name' => $node->getAttribute('name'), 'value' => $node->getAttribute('value')); - }), - ); - - foreach ($hidden_fields as $fields) - { - foreach($fields as $field) - { - $form_data[$field['name']] = $field['value']; - } - } - - // Bypass time restriction that said that if the lastclick time (i.e. time when the form was opened) - // is not at least 2 seconds before submission, cancel the form - $form_data['lastclick'] = 0; - - // I use a request because the form submission method does not allow you to send data that is not - // contained in one of the actual form fields that the browser sees (i.e. it ignores "hidden" inputs) - // Instead, I send it as a request with the submit button "post" set to true. - $crawler = $this->test_case->get_client()->request('POST', $posting_url, $form_data); - $this->test_case->assertContains($this->test_case->lang('POST_STORED'), $crawler->filter('html')->text()); - - $url = $crawler->selectLink($this->test_case->lang('VIEW_MESSAGE', '', ''))->link()->getUri(); - - $matches = $topic_id = $post_id = false; - preg_match_all('#&t=([0-9]+)(&p=([0-9]+))?#', $url, $matches); - - $topic_id = (int) (isset($matches[1][0])) ? $matches[1][0] : 0; - $post_id = (int) (isset($matches[3][0])) ? $matches[3][0] : 0; - - return array( - 'topic_id' => $topic_id, - 'post_id' => $post_id, - ); - } -} From 649e009f7b42a751d7b208bd5a4659c0fc442912 Mon Sep 17 00:00:00 2001 From: Nathan Guse Date: Sat, 15 Dec 2012 16:23:48 -0600 Subject: [PATCH 177/443] [ticket/8610] Update comment PHPBB3-8610 --- phpBB/includes/mcp/mcp_forum.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index de2966d34e..04e0e70f1d 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -422,7 +422,7 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) // Update the topic watch table. phpbb_update_rows_avoiding_duplicates_notify_status($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); - // If the topic no longer exist, we will update the bookmarks table. + // Update the bookmarks table. phpbb_update_rows_avoiding_duplicates($db, BOOKMARKS_TABLE, 'topic_id', $topic_ids, $to_topic_id); // Link to the new topic From f0c780a45359ceb3eb3fe8ab6b0e5f8c0f07e26f Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 19 Dec 2012 13:35:48 +0100 Subject: [PATCH 178/443] [ticket/11278] Fix not running queries from db tools in database update The db_tools class is running in return mode, which means that the queries are not run, but just returned. Therefor the broken tables were not removed from the database. PHPBB3-11278 --- phpBB/install/database_update.php | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 983b1b46c4..0281aea0b3 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -1017,7 +1017,7 @@ function database_update_info() *****************************************************************************/ function change_database_data(&$no_updates, $version) { - global $db, $errored, $error_ary, $config, $phpbb_root_path, $phpEx; + global $db, $db_tools, $errored, $error_ary, $config, $phpbb_root_path, $phpEx; switch ($version) { @@ -1332,8 +1332,6 @@ function change_database_data(&$no_updates, $version) ), ); - global $db_tools; - $statements = $db_tools->perform_schema_changes($changes); foreach ($statements as $sql) @@ -1975,24 +1973,25 @@ function change_database_data(&$no_updates, $version) } $db->sql_freeresult($result); - global $db_tools, $table_prefix; + global $table_prefix; // Recover from potentially broken Q&A CAPTCHA table on firebird // Q&A CAPTCHA was uninstallable, so it's safe to remove these // without data loss if ($db_tools->sql_layer == 'firebird') { - $tables = array( - $table_prefix . 'captcha_questions', - $table_prefix . 'captcha_answers', - $table_prefix . 'qa_confirm', + $changes = array( + 'drop_tables' => array( + $table_prefix . 'captcha_questions', + $table_prefix . 'captcha_answers', + $table_prefix . 'qa_confirm', + ), ); - foreach ($tables as $table) + $statements = $db_tools->perform_schema_changes($changes); + + foreach ($statements as $sql) { - if ($db_tools->sql_table_exists($table)) - { - $db_tools->sql_table_drop($table); - } + _sql($sql, $errored, $error_ary); } } From 917a2fa9a6cf8b01a347df67fc14d3fc826aa3ed Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Tue, 22 May 2012 02:20:21 +0200 Subject: [PATCH 179/443] [ticket/10880] The m_approve permisson no longer implies f_noapprove. PHPBB3-10880 --- phpBB/includes/functions_posting.php | 5 +++-- phpBB/posting.php | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index a1029ab97a..e5cbae0d71 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -1698,8 +1698,9 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u // The variable name should be $post_approved, because it indicates if the post is approved or not $post_approval = 1; - // Check the permissions for post approval. Moderators are not affected. - if (!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id'])) + // Check the permissions for post approval. + // Moderators must go through post approval like ordinary users. + if (!$auth->acl_get('f_noapprove', $data['forum_id'])) { // Post not approved, but in queue $post_approval = 0; diff --git a/phpBB/posting.php b/phpBB/posting.php index 76c8100c78..e57f5420f5 100644 --- a/phpBB/posting.php +++ b/phpBB/posting.php @@ -1018,7 +1018,7 @@ if ($submit || $preview || $refresh) $forum_type = (int) $db->sql_fetchfield('forum_type'); $db->sql_freeresult($result); - if ($forum_type != FORUM_POST || !$auth->acl_get('f_post', $to_forum_id) || (!$auth->acl_get('m_approve', $to_forum_id) && !$auth->acl_get('f_noapprove', $to_forum_id))) + if ($forum_type != FORUM_POST || !$auth->acl_get('f_post', $to_forum_id) || !$auth->acl_get('f_noapprove', $to_forum_id)) { $to_forum_id = 0; } @@ -1138,8 +1138,9 @@ if ($submit || $preview || $refresh) $captcha->reset(); } - // Check the permissions for post approval. Moderators are not affected. - if ((!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id']) && empty($data['force_approved_state'])) || (isset($data['force_approved_state']) && !$data['force_approved_state'])) + // Check the permissions for post approval. + // Moderators must go through post approval like ordinary users. + if ((!$auth->acl_get('f_noapprove', $data['forum_id']) && empty($data['force_approved_state'])) || (isset($data['force_approved_state']) && !$data['force_approved_state'])) { meta_refresh(10, $redirect_url); $message = ($mode == 'edit') ? $user->lang['POST_EDITED_MOD'] : $user->lang['POST_STORED_MOD']; From 00d8f944da084a660ef72f21438b22297eb1c857 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 20 Dec 2012 13:20:05 -0500 Subject: [PATCH 180/443] [ticket/11285] Use more granularity in dependency checks in compress test Some of the tests can be run without zlib or bz2 extensions present. PHPBB3-11285 --- tests/compress/compress_test.php | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/tests/compress/compress_test.php b/tests/compress/compress_test.php index 65094671e3..ce193cf3ba 100644 --- a/tests/compress/compress_test.php +++ b/tests/compress/compress_test.php @@ -32,10 +32,16 @@ class phpbb_compress_test extends phpbb_test_case $phpbb_root_path = ''; $this->path = dirname(__FILE__) . '/fixtures/'; + } - if (!@extension_loaded('zlib') || !@extension_loaded('bz2')) + protected function check_extensions($extensions) + { + foreach ($extensions as $extension) { - $this->markTestSkipped('PHP needs to be compiled with --with-zlib and --with-bz2 in order to run these tests'); + if (!@extension_loaded($extension)) + { + $this->markTestSkipped("$extension extension is not loaded"); + } } } @@ -103,17 +109,18 @@ class phpbb_compress_test extends phpbb_test_case public function tar_archive_list() { return array( - array('archive.tar', '.tar'), - array('archive.tar.gz', '.tar.gz'), - array('archive.tar.bz2', '.tar.bz2'), + array('archive.tar', '.tar', array()), + array('archive.tar.gz', '.tar.gz', array('zlib')), + array('archive.tar.bz2', '.tar.bz2', array('bz2')), ); } /** * @dataProvider tar_archive_list */ - public function test_extract_tar($filename, $type) + public function test_extract_tar($filename, $type, $extensions) { + $this->check_extensions($extensions); $compress = new compress_tar('r', $this->path . $filename); $compress->extract('tests/compress/' . self::EXTRACT_DIR); $this->valid_extraction(); @@ -130,8 +137,10 @@ class phpbb_compress_test extends phpbb_test_case * @depends test_extract_tar * @dataProvider tar_archive_list */ - public function test_compress_tar($filename, $type) + public function test_compress_tar($filename, $type, $extensions) { + $this->check_extensions($extensions); + $tar = dirname(__FILE__) . self::ARCHIVE_DIR . $filename; $compress = new compress_tar('w', $tar); $this->archive_files($compress); @@ -149,6 +158,8 @@ class phpbb_compress_test extends phpbb_test_case */ public function test_compress_zip() { + $this->check_extensions(array('zlib')); + $zip = dirname(__FILE__) . self::ARCHIVE_DIR . 'archive.zip'; $compress = new compress_zip('w', $zip); $this->archive_files($compress); From 68ffb106fb2f9b246f52cf94f09c187531059f3e Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Fri, 21 Dec 2012 16:05:05 +0100 Subject: [PATCH 181/443] [ticket/11278] Comment out the code for dropping the Q&A tables Due to a bug, vanilla phpbb could not create captcha tables in 3.0.8 on firebird. It was possible for board administrators to adjust the code to work. If code was manually adjusted by board administrators, index names would not be the same as what 3.0.9 and newer expect. This code fragment drops captcha tables, destroying all entered Q&A captcha configuration, such that when Q&A is configured next the respective tables will be created with corrent index names. If you wish to preserve your Q&A captcha configuration, you can manually rename indexes to the currently expected name: phpbb_captcha_questions_lang_iso => phpbb_captcha_question_lang phpbb_captcha_answers_question_id => phpbb_captcha_answers_qid Again, this needs to be done only if a board was manually modified to fix broken captcha code. PHPBB3-11278 --- phpBB/install/database_update.php | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 0281aea0b3..8aa62af7e1 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -1017,7 +1017,7 @@ function database_update_info() *****************************************************************************/ function change_database_data(&$no_updates, $version) { - global $db, $db_tools, $errored, $error_ary, $config, $phpbb_root_path, $phpEx; + global $db, $db_tools, $errored, $error_ary, $config, $table_prefix, $phpbb_root_path, $phpEx; switch ($version) { @@ -1973,11 +1973,24 @@ function change_database_data(&$no_updates, $version) } $db->sql_freeresult($result); - global $table_prefix; - - // Recover from potentially broken Q&A CAPTCHA table on firebird - // Q&A CAPTCHA was uninstallable, so it's safe to remove these - // without data loss + /* + * Due to a bug, vanilla phpbb could not create captcha tables + * in 3.0.8 on firebird. It was possible for board administrators + * to adjust the code to work. If code was manually adjusted by + * board administrators, index names would not be the same as + * what 3.0.9 and newer expect. This code fragment drops captcha + * tables, destroying all entered Q&A captcha configuration, such + * that when Q&A is configured next the respective tables will be + * created with correct index names. + * + * If you wish to preserve your Q&A captcha configuration, you can + * manually rename indexes to the currently expected name: + * phpbb_captcha_questions_lang_iso => phpbb_captcha_questions_lang + * phpbb_captcha_answers_question_id => phpbb_captcha_answers_qid + * + * Again, this needs to be done only if a board was manually modified + * to fix broken captcha code. + * if ($db_tools->sql_layer == 'firebird') { $changes = array( @@ -1994,6 +2007,7 @@ function change_database_data(&$no_updates, $version) _sql($sql, $errored, $error_ary); } } + */ $no_updates = false; break; From 68710bb55a4ca39f31136c29369b49b8ee082c99 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 23 Dec 2012 19:57:30 +0100 Subject: [PATCH 182/443] [ticket/11291] phing: Make sure composer is available before calling it. Older versions of the tree didn't use it. PHPBB3-11291 --- build/build.xml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/build/build.xml b/build/build.xml index 28dd36bea8..cd7f8594d4 100644 --- a/build/build.xml +++ b/build/build.xml @@ -162,9 +162,18 @@ command="git archive ${revision} | tar -xf - -C ../${dir}" checkreturn="true" /> - + + + + + + + From c701de695f33d78e99517b9213eb06a95e57f9a0 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 23 Dec 2012 22:14:18 +0100 Subject: [PATCH 183/443] [develop-olympus] Set build version (and thus package name) to 3.0.12-dev. This is so generated packages are not confused with the already-released 3.0.11 version. --- build/build.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/build.xml b/build/build.xml index 28dd36bea8..d21ed99fd7 100644 --- a/build/build.xml +++ b/build/build.xml @@ -2,9 +2,9 @@ - - - + + + From 5056f162351420440bf989d0b1cfc6c325499f7a Mon Sep 17 00:00:00 2001 From: Martin Beckmann Date: Mon, 24 Dec 2012 03:53:54 +0100 Subject: [PATCH 184/443] [ticket/11292] Fix: Newlines removed in display of PM reports Report text is run through make_clickable and bbcode_nl2br for PMs just as it is for posts. PHPBB3-11292 --- phpBB/includes/mcp/mcp_pm_reports.php | 1 + 1 file changed, 1 insertion(+) diff --git a/phpBB/includes/mcp/mcp_pm_reports.php b/phpBB/includes/mcp/mcp_pm_reports.php index 72f77fae7c..77bc7680e6 100644 --- a/phpBB/includes/mcp/mcp_pm_reports.php +++ b/phpBB/includes/mcp/mcp_pm_reports.php @@ -123,6 +123,7 @@ class mcp_pm_reports $message = bbcode_nl2br($message); $message = smiley_text($message); + $report['report_text'] = make_clickable(bbcode_nl2br($report['report_text'])); if ($pm_info['message_attachment'] && $auth->acl_get('u_pm_download')) { From 989c4c3e6408e0d53b042161cfb34a0befe2570c Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 25 Dec 2012 00:11:34 -0500 Subject: [PATCH 185/443] [ticket/11293] Add a note that mysqli should be in front of mysql. php 5.5 alpha 2 deprecated mysql extension, prefer mysqli if both are available. PHPBB3-11293 --- phpBB/includes/functions_install.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phpBB/includes/functions_install.php b/phpBB/includes/functions_install.php index eae136808c..47f4eac627 100644 --- a/phpBB/includes/functions_install.php +++ b/phpBB/includes/functions_install.php @@ -55,6 +55,8 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'AVAILABLE' => true, '2.0.x' => false, ), + // Note: php 5.5 alpha 2 deprecated mysql. + // Keep mysqli before mysql in this list. 'mysqli' => array( 'LABEL' => 'MySQL with MySQLi Extension', 'SCHEMA' => 'mysql_41', From c0b3151f0d8c394ab1522332549132ffc4ca3d63 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 25 Dec 2012 07:15:58 -0500 Subject: [PATCH 186/443] [ticket/11294] Update required/optional extension list for olympus. PHPBB3-11294 --- tests/RUNNING_TESTS.txt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/RUNNING_TESTS.txt b/tests/RUNNING_TESTS.txt index 7c2a7c3fce..95c6b0a057 100644 --- a/tests/RUNNING_TESTS.txt +++ b/tests/RUNNING_TESTS.txt @@ -17,7 +17,24 @@ PHP extensions Unit tests use several PHP extensions that board code does not use. Currently the following PHP extensions must be installed and enabled to run unit tests: -- ctype +- ctype (also a phpunit dependency) +- dom (phpunit dependency) + +Some of the functionality in phpBB and/or the test suite uses additional +PHP extensions. If these extensions are not loaded, respective tests +will be skipped: + +- apc (APC cache driver) +- bz2 (compress tests) +- interbase, pdo_firebird (Firebird database driver) +- mysql, pdo_mysql (MySQL database driver) +- mysqli, pdo_mysql (MySQLi database driver) +- pdo (any database tests) +- pgsql, pdo_pgsql (PostgreSQL database driver) +- simplexml (any database tests) +- sqlite, pdo_sqlite (SQLite database driver, requires SQLite 2.x support + in pdo_sqlite) +- zlib (compress tests) Database Tests -------------- From 02a1777fcbc550b4d91aaa585cffa9c052e4c525 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 26 Dec 2012 00:30:20 -0500 Subject: [PATCH 187/443] [ticket/11295] Drop tables rather than database for postgres in test suite. Doing so allows: 1. User running the tests no longer needs create database privilege. 2. Test database may be located in a non-default tablespace and generally have site-specific options applied to it. PHPBB3-11295 --- ...phpbb_database_test_connection_manager.php | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index d7c2804aa7..3b8c2e99ae 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -186,6 +186,16 @@ class phpbb_database_test_connection_manager $this->purge_extras(); break; + case 'postgres': + $this->connect(); + // Drop all of the tables + foreach ($this->get_tables() as $table) + { + $this->pdo->exec('DROP TABLE ' . $table . ' CASCADE'); + } + $this->purge_extras(); + break; + default: $this->connect(false); @@ -293,7 +303,7 @@ class phpbb_database_test_connection_manager protected function load_schema_from_file($directory) { $schema = $this->dbms['SCHEMA']; - + if ($this->config['dbms'] == 'mysql') { $sth = $this->pdo->query('SELECT VERSION() AS version'); @@ -313,7 +323,7 @@ class phpbb_database_test_connection_manager $queries = file_get_contents($filename); $sql = phpbb_remove_comments($queries); - + $sql = split_sql_file($sql, $this->dbms['DELIM']); foreach ($sql as $query) @@ -419,6 +429,19 @@ class phpbb_database_test_connection_manager $queries[] = 'DROP SEQUENCE ' . current($row); } break; + + case 'postgres': + $sql = 'SELECT sequence_name + FROM information_schema.sequences'; + $result = $this->pdo->query($sql); + + while ($row = $result->fetch(PDO::FETCH_NUM)) + { + $queries[] = 'DROP SEQUENCE ' . current($row); + } + + $queries[] = 'DROP TYPE IF EXISTS varchar_ci CASCADE'; + break; } foreach ($queries as $query) From bc797c7da22ef1b0c68494d9a93eb23b981e2ebd Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 26 Dec 2012 10:41:13 -0500 Subject: [PATCH 188/443] [ticket/11294] Capitalize phpunit. PHPBB3-11294 --- tests/RUNNING_TESTS.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/RUNNING_TESTS.txt b/tests/RUNNING_TESTS.txt index 95c6b0a057..de9c751238 100644 --- a/tests/RUNNING_TESTS.txt +++ b/tests/RUNNING_TESTS.txt @@ -17,8 +17,8 @@ PHP extensions Unit tests use several PHP extensions that board code does not use. Currently the following PHP extensions must be installed and enabled to run unit tests: -- ctype (also a phpunit dependency) -- dom (phpunit dependency) +- ctype (also a PHPUnit dependency) +- dom (PHPUnit dependency) Some of the functionality in phpBB and/or the test suite uses additional PHP extensions. If these extensions are not loaded, respective tests @@ -61,7 +61,7 @@ to use in the environment as follows: $ PHPBB_TEST_CONFIG=tests/test_config.php phpunit Alternatively you can specify parameters in the environment, so e.g. the -following will run phpunit with the same parameters as in the shown +following will run PHPUnit with the same parameters as in the shown test_config.php file: $ PHPBB_TEST_DBMS='mysqli' PHPBB_TEST_DBHOST='localhost' \ From f6315dafb78b4164dd1a1be32d2dc3117616df30 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 29 Dec 2012 03:41:01 +0100 Subject: [PATCH 189/443] [ticket/11291] phing: Correct dependencies of composer target. This command runs composer in the phpBB tree and does not write to the build folders. Thus, it does not have to depend on prepare and clean targets. PHPBB3-11291 --- build/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index cd7f8594d4..f77635b586 100644 --- a/build/build.xml +++ b/build/build.xml @@ -43,7 +43,7 @@ - + From c9cc5a00dcbf8e10daf350591044df1a2aca3a05 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 29 Dec 2012 03:43:04 +0100 Subject: [PATCH 190/443] [ticket/11291] phing: Add --dev to composer install. The composer target runs composer in the phpBB tree in order to load dependencies for testing. The testing framework may have additional development dependencies (e.g. goutte). We also have to load those. PHPBB3-11291 --- build/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index f77635b586..bc83cc0953 100644 --- a/build/build.xml +++ b/build/build.xml @@ -45,7 +45,7 @@ From e775e7fc91817cb353251d2406dea810565ffb18 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 29 Dec 2012 03:50:18 +0100 Subject: [PATCH 191/443] [ticket/11291] phing: Add description for composer target. PHPBB3-11291 --- build/build.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build/build.xml b/build/build.xml index bc83cc0953..56179bbbe2 100644 --- a/build/build.xml +++ b/build/build.xml @@ -43,6 +43,11 @@ + Date: Sat, 29 Dec 2012 03:51:41 +0100 Subject: [PATCH 192/443] [ticket/11291] phing: Adjust directory format of composer exec. Adjust the directory format to what all the other exec calls are using. PHPBB3-11291 --- build/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index 56179bbbe2..8807f77379 100644 --- a/build/build.xml +++ b/build/build.xml @@ -49,7 +49,7 @@ loaded because testing framework may depend on them. --> - From 316bfc20c0ff388bf399657af59171e73d7e8cd1 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 29 Dec 2012 03:55:20 +0100 Subject: [PATCH 193/443] [ticket/11291] phing: The package target does not depend on composer. The packaging process does not require running composer in the phpBB tree. It does however require running composer on the git exports, but this is not what the composer target does. PHPBB3-11291 --- build/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index 8807f77379..0cddf613f8 100644 --- a/build/build.xml +++ b/build/build.xml @@ -11,7 +11,7 @@ - + From 370e3c31e86406eef2b5b292782f05fd1bf6c659 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 29 Dec 2012 03:59:55 +0100 Subject: [PATCH 194/443] [ticket/11291] phing: Remove no longer needed create-package target. PHPBB3-11291 --- build/build.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/build/build.xml b/build/build.xml index 0cddf613f8..ae36413d2f 100644 --- a/build/build.xml +++ b/build/build.xml @@ -11,8 +11,7 @@ - - + @@ -127,7 +126,7 @@ - + From 46a752ee628fc4b08f2d5e26b159dca41b816277 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 29 Dec 2012 04:38:16 +0100 Subject: [PATCH 195/443] [ticket/11291] phing packaging: Export composer.phar and install dependencies. PHPBB3-11291 --- build/build.xml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/build/build.xml b/build/build.xml index ae36413d2f..393343d677 100644 --- a/build/build.xml +++ b/build/build.xml @@ -167,15 +167,21 @@ checkreturn="true" /> + - + + + From 1fc103e3f322991e1f1877146219b0efeca3f458 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 29 Dec 2012 04:53:33 +0100 Subject: [PATCH 196/443] [ticket/11291] phing: Exclude vendor folder from diffs. Otherwise we end up with very huge diffs and the build process is severely slowed down. PHPBB3-11291 --- build/build.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/build/build.xml b/build/build.xml index 393343d677..df65967e2a 100644 --- a/build/build.xml +++ b/build/build.xml @@ -206,6 +206,7 @@ + From b36050983d34de0ecdb242816d5d9daf297cfea1 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 29 Dec 2012 13:30:25 +0100 Subject: [PATCH 197/443] [ticket/11291] phing: Add checkreturn="true" to all new commands. PHPBB3-11291 --- build/build.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index df65967e2a..25bed7de0c 100644 --- a/build/build.xml +++ b/build/build.xml @@ -172,14 +172,17 @@ --> + command="git archive ${revision} composer.phar | tar -xf - -C ${dir}" + checkreturn="true" /> From 6951356a87564511595be85f45b9ff88ab495bd0 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 29 Dec 2012 13:38:40 +0100 Subject: [PATCH 198/443] [ticket/11291] phing: Also add checkreturn="true" to composer execution. PHPBB3-11291 --- build/build.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/build/build.xml b/build/build.xml index 25bed7de0c..9576407296 100644 --- a/build/build.xml +++ b/build/build.xml @@ -50,6 +50,7 @@ From 24befac7b4879ae02a4416e47ca0deea93766b93 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Tue, 8 Jan 2013 23:18:17 +0100 Subject: [PATCH 199/443] [ticket/11301] Explicitly cast str offset to int to prevent E_NOTICE on 5.4. PHPBB3-11301 --- phpBB/includes/captcha/captcha_non_gd.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/captcha/captcha_non_gd.php b/phpBB/includes/captcha/captcha_non_gd.php index f82896f628..a823fa4226 100644 --- a/phpBB/includes/captcha/captcha_non_gd.php +++ b/phpBB/includes/captcha/captcha_non_gd.php @@ -119,7 +119,7 @@ class captcha $new_line = ''; $end = strlen($scanline) - ceil($width/2); - for ($i = floor($width/2); $i < $end; $i++) + for ($i = (int) floor($width/2); $i < $end; $i++) { $pixel = ord($scanline{$i}); From 41a07eedeb13349305977bb8882f0bd6429480e3 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Tue, 8 Jan 2013 23:20:30 +0100 Subject: [PATCH 200/443] [ticket/11301] Guidelines: Add spaces in front and after the / operator. PHPBB3-11301 --- phpBB/includes/captcha/captcha_non_gd.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/captcha/captcha_non_gd.php b/phpBB/includes/captcha/captcha_non_gd.php index a823fa4226..2adf909b96 100644 --- a/phpBB/includes/captcha/captcha_non_gd.php +++ b/phpBB/includes/captcha/captcha_non_gd.php @@ -119,7 +119,7 @@ class captcha $new_line = ''; $end = strlen($scanline) - ceil($width/2); - for ($i = (int) floor($width/2); $i < $end; $i++) + for ($i = (int) floor($width / 2); $i < $end; $i++) { $pixel = ord($scanline{$i}); From 4001410c8c80ac9c531343af28310e97b4bbf1fe Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 13 Jan 2013 23:40:07 +0100 Subject: [PATCH 201/443] [ticket/11324] Add PHP 5.5 environment to travis and allow it to fail. PHPBB3-11324 --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 94e7086c1e..ba8c1b4a91 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,11 +4,16 @@ php: - 5.3.3 - 5.3 - 5.4 + - 5.5 env: - DB=mysql - DB=postgres +matrix: + allow_failures: + - php: 5.5 + before_script: - sh -c "if [ '$DB' = 'postgres' ]; then psql -c 'DROP DATABASE IF EXISTS phpbb_tests;' -U postgres; fi" - sh -c "if [ '$DB' = 'postgres' ]; then psql -c 'create database phpbb_tests;' -U postgres; fi" From 90235754b3919eafcb47047a8aac0fa0f075087e Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 13 Jan 2013 18:28:51 -0500 Subject: [PATCH 202/443] [ticket/11323] Backport include_define test to olympus. PHPBB3-11323 --- tests/template/template_test.php | 7 +++++++ tests/template/templates/include_define.html | 2 ++ 2 files changed, 9 insertions(+) create mode 100644 tests/template/templates/include_define.html diff --git a/tests/template/template_test.php b/tests/template/template_test.php index 9b3c6ac245..83af63cdd9 100644 --- a/tests/template/template_test.php +++ b/tests/template/template_test.php @@ -232,6 +232,13 @@ class phpbb_template_template_test extends phpbb_test_case array(), 'value', ), + array( + 'include_define.html', + array('VARIABLE' => 'value'), + array(), + array(), + 'value', + ), array( 'loop_vars.html', array(), diff --git a/tests/template/templates/include_define.html b/tests/template/templates/include_define.html new file mode 100644 index 0000000000..2419c8cba1 --- /dev/null +++ b/tests/template/templates/include_define.html @@ -0,0 +1,2 @@ + + From 4c50a35b62a46de69b439f9ac8007721d76881b0 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Mon, 14 Jan 2013 01:14:29 +0100 Subject: [PATCH 203/443] [ticket/11323] Add tests for inclusion of defined variables This adds 2 tests for the template engine. The test using include_define_variable.html will test if a defined variable, which was defined with another template variable, can be used to include a file. The second test will do the same inside a loop using a loop variable. PHPBB3-11323 --- tests/template/template_test.php | 17 ++++++++++++++++- .../templates/include_define_variable.html | 2 ++ .../template/templates/include_loop_define.html | 4 ++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 tests/template/templates/include_define_variable.html create mode 100644 tests/template/templates/include_loop_define.html diff --git a/tests/template/template_test.php b/tests/template/template_test.php index 9b3c6ac245..291b424bdd 100644 --- a/tests/template/template_test.php +++ b/tests/template/template_test.php @@ -238,7 +238,22 @@ class phpbb_template_template_test extends phpbb_test_case array('loop' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'loop.inner' => array(array(), array())), array('loop'), '', - ),/* no top level nested loops + ), + array( + 'include_define_variable.html', + array('VARIABLE' => 'variable.html'), + array(), + array(), + 'variable.html', + ), + array( + 'include_loop_define.html', + array('VARIABLE' => 'value'), + array('loop' => array(array('NESTED_FILE' => 'variable.html'))), + array(), + 'value', + ), + /* no top level nested loops array( 'loop_vars.html', array(), diff --git a/tests/template/templates/include_define_variable.html b/tests/template/templates/include_define_variable.html new file mode 100644 index 0000000000..aff9b574c2 --- /dev/null +++ b/tests/template/templates/include_define_variable.html @@ -0,0 +1,2 @@ + + diff --git a/tests/template/templates/include_loop_define.html b/tests/template/templates/include_loop_define.html new file mode 100644 index 0000000000..f539b21396 --- /dev/null +++ b/tests/template/templates/include_loop_define.html @@ -0,0 +1,4 @@ + + + + From 317964174e9a70972d4c783feb318cb138e2bd57 Mon Sep 17 00:00:00 2001 From: Senky Date: Sat, 19 Jan 2013 12:31:53 +0100 Subject: [PATCH 204/443] [ticket/10050] adding .topicrow to template condition PHPBB3-10050 --- phpBB/styles/prosilver/template/viewforum_body.html | 2 +- phpBB/styles/subsilver2/template/viewforum_body.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/phpBB/styles/prosilver/template/viewforum_body.html b/phpBB/styles/prosilver/template/viewforum_body.html index 02f42fa097..4b9c514932 100644 --- a/phpBB/styles/prosilver/template/viewforum_body.html +++ b/phpBB/styles/prosilver/template/viewforum_body.html @@ -57,7 +57,7 @@