mirror of
https://github.com/phpbb/phpbb.git
synced 2025-09-17 03:22:07 +02:00
Compare commits
154 Commits
release-3.
...
release-3.
Author | SHA1 | Date | |
---|---|---|---|
|
2973c2f6db | ||
|
57ef18ecc0 | ||
|
e9e305ee9f | ||
|
1d256fef61 | ||
|
599073cab2 | ||
|
b7ffee0945 | ||
|
56c1b9b5bd | ||
|
18c00a902f | ||
|
8497104bdb | ||
|
4038bb9dc3 | ||
|
935c1a3ea2 | ||
|
6eb49d0907 | ||
|
7fe0cc7f26 | ||
|
28cf33eb2f | ||
|
cf47bed67e | ||
|
1e28669407 | ||
|
58cc1f4ef3 | ||
|
45d64a1627 | ||
|
10f92dbb68 | ||
|
bc7bd15312 | ||
|
5c40766dc4 | ||
|
661140c50b | ||
|
294c517256 | ||
|
de660fe0c8 | ||
|
e602889213 | ||
|
f4b1444248 | ||
|
13e6cd5992 | ||
|
dd9267b678 | ||
|
f646fcdefa | ||
|
99c97b951f | ||
|
f41c8eef47 | ||
|
17b4838ee3 | ||
|
a0092bdd18 | ||
|
c0b81a1a48 | ||
|
89afa0cb5e | ||
|
a62a303318 | ||
|
cacd9375fd | ||
|
7763969625 | ||
|
a2e7205154 | ||
|
350c9213ee | ||
|
7365764476 | ||
|
dd4c982792 | ||
|
2088ee5e84 | ||
|
926a0a4e33 | ||
|
30144052da | ||
|
8298095421 | ||
|
55dbe070e3 | ||
|
8639be4bd4 | ||
|
ffc655a1ba | ||
|
922e7699ed | ||
|
c790e81fb6 | ||
|
42851d0d9f | ||
|
00d1351e55 | ||
|
48a233e415 | ||
|
6798c337f8 | ||
|
99b745982e | ||
|
bde7b119b2 | ||
|
5013075af7 | ||
|
40881b537e | ||
|
efece4136b | ||
|
38177e9052 | ||
|
a4296a9e6b | ||
|
d7477760d6 | ||
|
294b3ff922 | ||
|
ad77f0d0ab | ||
|
5a9c01716f | ||
|
5b03cd422a | ||
|
e5d2e82ef5 | ||
|
8eacbf8305 | ||
|
5976dc2141 | ||
|
3647cf2cfe | ||
|
dd3ebe2b71 | ||
|
f3460fe9eb | ||
|
15960a7918 | ||
|
fa893f092b | ||
|
99b07b884b | ||
|
7f9bcc2743 | ||
|
d875eaa405 | ||
|
db40145fd5 | ||
|
8c77da9c30 | ||
|
09f0b417be | ||
|
8432e506c4 | ||
|
77d1010081 | ||
|
4003f54d0b | ||
|
abaef09a14 | ||
|
127121f1d2 | ||
|
e53cd79067 | ||
|
8bdff227d9 | ||
|
df7dae9600 | ||
|
e21a8e02cd | ||
|
db9874546b | ||
|
e125f1f709 | ||
|
9e15802805 | ||
|
f98f2c5896 | ||
|
c2d91650bd | ||
|
51b773e588 | ||
|
ef4db99709 | ||
|
cd0e682984 | ||
|
431b399c68 | ||
|
56d8a7e43f | ||
|
2976314205 | ||
|
be6bb09984 | ||
|
8a8232109c | ||
|
f3ead808f3 | ||
|
276502ce58 | ||
|
8899fcfdc2 | ||
|
2aba9b0e3f | ||
|
80a12f7108 | ||
|
6cef48af2f | ||
|
607fe555af | ||
|
166c4eeb7e | ||
|
bf55502c62 | ||
|
df5fcafcb9 | ||
|
1fb7e6d2c8 | ||
|
1c1c981b17 | ||
|
7c661746cf | ||
|
24dd47adcf | ||
|
f853f6523f | ||
|
a63a1913fa | ||
|
ef593afec5 | ||
|
51da43f77f | ||
|
e328ee96d2 | ||
|
7f11c1b46d | ||
|
ae18669fcd | ||
|
9ea4aabe9a | ||
|
a88040df85 | ||
|
fcf89208cf | ||
|
d365f17ebd | ||
|
6f345e43cb | ||
|
874fb7bf8a | ||
|
558b8ae7ed | ||
|
477f5d9e1d | ||
|
92e545fc26 | ||
|
c330500c4d | ||
|
9fcf956888 | ||
|
40ed6c6458 | ||
|
cd34cdedee | ||
|
e850915190 | ||
|
d14f98f672 | ||
|
130c10915e | ||
|
9ecf09dbe8 | ||
|
8954a68953 | ||
|
f986138467 | ||
|
611faafaf3 | ||
|
ed0b5020a9 | ||
|
b2d2216b87 | ||
|
766ecaed5a | ||
|
a7a53de34d | ||
|
6aa980eadb | ||
|
dbf0b9ebe6 | ||
|
874fb8c59c | ||
|
e195e2ad82 | ||
|
9aebbcc1a0 | ||
|
de31c4e797 |
@@ -30,7 +30,7 @@ installer:
|
||||
server:
|
||||
cookie_secure: false
|
||||
server_protocol: http://
|
||||
force_server_vars: false
|
||||
force_server_vars: true
|
||||
server_name: localhost
|
||||
server_port: 80
|
||||
script_path: /
|
||||
|
@@ -34,6 +34,14 @@ sudo ln -s /workspaces/phpbb/phpBB /var/www/html
|
||||
echo "[Codespaces] Copy phpBB configuration"
|
||||
cp /workspaces/phpbb/.devcontainer/resources/phpbb-config.yml /workspaces/phpbb/phpBB/install/install-config.yml
|
||||
|
||||
# Force the server URL to reflect the Codespace
|
||||
# https://docs.github.com/en/codespaces/developing-in-a-codespace/default-environment-variables-for-your-codespace
|
||||
if [ "$CODESPACES" = true ] ; then
|
||||
echo "[Codespaces] Set the phpBB server name using default environment variables"
|
||||
codespaces_url="${CODESPACE_NAME}-80.${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}"
|
||||
sed -i "s/localhost/$codespaces_url/g" /workspaces/phpbb/phpBB/install/install-config.yml
|
||||
fi
|
||||
|
||||
# Install phpBB
|
||||
echo "[Codespaces] Run phpBB CLI installation"
|
||||
cd /workspaces/phpbb/phpBB && composer install --no-interaction
|
||||
|
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -7,4 +7,4 @@ Checklist:
|
||||
|
||||
Tracker ticket:
|
||||
|
||||
https://tracker.phpbb.com/browse/PHPBB3-12345
|
||||
https://tracker.phpbb.com/browse/PHPBB-12345
|
||||
|
10
.github/workflows/tests.yml
vendored
10
.github/workflows/tests.yml
vendored
@@ -128,6 +128,8 @@ jobs:
|
||||
db: "mysql:5.7"
|
||||
- php: '8.3'
|
||||
db: "mysql:5.7"
|
||||
- php: '8.4'
|
||||
db: "mysql:5.7"
|
||||
|
||||
name: PHP ${{ matrix.php }} - ${{ matrix.db_alias != '' && matrix.db_alias || matrix.db }}
|
||||
|
||||
@@ -261,6 +263,8 @@ jobs:
|
||||
db: "postgres:14"
|
||||
- php: '8.3'
|
||||
db: "postgres:14"
|
||||
- php: '8.4'
|
||||
db: "postgres:14"
|
||||
|
||||
name: PHP ${{ matrix.php }} - ${{ matrix.db }}
|
||||
|
||||
@@ -469,6 +473,9 @@ jobs:
|
||||
- php: '8.3'
|
||||
db: "postgres"
|
||||
type: 'unit'
|
||||
- php: '8.4'
|
||||
db: "postgres"
|
||||
type: 'unit'
|
||||
- php: '7.4'
|
||||
db: "postgres"
|
||||
type: 'functional'
|
||||
@@ -484,6 +491,9 @@ jobs:
|
||||
- php: '8.3'
|
||||
db: "postgres"
|
||||
type: 'functional'
|
||||
- php: '8.4'
|
||||
db: "postgres"
|
||||
type: 'functional'
|
||||
|
||||
name: Windows - PHP ${{ matrix.php }} - ${{ matrix.db }} - ${{ matrix.type }}
|
||||
|
||||
|
@@ -2,9 +2,9 @@
|
||||
|
||||
<project name="phpBB" description="The phpBB forum software" default="all" basedir="../">
|
||||
<!-- a few settings for the build -->
|
||||
<property name="newversion" value="3.3.12-RC1" />
|
||||
<property name="prevversion" value="3.3.11" />
|
||||
<property name="olderversions" value="3.1.0, 3.1.1, 3.1.2, 3.1.3, 3.1.4, 3.1.5, 3.1.6, 3.1.7, 3.1.7-pl1, 3.1.8, 3.1.9, 3.1.10, 3.1.11, 3.1.12, 3.2.0, 3.2.1, 3.2.2, 3.2.3, 3.2.4, 3.2.5, 3.2.6, 3.2.7, 3.2.8, 3.2.9, 3.2.10, 3.2.11, 3.3.0, 3.3.1, 3.3.2, 3.3.3, 3.3.4, 3.3.5, 3.3.6, 3.3.7, 3.3.8, 3.3.9, 3.3.10" />
|
||||
<property name="newversion" value="3.3.13-RC1" />
|
||||
<property name="prevversion" value="3.3.12" />
|
||||
<property name="olderversions" value="3.1.0, 3.1.1, 3.1.2, 3.1.3, 3.1.4, 3.1.5, 3.1.6, 3.1.7, 3.1.7-pl1, 3.1.8, 3.1.9, 3.1.10, 3.1.11, 3.1.12, 3.2.0, 3.2.1, 3.2.2, 3.2.3, 3.2.4, 3.2.5, 3.2.6, 3.2.7, 3.2.8, 3.2.9, 3.2.10, 3.2.11, 3.3.0, 3.3.1, 3.3.2, 3.3.3, 3.3.4, 3.3.5, 3.3.6, 3.3.7, 3.3.8, 3.3.9, 3.3.10, 3.3.11" />
|
||||
<!-- no configuration should be needed beyond this point -->
|
||||
|
||||
<property name="oldversions" value="${olderversions}, ${prevversion}" />
|
||||
@@ -181,6 +181,7 @@
|
||||
|
||||
<!-- create an empty config.php file (not for diffs) -->
|
||||
<touch file="build/new_version/phpBB3/config.php" />
|
||||
<copy file="build/new_version/phpBB3/phpbb/.htaccess" tofile="build/new_version/phpBB3/vendor/.htaccess" />
|
||||
|
||||
</target>
|
||||
|
||||
|
BIN
composer.phar
BIN
composer.phar
Binary file not shown.
@@ -224,7 +224,7 @@ do
|
||||
"footer")
|
||||
err=$ERR_FOOTER;
|
||||
# Each ticket is on its own line
|
||||
echo "$line" | grep -Eq "^PHPBB3-[0-9]+$";
|
||||
echo "$line" | grep -Eq "^PHPBB3?-[0-9]+$";
|
||||
;;
|
||||
"eof")
|
||||
err=$ERR_EOF;
|
||||
@@ -356,7 +356,7 @@ echo "$expecting" | grep -q "eof" || (
|
||||
# Check the branch ticket is mentioned, doesn't make sense otherwise
|
||||
if [ $ticket -gt 0 ]
|
||||
then
|
||||
echo "$tickets" | grep -Eq "\bPHPBB3-$ticket\b" || (
|
||||
echo "$tickets" | grep -Eq "\bPHPBB3?-$ticket\b" || (
|
||||
complain "Ticket ID [$ticket] of branch missing from list of tickets:" >&2;
|
||||
complain "$tickets" | sed 's/ /\n/g;s/^/* /g' >&2;
|
||||
quit $ERR_FOOTER;
|
||||
|
@@ -47,7 +47,7 @@ then
|
||||
# Branch is prefixed with 'ticket/', append ticket ID to message
|
||||
if [ "$branch" != "${branch##ticket/}" ];
|
||||
then
|
||||
tail="$(printf '\n\nPHPBB3-%s' "$ticket_id")";
|
||||
tail="$(printf '\n\nPHPBB-%s' "$ticket_id")";
|
||||
fi
|
||||
fi
|
||||
|
||||
|
@@ -225,6 +225,7 @@
|
||||
|
||||
<fieldset>
|
||||
<legend>{L_ADD_USERS}</legend>
|
||||
{% EVENT acp_groups_add_user_options_before %}
|
||||
<dl>
|
||||
<dt><label for="leader">{L_USER_GROUP_LEADER}{L_COLON}</label></dt>
|
||||
<dd><label><input name="leader" type="radio" class="radio" value="1" /> {L_YES}</label>
|
||||
@@ -235,11 +236,13 @@
|
||||
<dd><label><input name="default" type="radio" class="radio" value="1" /> {L_YES}</label>
|
||||
<label><input name="default" type="radio" class="radio" id="default" value="0" checked="checked" /> {L_NO}</label></dd>
|
||||
</dl>
|
||||
{% EVENT acp_groups_add_user_usernames_before %}
|
||||
<dl>
|
||||
<dt><label for="usernames">{L_USERNAME}{L_COLON}</label><br /><span>{L_USERNAMES_EXPLAIN}</span></dt>
|
||||
<dd><textarea id="usernames" name="usernames" cols="40" rows="5"></textarea></dd>
|
||||
<dd><!-- EVENT acp_groups_find_username_prepend -->[ <a href="{U_FIND_USERNAME}" onclick="find_username(this.href); return false;">{L_FIND_USERNAME}</a> ]<!-- EVENT acp_groups_find_username_append --></dd>
|
||||
</dl>
|
||||
{% EVENT acp_groups_add_user_options_after %}
|
||||
|
||||
<p class="quick">
|
||||
<input class="button2" type="submit" name="addusers" value="{L_SUBMIT}" />
|
||||
|
@@ -14,27 +14,31 @@
|
||||
|
||||
<p>{L_ADMIN_INTRO}</p>
|
||||
|
||||
<!-- IF S_UPDATE_INCOMPLETE -->
|
||||
{% if S_UPDATE_INCOMPLETE %}
|
||||
<div class="errorbox">
|
||||
<p>{L_UPDATE_INCOMPLETE} <a href="{U_VERSIONCHECK}">{L_MORE_INFORMATION}</a></p>
|
||||
<p>{{ lang('UPDATE_INCOMPLETE') }} <a href="{{ U_VERSIONCHECK }}">{{ lang('MORE_INFORMATION') }}</a></p>
|
||||
</div>
|
||||
<!-- ELSEIF S_VERSIONCHECK_FAIL -->
|
||||
{% elseif S_VERSIONCHECK_FAIL %}
|
||||
<div class="errorbox notice">
|
||||
<p>{L_VERSIONCHECK_FAIL}</p>
|
||||
<p>{VERSIONCHECK_FAIL_REASON}</p>
|
||||
<p><a href="{U_VERSIONCHECK_FORCE}">{L_VERSIONCHECK_FORCE_UPDATE}</a> · <a href="{U_VERSIONCHECK}">{L_MORE_INFORMATION}</a></p>
|
||||
<p>{{ lang('VERSIONCHECK_FAIL') }}</p>
|
||||
<p>{{ VERSIONCHECK_FAIL_REASON }}</p>
|
||||
<p><a href="{{ U_VERSIONCHECK_FORCE }}">{{ lang('VERSIONCHECK_FORCE_UPDATE') }}</a> · <a href="{{ U_VERSIONCHECK }}">{{ lang('MORE_INFORMATION') }}</a></p>
|
||||
</div>
|
||||
<!-- ELSEIF not S_VERSION_UP_TO_DATE -->
|
||||
{% elseif not S_VERSION_UP_TO_DATE %}
|
||||
<div class="errorbox">
|
||||
<p>{L_VERSION_NOT_UP_TO_DATE_TITLE}</p>
|
||||
<p><a href="{U_VERSIONCHECK_FORCE}">{L_VERSIONCHECK_FORCE_UPDATE}</a> · <a href="{U_VERSIONCHECK}">{L_MORE_INFORMATION}</a></p>
|
||||
<p>{{ lang('VERSION_NOT_UP_TO_DATE_TITLE') }}</p>
|
||||
<p><a href="{{ U_VERSIONCHECK_FORCE }}">{{ lang('VERSIONCHECK_FORCE_UPDATE') }}</a> · <a href="{{ U_VERSIONCHECK }}">{{ lang('MORE_INFORMATION') }}</a></p>
|
||||
</div>
|
||||
<!-- ENDIF -->
|
||||
<!-- IF S_VERSION_UPGRADEABLE -->
|
||||
{% elseif S_VERSION_UP_TO_DATE && S_VERSIONCHECK_FORCE %}
|
||||
<div class="successbox">
|
||||
<p>{{ lang('VERSION_UP_TO_DATE_ACP') }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if S_VERSION_UPGRADEABLE %}
|
||||
<div class="errorbox notice">
|
||||
<p>{UPGRADE_INSTRUCTIONS}</p>
|
||||
<p>{{ UPGRADE_INSTRUCTIONS }}</p>
|
||||
</div>
|
||||
<!-- ENDIF -->
|
||||
{% endif %}
|
||||
|
||||
<!-- IF S_SEARCH_INDEX_MISSING -->
|
||||
<div class="errorbox">
|
||||
|
176
phpBB/composer.lock
generated
176
phpBB/composer.lock
generated
@@ -3027,16 +3027,16 @@
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.11.1",
|
||||
"version": "1.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
|
||||
"reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
|
||||
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
|
||||
"reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3044,11 +3044,12 @@
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/collections": "<1.6.8",
|
||||
"doctrine/common": "<2.13.3 || >=3,<3.2.2"
|
||||
"doctrine/common": "<2.13.3 || >=3 <3.2.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/collections": "^1.6.8",
|
||||
"doctrine/common": "^2.13.3 || ^3.2.2",
|
||||
"phpspec/prophecy": "^1.10",
|
||||
"phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
|
||||
},
|
||||
"type": "library",
|
||||
@@ -3074,7 +3075,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3082,7 +3083,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-03-08T13:26:56+00:00"
|
||||
"time": "2024-06-12T14:39:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/manifest",
|
||||
@@ -3533,24 +3534,24 @@
|
||||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
"version": "v1.18.0",
|
||||
"version": "v1.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/prophecy.git",
|
||||
"reference": "d4f454f7e1193933f04e6500de3e79191648ed0c"
|
||||
"reference": "67a759e7d8746d501c41536ba40cd9c0a07d6a87"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/d4f454f7e1193933f04e6500de3e79191648ed0c",
|
||||
"reference": "d4f454f7e1193933f04e6500de3e79191648ed0c",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/67a759e7d8746d501c41536ba40cd9c0a07d6a87",
|
||||
"reference": "67a759e7d8746d501c41536ba40cd9c0a07d6a87",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/instantiator": "^1.2 || ^2.0",
|
||||
"php": "^7.2 || 8.0.* || 8.1.* || 8.2.* || 8.3.*",
|
||||
"phpdocumentor/reflection-docblock": "^5.2",
|
||||
"sebastian/comparator": "^3.0 || ^4.0 || ^5.0",
|
||||
"sebastian/recursion-context": "^3.0 || ^4.0 || ^5.0"
|
||||
"sebastian/comparator": "^3.0 || ^4.0 || ^5.0 || ^6.0",
|
||||
"sebastian/recursion-context": "^3.0 || ^4.0 || ^5.0 || ^6.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpspec/phpspec": "^6.0 || ^7.0",
|
||||
@@ -3596,9 +3597,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpspec/prophecy/issues",
|
||||
"source": "https://github.com/phpspec/prophecy/tree/v1.18.0"
|
||||
"source": "https://github.com/phpspec/prophecy/tree/v1.19.0"
|
||||
},
|
||||
"time": "2023-12-07T16:22:33+00:00"
|
||||
"time": "2024-02-29T11:52:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/dbunit",
|
||||
@@ -3726,16 +3727,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
"version": "2.0.5",
|
||||
"version": "2.0.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
||||
"reference": "42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5"
|
||||
"reference": "69deeb8664f611f156a924154985fbd4911eb36b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5",
|
||||
"reference": "42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/69deeb8664f611f156a924154985fbd4911eb36b",
|
||||
"reference": "69deeb8664f611f156a924154985fbd4911eb36b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3774,7 +3775,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
|
||||
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/2.0.5"
|
||||
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/2.0.6"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3782,7 +3783,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-12-02T12:42:26+00:00"
|
||||
"time": "2024-03-01T13:39:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-text-template",
|
||||
@@ -3831,16 +3832,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-timer",
|
||||
"version": "2.1.3",
|
||||
"version": "2.1.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-timer.git",
|
||||
"reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662"
|
||||
"reference": "a691211e94ff39a34811abd521c31bd5b305b0bb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/2454ae1765516d20c4ffe103d85a58a9a3bd5662",
|
||||
"reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/a691211e94ff39a34811abd521c31bd5b305b0bb",
|
||||
"reference": "a691211e94ff39a34811abd521c31bd5b305b0bb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3878,7 +3879,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-timer/issues",
|
||||
"source": "https://github.com/sebastianbergmann/php-timer/tree/2.1.3"
|
||||
"source": "https://github.com/sebastianbergmann/php-timer/tree/2.1.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3886,7 +3887,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-30T08:20:02+00:00"
|
||||
"time": "2024-03-01T13:42:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-token-stream",
|
||||
@@ -4038,16 +4039,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/code-unit-reverse-lookup",
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
|
||||
"reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619"
|
||||
"reference": "92a1a52e86d34cde6caa54f1b5ffa9fda18e5d54"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619",
|
||||
"reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/92a1a52e86d34cde6caa54f1b5ffa9fda18e5d54",
|
||||
"reference": "92a1a52e86d34cde6caa54f1b5ffa9fda18e5d54",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4081,7 +4082,7 @@
|
||||
"homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
|
||||
"source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2"
|
||||
"source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4089,7 +4090,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-30T08:15:22+00:00"
|
||||
"time": "2024-03-01T13:45:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/comparator",
|
||||
@@ -4167,16 +4168,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
"version": "3.0.4",
|
||||
"version": "3.0.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/diff.git",
|
||||
"reference": "6296a0c086dd0117c1b78b059374d7fcbe7545ae"
|
||||
"reference": "98ff311ca519c3aa73ccd3de053bdb377171d7b6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/6296a0c086dd0117c1b78b059374d7fcbe7545ae",
|
||||
"reference": "6296a0c086dd0117c1b78b059374d7fcbe7545ae",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/98ff311ca519c3aa73ccd3de053bdb377171d7b6",
|
||||
"reference": "98ff311ca519c3aa73ccd3de053bdb377171d7b6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4221,7 +4222,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/diff/issues",
|
||||
"source": "https://github.com/sebastianbergmann/diff/tree/3.0.4"
|
||||
"source": "https://github.com/sebastianbergmann/diff/tree/3.0.6"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4229,20 +4230,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-05-07T05:30:20+00:00"
|
||||
"time": "2024-03-02T06:16:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
"version": "4.2.4",
|
||||
"version": "4.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/environment.git",
|
||||
"reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0"
|
||||
"reference": "56932f6049a0482853056ffd617c91ffcc754205"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/d47bbbad83711771f167c72d4e3f25f7fcc1f8b0",
|
||||
"reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/56932f6049a0482853056ffd617c91ffcc754205",
|
||||
"reference": "56932f6049a0482853056ffd617c91ffcc754205",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4284,7 +4285,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/environment/issues",
|
||||
"source": "https://github.com/sebastianbergmann/environment/tree/4.2.4"
|
||||
"source": "https://github.com/sebastianbergmann/environment/tree/4.2.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4292,24 +4293,24 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-30T07:53:42+00:00"
|
||||
"time": "2024-03-01T13:49:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
"version": "3.1.5",
|
||||
"version": "3.1.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/exporter.git",
|
||||
"reference": "73a9676f2833b9a7c36968f9d882589cd75511e6"
|
||||
"reference": "1939bc8fd1d39adcfa88c5b35335910869214c56"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/73a9676f2833b9a7c36968f9d882589cd75511e6",
|
||||
"reference": "73a9676f2833b9a7c36968f9d882589cd75511e6",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/1939bc8fd1d39adcfa88c5b35335910869214c56",
|
||||
"reference": "1939bc8fd1d39adcfa88c5b35335910869214c56",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.0",
|
||||
"php": ">=7.2",
|
||||
"sebastian/recursion-context": "^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
@@ -4361,7 +4362,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/exporter/issues",
|
||||
"source": "https://github.com/sebastianbergmann/exporter/tree/3.1.5"
|
||||
"source": "https://github.com/sebastianbergmann/exporter/tree/3.1.6"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4369,7 +4370,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-09-14T06:00:17+00:00"
|
||||
"time": "2024-03-02T06:21:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/global-state",
|
||||
@@ -4428,16 +4429,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/object-enumerator",
|
||||
"version": "3.0.4",
|
||||
"version": "3.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/object-enumerator.git",
|
||||
"reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2"
|
||||
"reference": "ac5b293dba925751b808e02923399fb44ff0d541"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2",
|
||||
"reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/ac5b293dba925751b808e02923399fb44ff0d541",
|
||||
"reference": "ac5b293dba925751b808e02923399fb44ff0d541",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4473,7 +4474,7 @@
|
||||
"homepage": "https://github.com/sebastianbergmann/object-enumerator/",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
|
||||
"source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0.4"
|
||||
"source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4481,20 +4482,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-30T07:40:27+00:00"
|
||||
"time": "2024-03-01T13:54:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/object-reflector",
|
||||
"version": "1.1.2",
|
||||
"version": "1.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/object-reflector.git",
|
||||
"reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d"
|
||||
"reference": "1d439c229e61f244ff1f211e5c99737f90c67def"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/9b8772b9cbd456ab45d4a598d2dd1a1bced6363d",
|
||||
"reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/1d439c229e61f244ff1f211e5c99737f90c67def",
|
||||
"reference": "1d439c229e61f244ff1f211e5c99737f90c67def",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4528,7 +4529,7 @@
|
||||
"homepage": "https://github.com/sebastianbergmann/object-reflector/",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/object-reflector/issues",
|
||||
"source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1.2"
|
||||
"source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4536,20 +4537,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-30T07:37:18+00:00"
|
||||
"time": "2024-03-01T13:56:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/recursion-context",
|
||||
"version": "3.0.1",
|
||||
"version": "3.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/recursion-context.git",
|
||||
"reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb"
|
||||
"reference": "9bfd3c6f1f08c026f542032dfb42813544f7d64c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/367dcba38d6e1977be014dc4b22f47a484dac7fb",
|
||||
"reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/9bfd3c6f1f08c026f542032dfb42813544f7d64c",
|
||||
"reference": "9bfd3c6f1f08c026f542032dfb42813544f7d64c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4591,7 +4592,7 @@
|
||||
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/recursion-context/issues",
|
||||
"source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0.1"
|
||||
"source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4599,20 +4600,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-30T07:34:24+00:00"
|
||||
"time": "2024-03-01T14:07:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/resource-operations",
|
||||
"version": "2.0.2",
|
||||
"version": "2.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/resource-operations.git",
|
||||
"reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3"
|
||||
"reference": "72a7f7674d053d548003b16ff5a106e7e0e06eee"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/31d35ca87926450c44eae7e2611d45a7a65ea8b3",
|
||||
"reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/72a7f7674d053d548003b16ff5a106e7e0e06eee",
|
||||
"reference": "72a7f7674d053d548003b16ff5a106e7e0e06eee",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4642,8 +4643,7 @@
|
||||
"description": "Provides a list of PHP built-in functions that operate on resources",
|
||||
"homepage": "https://www.github.com/sebastianbergmann/resource-operations",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/resource-operations/issues",
|
||||
"source": "https://github.com/sebastianbergmann/resource-operations/tree/2.0.2"
|
||||
"source": "https://github.com/sebastianbergmann/resource-operations/tree/2.0.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4651,7 +4651,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-30T07:30:19+00:00"
|
||||
"time": "2024-03-01T13:59:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/version",
|
||||
@@ -4702,16 +4702,16 @@
|
||||
},
|
||||
{
|
||||
"name": "squizlabs/php_codesniffer",
|
||||
"version": "3.9.0",
|
||||
"version": "3.10.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
|
||||
"reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b"
|
||||
"reference": "8f90f7a53ce271935282967f53d0894f8f1ff877"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/d63cee4890a8afaf86a22e51ad4d97c91dd4579b",
|
||||
"reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b",
|
||||
"url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/8f90f7a53ce271935282967f53d0894f8f1ff877",
|
||||
"reference": "8f90f7a53ce271935282967f53d0894f8f1ff877",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4778,7 +4778,7 @@
|
||||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2024-02-16T15:06:51+00:00"
|
||||
"time": "2024-05-22T21:24:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/browser-kit",
|
||||
@@ -4985,16 +4985,16 @@
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
"version": "1.2.2",
|
||||
"version": "1.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/theseer/tokenizer.git",
|
||||
"reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96"
|
||||
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
|
||||
"reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
|
||||
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5023,7 +5023,7 @@
|
||||
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
||||
"support": {
|
||||
"issues": "https://github.com/theseer/tokenizer/issues",
|
||||
"source": "https://github.com/theseer/tokenizer/tree/1.2.2"
|
||||
"source": "https://github.com/theseer/tokenizer/tree/1.2.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -5031,7 +5031,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-11-20T00:12:19+00:00"
|
||||
"time": "2024-03-03T12:36:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
|
@@ -281,6 +281,22 @@ services:
|
||||
tags:
|
||||
- { name: console.command }
|
||||
|
||||
console.command.user.delete_id:
|
||||
class: phpbb\console\command\user\delete_id
|
||||
arguments:
|
||||
- '@dbal.conn'
|
||||
- '@language'
|
||||
- '@log'
|
||||
- '@user'
|
||||
- '@user_loader'
|
||||
- '%tables.bots%'
|
||||
- '%tables.user_group%'
|
||||
- '%tables.users%'
|
||||
- '%core.root_path%'
|
||||
- '%core.php_ext%'
|
||||
tags:
|
||||
- { name: console.command }
|
||||
|
||||
console.command.user.reclean:
|
||||
class: phpbb\console\command\user\reclean
|
||||
arguments:
|
||||
|
@@ -1,4 +1,15 @@
|
||||
services:
|
||||
phpbb.ucp.controller.delete_cookies:
|
||||
class: phpbb\ucp\controller\delete_cookies
|
||||
arguments:
|
||||
- '@config'
|
||||
- '@dispatcher'
|
||||
- '@language'
|
||||
- '@request'
|
||||
- '@user'
|
||||
- '%core.root_path%'
|
||||
- '%core.php_ext%'
|
||||
|
||||
phpbb.ucp.controller.reset_password:
|
||||
class: phpbb\ucp\controller\reset_password
|
||||
arguments:
|
||||
|
@@ -1,3 +1,7 @@
|
||||
phpbb_ucp_delete_cookies_controller:
|
||||
path: /delete_cookies
|
||||
defaults: { _controller: phpbb.ucp.controller.delete_cookies:handle }
|
||||
|
||||
phpbb_ucp_reset_password_controller:
|
||||
path: /reset_password
|
||||
defaults: { _controller: phpbb.ucp.controller.reset_password:reset }
|
||||
|
@@ -50,6 +50,8 @@
|
||||
<ol>
|
||||
<li><a href="#changelog">Changelog</a>
|
||||
<ul>
|
||||
<li><a href="#v3312">Changes since 3.3.12</a></li>
|
||||
<li><a href="#v3312rc1">Changes since 3.3.12-RC1</a></li>
|
||||
<li><a href="#v3311">Changes since 3.3.11</a></li>
|
||||
<li><a href="#v3310">Changes since 3.3.10</a></li>
|
||||
<li><a href="#v3310rc1">Changes since 3.3.10-RC1</a></li>
|
||||
@@ -168,6 +170,70 @@
|
||||
<div class="inner">
|
||||
|
||||
<div class="content">
|
||||
<a name="v3312"></a><h3>Changes since 3.3.12</h3>
|
||||
<h4>Bug</h4>
|
||||
<ul>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-13916">PHPBB-13916</a>] - Cancelling save draft removes previous notify setting on posting page</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-14454">PHPBB-14454</a>] - Accessing ACP modules while testing user permissions returns a General Error</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-15043">PHPBB-15043</a>] - Searching no longer working in 3.2.0</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-15576">PHPBB-15576</a>] - PM subject truncated to shorter length than maxlength</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-16213">PHPBB-16213</a>] - vendor and phpbb folders should have .htaccess files</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-16907">PHPBB-16907</a>] - "phpbb" value in "hiddenSegments" blocks client requests for extensions in IIS</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17109">PHPBB-17109</a>] - Users without the "Can use signature" permission should not see checkboxes for signature</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17175">PHPBB-17175</a>] - Breadcrumbs show wrong forum and topic when using 'email topic'</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17301">PHPBB-17301</a>] - Wrong length parameter for fread in phpbb/cache/driver/file.php can lead to unusable forum</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17327">PHPBB-17327</a>] - Fix linting issue in console user add command</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17332">PHPBB-17332</a>] - New permission copied from existing permission ignores permission set options</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17337">PHPBB-17337</a>] - Transaction begin is missing from mysqli driver </li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17338">PHPBB-17338</a>] - Incorrect members list sorting by user_last_visit</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17351">PHPBB-17351</a>] - phpBB2 password hashes incorrectly handled during rehash cron</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17352">PHPBB-17352</a>] - Long rank titles push other profile details below</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17353">PHPBB-17353</a>] - Gravatar avatar src is not image src</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17356">PHPBB-17356</a>] - Errors hidden by at are being displayed in PHP 8 or newer</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17358">PHPBB-17358</a>] - Redis cache never expires with the TTL of 0</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17362">PHPBB-17362</a>] - Missing declaration of property in extension manager</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17365">PHPBB-17365</a>] - Enforce the search word limit on queries containing operators without white space</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17366">PHPBB-17366</a>] - Captcha disappears on error message from registration & posting</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17369">PHPBB-17369</a>] - Permanently deleting soft-deleted topics returns incorrect forum in redirect link</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17370">PHPBB-17370</a>] - Deleting Cookies on FAQ/other pages</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17374">PHPBB-17374</a>] - ACP - Maintenance - Logs: Deleting Error / Bug</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17375">PHPBB-17375</a>] - User lastvisit gets updated too often in session garbage collection</li>
|
||||
</ul>
|
||||
<h4>Improvement</h4>
|
||||
<ul>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-16553">PHPBB-16553</a>] - Disapproving a reported post causes a "Module not accessible" error</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17308">PHPBB-17308</a>] - Rename tracker project key to PHPBB-</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17315">PHPBB-17315</a>] - Add new template events to group</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17316">PHPBB-17316</a>] - Add template events to ucp_groups_manage</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17317">PHPBB-17317</a>] - Update button text and make it more readable</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17325">PHPBB-17325</a>] - Show explicit message for "Re-Check version" if installed version is still up to date</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17340">PHPBB-17340</a>] - Update composer to 2.7.7</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17342">PHPBB-17342</a>] - Add PHP 8.4-dev tests to GitHub Actions</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17347">PHPBB-17347</a>] - Support deleting users by ID via console</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17350">PHPBB-17350</a>] - Add user IP address to log when installing extensions on fresh installs</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-17355">PHPBB-17355</a>] - Update gravatar hash to sha256</li>
|
||||
</ul>
|
||||
<h4>Task</h4>
|
||||
<ul>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-13933">PHPBB-13933</a>] - Update tokens' definitions in acp_bbcodes</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB-16890">PHPBB-16890</a>] - Edit the config sample files and web.config to deny access to the "config" directory</li>
|
||||
</ul>
|
||||
|
||||
<a name="v3312rc1"></a><h3>Changes since 3.3.12-RC1</h3>
|
||||
<h4>Bug</h4>
|
||||
<ul>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB3-17312">PHPBB3-17312</a>] - User last visit gets updated too often</li>
|
||||
</ul>
|
||||
<h4>Improvement</h4>
|
||||
<ul>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/PHPBB3-17324">PHPBB3-17324</a>] - Add template event to notification_dropdown.html</li>
|
||||
</ul>
|
||||
<h4>Hardening</h4>
|
||||
<ul>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/SECURITY-276">SECURITY-276</a>] - Prevent resending activation email too often</li>
|
||||
<li>[<a href="https://tracker.phpbb.com/browse/SECURITY-278">SECURITY-278</a>] - Always release cron lock, even invalid task is passed</li>
|
||||
</ul>
|
||||
|
||||
<a name="v3311"></a><h3>Changes since 3.3.11</h3>
|
||||
<h4>Bug</h4>
|
||||
<ul>
|
||||
|
@@ -147,7 +147,7 @@
|
||||
<li>Oracle</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>PHP 7.2.0+</strong> up to and including <strong>PHP 8.1</strong> with support for the database you intend to use.</li>
|
||||
<li><strong>PHP 7.2.0+</strong> up to and including <strong>PHP 8.3</strong> with support for the database you intend to use.</li>
|
||||
<li>The following PHP modules are required:
|
||||
<ul>
|
||||
<li>json</li>
|
||||
|
@@ -327,7 +327,7 @@
|
||||
|
||||
<p>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 phpBB. If you are running a development version of PHP please check any bugs you find on a system running a stable release before submitting.</p>
|
||||
|
||||
<p>This board has been developed and tested under Linux and Windows (amongst others) running Apache using MySQLi 4.1.3, 4.x, 5.x, MariaDB 5.x, PostgreSQL 8.x, Oracle 8 and SQLite 3. Versions of PHP used range from 7.2.0 to 7.4.x, 8.0.x and 8.1.x.</p>
|
||||
<p>This board has been developed and tested under Linux and Windows (amongst others) running Apache using MySQLi 4.1.3, 4.x, 5.x, MariaDB 5.x, PostgreSQL 8.x, Oracle 8 and SQLite 3. Versions of PHP used range from 7.2.0 to 7.4.x and 8.0.x to 8.3.x.</p>
|
||||
|
||||
<a name="phpsec"></a><h3>7.i. Notice on PHP security issues</h3>
|
||||
|
||||
|
@@ -184,6 +184,24 @@ acp_group_types_prepend
|
||||
* Since: 3.2.9-RC1
|
||||
* Purpose: Add additional group type options to group settings (prepend the list)
|
||||
|
||||
acp_groups_add_user_options_after
|
||||
===
|
||||
* Location: adm/style/acp_groups.html
|
||||
* Since: 3.3.13-RC1
|
||||
* Purpose: Add content after options for adding user to group in the ACP
|
||||
|
||||
acp_groups_add_user_options_before
|
||||
===
|
||||
* Location: adm/style/acp_groups.html
|
||||
* Since: 3.3.13-RC1
|
||||
* Purpose: Add content before options for adding user to group in the ACP
|
||||
|
||||
acp_groups_add_user_usernames_before
|
||||
===
|
||||
* Location: adm/style/acp_groups.html
|
||||
* Since: 3.3.13-RC1
|
||||
* Purpose: Add content before usernames option for adding user to group in the ACP
|
||||
|
||||
acp_groups_find_username_append
|
||||
===
|
||||
* Location: adm/style/acp_groups.html
|
||||
@@ -1597,6 +1615,20 @@ navbar_header_username_prepend
|
||||
* Since: 3.1.0-RC1
|
||||
* Purpose: Add text and HTMl before the username shown in the navbar.
|
||||
|
||||
notification_dropdown_footer_after
|
||||
===
|
||||
* Locations:
|
||||
+ styles/prosilver/template/notification_dropdown.html
|
||||
* Since: 3.3.12
|
||||
* Purpose: Add content after notifications list footer.
|
||||
|
||||
notification_dropdown_footer_before
|
||||
===
|
||||
* Locations:
|
||||
+ styles/prosilver/template/notification_dropdown.html
|
||||
* Since: 3.3.12
|
||||
* Purpose: Add content before notifications list footer.
|
||||
|
||||
overall_footer_after
|
||||
===
|
||||
* Locations:
|
||||
@@ -2521,6 +2553,20 @@ ucp_friend_list_before
|
||||
* Since: 3.1.0-a4
|
||||
* Purpose: Add optional elements before list of friends in UCP
|
||||
|
||||
ucp_group_settings_after
|
||||
===
|
||||
* Locations:
|
||||
+ styles/prosilver/template/ucp_groups_manage.html
|
||||
* Since: 3.3.13-RC1
|
||||
* Purpose: Add content after options for managing a group in the UCP
|
||||
|
||||
ucp_group_settings_before
|
||||
===
|
||||
* Locations:
|
||||
+ styles/prosilver/template/ucp_groups_manage.html
|
||||
* Since: 3.3.13-RC1
|
||||
* Purpose: Add content before options for managing a group in the UCP
|
||||
|
||||
ucp_header_content_before
|
||||
===
|
||||
* Locations:
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# Sample lighttpd configuration file for phpBB.
|
||||
# Global settings have been removed, copy them
|
||||
# from your system's lighttpd.conf.
|
||||
# Tested with lighttpd 1.4.35
|
||||
# Tested with lighttpd 1.4.36
|
||||
|
||||
# If you want to use the X-Sendfile feature,
|
||||
# uncomment the 'allow-x-send-file' for the fastcgi
|
||||
@@ -13,7 +13,7 @@
|
||||
# for the details on X-Sendfile.
|
||||
|
||||
# Load moules
|
||||
server.modules += (
|
||||
server.modules += (
|
||||
"mod_access",
|
||||
"mod_fastcgi",
|
||||
"mod_rewrite",
|
||||
@@ -32,12 +32,12 @@ $HTTP["host"] == "www.myforums.com" {
|
||||
server.name = "www.myforums.com"
|
||||
server.document-root = "/path/to/phpbb"
|
||||
server.dir-listing = "disable"
|
||||
|
||||
|
||||
index-file.names = ( "index.php", "index.htm", "index.html" )
|
||||
accesslog.filename = "/var/log/lighttpd/access-www.myforums.com.log"
|
||||
|
||||
# Deny access to internal phpbb files.
|
||||
$HTTP["url"] =~ "^/(config\.php|common\.php|cache|files|images/avatars/upload|includes|phpbb|store|vendor)" {
|
||||
|
||||
# Deny access to internal phpbb files.
|
||||
$HTTP["url"] =~ "^/(config|common\.php|cache|files|images/avatars/upload|includes|phpbb|store|vendor)" {
|
||||
url.access-deny = ( "" )
|
||||
}
|
||||
|
||||
@@ -45,27 +45,28 @@ $HTTP["host"] == "www.myforums.com" {
|
||||
$HTTP["url"] =~ "/\.svn|/\.git" {
|
||||
url.access-deny = ( "" )
|
||||
}
|
||||
|
||||
|
||||
# Deny access to apache configuration files.
|
||||
$HTTP["url"] =~ "/\.htaccess|/\.htpasswd|/\.htgroups" {
|
||||
url.access-deny = ( "" )
|
||||
}
|
||||
|
||||
|
||||
# The following 3 lines will rewrite URLs passed through the front controller
|
||||
# to not require app.php in the actual URL. In other words, a controller is
|
||||
# by default accessed at /app.php/my/controller, but can also be accessed at
|
||||
# /my/controller
|
||||
url.rewrite-if-not-file = (
|
||||
"^/(.*)$" => "/app.php/$1"
|
||||
"^/install/(.*)$" => "/install/app.php/$1",
|
||||
"^/(.*)$" => "/app.php/$1"
|
||||
)
|
||||
|
||||
fastcgi.server = ( ".php" =>
|
||||
|
||||
fastcgi.server = ( ".php" =>
|
||||
((
|
||||
"bin-path" => "/usr/bin/php-cgi",
|
||||
"socket" => "/tmp/php.socket",
|
||||
"max-procs" => 4,
|
||||
"idle-timeout" => 30,
|
||||
"bin-environment" => (
|
||||
"bin-environment" => (
|
||||
"PHP_FCGI_CHILDREN" => "10",
|
||||
"PHP_FCGI_MAX_REQUESTS" => "10000"
|
||||
),
|
||||
|
@@ -63,7 +63,7 @@ server {
|
||||
}
|
||||
|
||||
# Deny access to internal phpbb files.
|
||||
location ~ /(config\.php|common\.php|cache|files|images/avatars/upload|includes|(?<!ext/)phpbb(?!\w+)|store|vendor) {
|
||||
location ~ /(config|common\.php|cache|files|images/avatars/upload|includes|(?<!ext/)phpbb(?!\w+)|store|vendor) {
|
||||
deny all;
|
||||
# deny was ignored before 0.8.40 for connections over IPv6.
|
||||
# Use internal directive to prohibit access on older versions.
|
||||
|
@@ -110,6 +110,7 @@ class acp_bbcodes
|
||||
);
|
||||
|
||||
$bbcode_tokens = array('TEXT', 'SIMPLETEXT', 'INTTEXT', 'IDENTIFIER', 'NUMBER', 'EMAIL', 'URL', 'LOCAL_URL', 'RELATIVE_URL', 'COLOR');
|
||||
$bbcode_tokens = array_merge($bbcode_tokens, ['ALNUM', 'CHOICE', 'FLOAT', 'HASHMAP', 'INT', 'IP', 'IPPORT', 'IPV4', 'IPV6', 'MAP', 'RANGE', 'REGEXP', 'TIMESTAMP', 'UINT']);
|
||||
|
||||
/**
|
||||
* Modify custom bbcode template data before we display the add/edit form
|
||||
|
@@ -238,10 +238,11 @@ class acp_inactive
|
||||
|
||||
$messenger->save_queue();
|
||||
|
||||
// Add the remind state to the database
|
||||
// Add the remind state to the database and increase activation expiration by one day
|
||||
$sql = 'UPDATE ' . USERS_TABLE . '
|
||||
SET user_reminded = user_reminded + 1,
|
||||
user_reminded_time = ' . time() . '
|
||||
user_reminded_time = ' . time() . ',
|
||||
user_actkey_expiration = ' . (int) $user::get_token_expiration() . '
|
||||
WHERE ' . $db->sql_in_set('user_id', $user_ids);
|
||||
$db->sql_query($sql);
|
||||
|
||||
|
@@ -51,7 +51,7 @@ class acp_logs
|
||||
$pagination = $phpbb_container->get('pagination');
|
||||
|
||||
// Delete entries if requested and able
|
||||
if (($deletemark || $deleteall) && $auth->acl_get('a_clearlogs'))
|
||||
if (($deleteall || ($deletemark && count($marked))) && $auth->acl_get('a_clearlogs'))
|
||||
{
|
||||
if (confirm_box(true))
|
||||
{
|
||||
|
@@ -454,6 +454,7 @@ class acp_main
|
||||
$template->assign_vars(array(
|
||||
'S_VERSION_UP_TO_DATE' => empty($updates_available),
|
||||
'S_VERSION_UPGRADEABLE' => !empty($upgrades_available),
|
||||
'S_VERSIONCHECK_FORCE' => (bool) $recheck,
|
||||
'UPGRADE_INSTRUCTIONS' => !empty($upgrades_available) ? $user->lang('UPGRADE_INSTRUCTIONS', $upgrades_available['current'], $upgrades_available['announcement']) : false,
|
||||
));
|
||||
}
|
||||
|
@@ -385,14 +385,18 @@ class acp_users
|
||||
$user_actkey = empty($user_activation_key) ? $user_actkey : $user_activation_key;
|
||||
}
|
||||
|
||||
if ($user_row['user_type'] == USER_NORMAL || empty($user_activation_key))
|
||||
{
|
||||
$sql = 'UPDATE ' . USERS_TABLE . "
|
||||
SET user_actkey = '" . $db->sql_escape($user_actkey) . "'
|
||||
WHERE user_id = $user_id";
|
||||
$db->sql_query($sql);
|
||||
}
|
||||
// Always update actkey even if same and also update actkey expiration to 24 hours from now
|
||||
$sql_ary = [
|
||||
'user_actkey' => $user_actkey,
|
||||
'user_actkey_expiration' => $user::get_token_expiration(),
|
||||
];
|
||||
|
||||
$sql = 'UPDATE ' . USERS_TABLE . '
|
||||
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
|
||||
WHERE user_id = ' . (int) $user_id;
|
||||
$db->sql_query($sql);
|
||||
|
||||
// Start sending email
|
||||
$messenger = new messenger(false);
|
||||
|
||||
$messenger->template($email_template, $user_row['user_lang']);
|
||||
@@ -1084,7 +1088,7 @@ class acp_users
|
||||
$s_action_options .= '<option value="' . $value . '">' . $user->lang['USER_ADMIN_' . $lang] . '</option>';
|
||||
}
|
||||
|
||||
$last_active = (!empty($user_row['session_time'])) ? $user_row['session_time'] : $user_row['user_lastvisit'];
|
||||
$last_active = $user_row['user_last_active'] ?: ($user_row['session_time'] ?? 0);
|
||||
|
||||
$inactive_reason = '';
|
||||
if ($user_row['user_type'] == USER_INACTIVE)
|
||||
|
@@ -28,7 +28,7 @@ if (!defined('IN_PHPBB'))
|
||||
*/
|
||||
|
||||
// phpBB Version
|
||||
@define('PHPBB_VERSION', '3.3.12-RC1');
|
||||
@define('PHPBB_VERSION', '3.3.13-RC1');
|
||||
|
||||
// QA-related
|
||||
// define('PHPBB_QA', 1);
|
||||
|
@@ -3028,8 +3028,16 @@ function msg_handler($errno, $msg_text, $errfile, $errline)
|
||||
global $phpbb_root_path, $msg_title, $msg_long_text, $phpbb_log;
|
||||
global $phpbb_container;
|
||||
|
||||
// https://www.php.net/manual/en/language.operators.errorcontrol.php
|
||||
// error_reporting() return a different error code inside the error handler after php 8.0
|
||||
$suppresed = E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR | E_PARSE;
|
||||
if (PHP_VERSION_ID < 80000)
|
||||
{
|
||||
$suppresed = 0;
|
||||
}
|
||||
|
||||
// Do not display notices if we suppress them via @
|
||||
if (error_reporting() == 0 && $errno != E_USER_ERROR && $errno != E_USER_WARNING && $errno != E_USER_NOTICE)
|
||||
if (error_reporting() == $suppresed && $errno != E_USER_ERROR && $errno != E_USER_WARNING && $errno != E_USER_NOTICE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -4053,7 +4061,7 @@ function page_header($page_title = '', $display_online_list = false, $item_id =
|
||||
'U_SEARCH_UNANSWERED' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=unanswered'),
|
||||
'U_SEARCH_UNREAD' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=unreadposts'),
|
||||
'U_SEARCH_ACTIVE_TOPICS'=> append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=active_topics'),
|
||||
'U_DELETE_COOKIES' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=delete_cookies'),
|
||||
'U_DELETE_COOKIES' => $controller_helper->route('phpbb_ucp_delete_cookies_controller'),
|
||||
'U_CONTACT_US' => ($config['contact_admin_form_enable'] && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contactadmin') : '',
|
||||
'U_TEAM' => (!$auth->acl_get('u_viewprofile')) ? '' : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=team'),
|
||||
'U_TERMS_USE' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=terms'),
|
||||
|
@@ -325,119 +325,98 @@ function bump_topic_allowed($forum_id, $topic_bumped, $last_post_time, $topic_po
|
||||
*
|
||||
* @return string Context of the specified words separated by "..."
|
||||
*/
|
||||
function get_context($text, $words, $length = 400)
|
||||
function get_context(string $text, array $words, int $length = 400): string
|
||||
{
|
||||
// first replace all whitespaces with single spaces
|
||||
$text = preg_replace('/ +/', ' ', strtr($text, "\t\n\r\x0C ", ' '));
|
||||
if ($length <= 0)
|
||||
{
|
||||
return '...';
|
||||
}
|
||||
|
||||
// we need to turn the entities back into their original form, to not cut the message in between them
|
||||
$entities = array('<', '>', '[', ']', '.', ':', ':');
|
||||
$characters = array('<', '>', '[', ']', '.', ':', ':');
|
||||
$text = str_replace($entities, $characters, $text);
|
||||
$text = html_entity_decode($text);
|
||||
|
||||
$word_indizes = array();
|
||||
if (count($words))
|
||||
// Replace all spaces/invisible characters with single spaces
|
||||
$text = preg_replace("/\s+/u", ' ', $text);
|
||||
|
||||
$text_length = utf8_strlen($text);
|
||||
|
||||
// Get first occurrence of each word
|
||||
$word_indexes = [];
|
||||
foreach ($words as $word)
|
||||
{
|
||||
$match = '';
|
||||
// find the starting indizes of all words
|
||||
foreach ($words as $word)
|
||||
$pos = utf8_stripos($text, $word);
|
||||
|
||||
if ($pos !== false)
|
||||
{
|
||||
if ($word)
|
||||
{
|
||||
if (preg_match('#(?:[^\w]|^)(' . $word . ')(?:[^\w]|$)#i', $text, $match))
|
||||
{
|
||||
if (empty($match[1]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$pos = utf8_strpos($text, $match[1]);
|
||||
if ($pos !== false)
|
||||
{
|
||||
$word_indizes[] = $pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($match);
|
||||
|
||||
if (count($word_indizes))
|
||||
{
|
||||
$word_indizes = array_unique($word_indizes);
|
||||
sort($word_indizes);
|
||||
|
||||
$wordnum = count($word_indizes);
|
||||
// number of characters on the right and left side of each word
|
||||
$sequence_length = (int) ($length / (2 * $wordnum)) - 2;
|
||||
$final_text = '';
|
||||
$word = $j = 0;
|
||||
$final_text_index = -1;
|
||||
|
||||
// cycle through every character in the original text
|
||||
for ($i = $word_indizes[$word], $n = utf8_strlen($text); $i < $n; $i++)
|
||||
{
|
||||
// if the current position is the start of one of the words then append $sequence_length characters to the final text
|
||||
if (isset($word_indizes[$word]) && ($i == $word_indizes[$word]))
|
||||
{
|
||||
if ($final_text_index < $i - $sequence_length - 1)
|
||||
{
|
||||
$final_text .= '... ' . preg_replace('#^([^ ]*)#', '', utf8_substr($text, $i - $sequence_length, $sequence_length));
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the final text is already nearer to the current word than $sequence_length we only append the text
|
||||
// from its current index on and distribute the unused length to all other sequenes
|
||||
$sequence_length += (int) (($final_text_index - $i + $sequence_length + 1) / (2 * $wordnum));
|
||||
$final_text .= utf8_substr($text, $final_text_index + 1, $i - $final_text_index - 1);
|
||||
}
|
||||
$final_text_index = $i - 1;
|
||||
|
||||
// add the following characters to the final text (see below)
|
||||
$word++;
|
||||
$j = 1;
|
||||
}
|
||||
|
||||
if ($j > 0)
|
||||
{
|
||||
// add the character to the final text and increment the sequence counter
|
||||
$final_text .= utf8_substr($text, $i, 1);
|
||||
$final_text_index++;
|
||||
$j++;
|
||||
|
||||
// if this is a whitespace then check whether we are done with this sequence
|
||||
if (utf8_substr($text, $i, 1) == ' ')
|
||||
{
|
||||
// only check whether we have to exit the context generation completely if we haven't already reached the end anyway
|
||||
if ($i + 4 < $n)
|
||||
{
|
||||
if (($j > $sequence_length && $word >= $wordnum) || utf8_strlen($final_text) > $length)
|
||||
{
|
||||
$final_text .= ' ...';
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// make sure the text really reaches the end
|
||||
$j -= 4;
|
||||
}
|
||||
|
||||
// stop context generation and wait for the next word
|
||||
if ($j > $sequence_length)
|
||||
{
|
||||
$j = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return str_replace($characters, $entities, $final_text);
|
||||
$word_indexes[$pos] = $word;
|
||||
}
|
||||
}
|
||||
|
||||
if (!count($words) || !count($word_indizes))
|
||||
if (!empty($word_indexes))
|
||||
{
|
||||
return str_replace($characters, $entities, ((utf8_strlen($text) >= $length + 3) ? utf8_substr($text, 0, $length) . '...' : $text));
|
||||
ksort($word_indexes);
|
||||
|
||||
// Size of the fragment of text per word
|
||||
$num_indexes = count($word_indexes);
|
||||
$characters_per_word = (int) ($length / $num_indexes) + 2; // 2 to leave one character of margin at the sides to don't cut words
|
||||
|
||||
// Get text fragment indexes
|
||||
$fragments = [];
|
||||
foreach ($word_indexes as $index => $word)
|
||||
{
|
||||
$word_length = utf8_strlen($word);
|
||||
$start = max(0, min($text_length - 1 - $characters_per_word, (int) ($index + ($word_length / 2) - ($characters_per_word / 2))));
|
||||
$end = $start + $characters_per_word;
|
||||
|
||||
// Check if we can merge this fragment into the previous fragment
|
||||
if (!empty($fragments))
|
||||
{
|
||||
[$prev_start, $prev_end] = end($fragments);
|
||||
|
||||
if ($prev_end + $characters_per_word >= $index + $word_length)
|
||||
{
|
||||
array_pop($fragments);
|
||||
$start = $prev_start;
|
||||
$end = $prev_end + $characters_per_word;
|
||||
}
|
||||
}
|
||||
|
||||
$fragments[] = [$start, $end];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// There is no coincidences, so we just create a fragment with the first $length characters
|
||||
$fragments[] = [0, $length];
|
||||
$end = $length;
|
||||
}
|
||||
|
||||
$output = [];
|
||||
foreach ($fragments as [$start, $end])
|
||||
{
|
||||
$fragment = utf8_substr($text, $start, $end - $start + 1);
|
||||
|
||||
$fragment_start = 0;
|
||||
$fragment_end = $end - $start + 1;
|
||||
|
||||
// Find the first valid alphanumeric character in the fragment to don't cut words
|
||||
if ($start > 0)
|
||||
{
|
||||
preg_match('/[^a-zA-Z0-9][a-zA-Z0-9]/u', $fragment, $matches, PREG_OFFSET_CAPTURE);
|
||||
$fragment_start = (int) $matches[0][1] + 1; // first valid alphanumeric character
|
||||
}
|
||||
|
||||
// Find the last valid alphanumeric character in the fragment to don't cut words
|
||||
if ($end < $text_length - 1)
|
||||
{
|
||||
preg_match_all('/[a-zA-Z0-9][^a-zA-Z0-9]/u', $fragment, $matches, PREG_OFFSET_CAPTURE);
|
||||
$fragment_end = end($matches[0])[1]; // last valid alphanumeric character
|
||||
}
|
||||
|
||||
$output[] = utf8_substr($fragment, $fragment_start, $fragment_end - $fragment_start + 1);
|
||||
}
|
||||
|
||||
return ($fragments[0][0] !== 0 ? '... ' : '') . htmlentities(implode(' ... ', $output)) . ($end < $text_length - 1 ? ' ...' : '');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1603,7 +1603,7 @@ function phpbb_show_profile($data, $user_notes_enabled = false, $warn_user_enabl
|
||||
|
||||
if ($data['user_allow_viewonline'] || $auth->acl_get('u_viewonline'))
|
||||
{
|
||||
$last_active = (!empty($data['session_time'])) ? $data['session_time'] : $data['user_lastvisit'];
|
||||
$last_active = $data['user_last_active'] ?: ($data['session_time'] ?? 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -480,7 +480,7 @@ class p_master
|
||||
*/
|
||||
function set_active($id = false, $mode = false)
|
||||
{
|
||||
global $request;
|
||||
global $auth, $request, $user;
|
||||
|
||||
$icat = false;
|
||||
$this->active_module = false;
|
||||
@@ -502,6 +502,14 @@ class p_master
|
||||
$id = $this->p_class . '_' . $id;
|
||||
}
|
||||
|
||||
// Fallback to acp main page for special restore permission mode
|
||||
if ($user->data['user_perm_from'] && $auth->acl_get('a_switchperm'))
|
||||
{
|
||||
$id = '';
|
||||
$mode = '';
|
||||
$icat = false;
|
||||
}
|
||||
|
||||
$category = false;
|
||||
foreach ($this->module_ary as $row_id => $item_ary)
|
||||
{
|
||||
|
@@ -1689,7 +1689,7 @@ function submit_pm($mode, $subject, &$data_ary, $put_in_outbox = true)
|
||||
}
|
||||
|
||||
// First of all make sure the subject are having the correct length.
|
||||
$subject = truncate_string($subject);
|
||||
$subject = truncate_string($subject, $mode === 'post' ? 120 : 124);
|
||||
|
||||
$db->sql_transaction('begin');
|
||||
|
||||
|
@@ -210,18 +210,18 @@ function user_add($user_row, $cp_data = false, $notifications_data = null)
|
||||
|
||||
// These are the additional vars able to be specified
|
||||
$additional_vars = array(
|
||||
'user_permissions' => '',
|
||||
'user_timezone' => $config['board_timezone'],
|
||||
'user_dateformat' => $config['default_dateformat'],
|
||||
'user_lang' => $config['default_lang'],
|
||||
'user_style' => (int) $config['default_style'],
|
||||
'user_actkey' => '',
|
||||
'user_ip' => '',
|
||||
'user_regdate' => time(),
|
||||
'user_passchg' => time(),
|
||||
'user_options' => 230271,
|
||||
'user_permissions' => '',
|
||||
'user_timezone' => $config['board_timezone'],
|
||||
'user_dateformat' => $config['default_dateformat'],
|
||||
'user_lang' => $config['default_lang'],
|
||||
'user_style' => (int) $config['default_style'],
|
||||
'user_actkey' => '',
|
||||
'user_ip' => '',
|
||||
'user_regdate' => time(),
|
||||
'user_passchg' => time(),
|
||||
'user_options' => 230271,
|
||||
// We do not set the new flag here - registration scripts need to specify it
|
||||
'user_new' => 0,
|
||||
'user_new' => 0,
|
||||
|
||||
'user_inactive_reason' => 0,
|
||||
'user_inactive_time' => 0,
|
||||
|
@@ -222,6 +222,7 @@ function mcp_post_details($id, $mode, $action)
|
||||
'U_POST_ACTION' => "$url&i=$id&mode=post_details", // Use this for action parameters
|
||||
'U_APPROVE_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", "i=queue&p=$post_id"),
|
||||
|
||||
'S_CAN_APPROVE' => $auth->acl_get('m_approve', $post_info['forum_id']),
|
||||
'S_CAN_VIEWIP' => $auth->acl_get('m_info', $post_info['forum_id']),
|
||||
'S_CAN_CHGPOSTER' => $auth->acl_get('m_chgposter', $post_info['forum_id']),
|
||||
'S_CAN_LOCK_POST' => $auth->acl_get('m_lock', $post_info['forum_id']),
|
||||
|
@@ -252,6 +252,7 @@ class mcp_reports
|
||||
$report_template = array(
|
||||
'S_MCP_REPORT' => true,
|
||||
'S_CLOSE_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&mode=report_details&p=' . $post_id),
|
||||
'S_CAN_APPROVE' => $auth->acl_get('m_approve', $post_info['forum_id']),
|
||||
'S_CAN_VIEWIP' => $auth->acl_get('m_info', $post_info['forum_id']),
|
||||
'S_POST_REPORTED' => $post_info['post_reported'],
|
||||
'S_POST_UNAPPROVED' => $post_info['post_visibility'] == ITEM_UNAPPROVED || $post_info['post_visibility'] == ITEM_REAPPROVE,
|
||||
@@ -260,6 +261,7 @@ class mcp_reports
|
||||
'S_USER_NOTES' => true,
|
||||
|
||||
'U_EDIT' => ($auth->acl_get('m_edit', $post_info['forum_id'])) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=edit&p={$post_info['post_id']}") : '',
|
||||
'U_APPROVE_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&p=' . $post_id),
|
||||
'U_MCP_APPROVE' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=approve_details&p=' . $post_id),
|
||||
'U_MCP_REPORT' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&mode=report_details&p=' . $post_id),
|
||||
'U_MCP_REPORTER_NOTES' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $report['user_id']),
|
||||
|
@@ -488,6 +488,8 @@ class ucp_prefs
|
||||
}
|
||||
|
||||
$template->assign_vars(array(
|
||||
'S_SIG_ALLOWED' => $config['allow_sig'] && $auth->acl_get('u_sig'),
|
||||
|
||||
'S_BBCODE' => $data['bbcode'],
|
||||
'S_SMILIES' => $data['smilies'],
|
||||
'S_SIG' => $data['sig'],
|
||||
|
@@ -196,9 +196,10 @@ class ucp_profile
|
||||
{
|
||||
$notifications_manager = $phpbb_container->get('notification_manager');
|
||||
$notifications_manager->add_notifications('notification.type.admin_activate_user', array(
|
||||
'user_id' => $user->data['user_id'],
|
||||
'user_actkey' => $user_actkey,
|
||||
'user_regdate' => time(), // Notification time
|
||||
'user_id' => $user->data['user_id'],
|
||||
'user_actkey' => $user_actkey,
|
||||
'user_actkey_expiration' => $user::get_token_expiration(),
|
||||
'user_regdate' => time(), // Notification time
|
||||
));
|
||||
}
|
||||
|
||||
|
@@ -381,18 +381,19 @@ class ucp_register
|
||||
$passwords_manager = $phpbb_container->get('passwords.manager');
|
||||
|
||||
$user_row = array(
|
||||
'username' => $data['username'],
|
||||
'user_password' => $passwords_manager->hash($data['new_password']),
|
||||
'user_email' => $data['email'],
|
||||
'group_id' => (int) $group_id,
|
||||
'user_timezone' => $data['tz'],
|
||||
'user_lang' => $data['lang'],
|
||||
'user_type' => $user_type,
|
||||
'user_actkey' => $user_actkey,
|
||||
'user_ip' => $user->ip,
|
||||
'user_regdate' => time(),
|
||||
'user_inactive_reason' => $user_inactive_reason,
|
||||
'user_inactive_time' => $user_inactive_time,
|
||||
'username' => $data['username'],
|
||||
'user_password' => $passwords_manager->hash($data['new_password']),
|
||||
'user_email' => $data['email'],
|
||||
'group_id' => (int) $group_id,
|
||||
'user_timezone' => $data['tz'],
|
||||
'user_lang' => $data['lang'],
|
||||
'user_type' => $user_type,
|
||||
'user_actkey' => $user_actkey,
|
||||
'user_actkey_expiration' => $user::get_token_expiration(),
|
||||
'user_ip' => $user->ip,
|
||||
'user_regdate' => time(),
|
||||
'user_inactive_reason' => $user_inactive_reason,
|
||||
'user_inactive_time' => $user_inactive_time,
|
||||
);
|
||||
|
||||
if ($config['new_member_post_limit'])
|
||||
|
@@ -45,7 +45,7 @@ class ucp_resend
|
||||
trigger_error('FORM_INVALID');
|
||||
}
|
||||
|
||||
$sql = 'SELECT user_id, group_id, username, user_email, user_type, user_lang, user_actkey, user_inactive_reason
|
||||
$sql = 'SELECT user_id, group_id, username, user_email, user_type, user_lang, user_actkey, user_actkey_expiration, user_inactive_reason
|
||||
FROM ' . USERS_TABLE . "
|
||||
WHERE user_email = '" . $db->sql_escape($email) . "'
|
||||
AND username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'";
|
||||
@@ -73,6 +73,12 @@ class ucp_resend
|
||||
trigger_error('ACCOUNT_DEACTIVATED');
|
||||
}
|
||||
|
||||
// Do not resend activation email if valid one still exists
|
||||
if (!empty($user_row['user_actkey']) && (int) $user_row['user_actkey_expiration'] >= time())
|
||||
{
|
||||
trigger_error('ACTIVATION_ALREADY_SENT');
|
||||
}
|
||||
|
||||
// Determine coppa status on group (REGISTERED(_COPPA))
|
||||
$sql = 'SELECT group_name, group_type
|
||||
FROM ' . GROUPS_TABLE . '
|
||||
@@ -144,6 +150,8 @@ class ucp_resend
|
||||
$db->sql_freeresult($result);
|
||||
}
|
||||
|
||||
$this->update_activation_expiration();
|
||||
|
||||
meta_refresh(3, append_sid("{$phpbb_root_path}index.$phpEx"));
|
||||
|
||||
$message = ($config['require_activation'] == USER_ACTIVATION_ADMIN) ? $user->lang['ACTIVATION_EMAIL_SENT_ADMIN'] : $user->lang['ACTIVATION_EMAIL_SENT'];
|
||||
@@ -160,4 +168,23 @@ class ucp_resend
|
||||
$this->tpl_name = 'ucp_resend';
|
||||
$this->page_title = 'UCP_RESEND';
|
||||
}
|
||||
|
||||
/**
|
||||
* Update activation expiration to 1 day from now
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function update_activation_expiration(): void
|
||||
{
|
||||
global $db, $user;
|
||||
|
||||
$sql_ary = [
|
||||
'user_actkey_expiration' => $user::get_token_expiration(),
|
||||
];
|
||||
|
||||
$sql = 'UPDATE ' . USERS_TABLE . '
|
||||
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
|
||||
WHERE user_id = ' . (int) $user->id();
|
||||
$db->sql_query($sql);
|
||||
}
|
||||
}
|
||||
|
@@ -72,6 +72,22 @@ function utf8_strpos($str, $needle, $offset = null)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* UTF-8 aware alternative to stripos
|
||||
* @ignore
|
||||
*/
|
||||
function utf8_stripos($str, $needle, $offset = null)
|
||||
{
|
||||
if (is_null($offset))
|
||||
{
|
||||
return mb_stripos($str, $needle);
|
||||
}
|
||||
else
|
||||
{
|
||||
return mb_stripos($str, $needle, $offset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* UTF-8 aware alternative to strtolower
|
||||
* @ignore
|
||||
|
@@ -38,7 +38,7 @@ $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
|
||||
$convertor_data = array(
|
||||
'forum_name' => 'phpBB 2.0.x',
|
||||
'version' => '1.0.3',
|
||||
'phpbb_version' => '3.3.12',
|
||||
'phpbb_version' => '3.3.13',
|
||||
'author' => '<a href="https://www.phpbb.com/">phpBB Limited</a>',
|
||||
'dbms' => $dbms,
|
||||
'dbhost' => $dbhost,
|
||||
@@ -901,6 +901,7 @@ if (!$get_info)
|
||||
array('user_email', 'users.user_email', 'strtolower'),
|
||||
array('user_birthday', ((defined('MOD_BIRTHDAY')) ? 'users.user_birthday' : ''), 'phpbb_get_birthday'),
|
||||
array('user_lastvisit', 'users.user_lastvisit', 'intval'),
|
||||
array('user_last_active', 'users.user_lastvisit', 'intval'),
|
||||
array('user_lastmark', 'users.user_lastvisit', 'intval'),
|
||||
array('user_lang', $config['default_lang'], ''),
|
||||
array('', 'users.user_lang', ''),
|
||||
|
@@ -23,7 +23,7 @@ if (php_sapi_name() !== 'cli')
|
||||
define('IN_PHPBB', true);
|
||||
define('IN_INSTALL', true);
|
||||
define('PHPBB_ENVIRONMENT', 'production');
|
||||
define('PHPBB_VERSION', '3.3.12-RC1');
|
||||
define('PHPBB_VERSION', '3.3.13-RC1');
|
||||
$phpbb_root_path = __DIR__ . '/../';
|
||||
$phpEx = substr(strrchr(__FILE__, '.'), 1);
|
||||
|
||||
|
@@ -316,7 +316,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('update_hashes_lock
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('upload_icons_path', 'images/upload_icons');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('upload_path', 'files');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('use_system_cron', '0');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('version', '3.3.12-RC1');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('version', '3.3.13-RC1');
|
||||
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');
|
||||
|
||||
@@ -527,10 +527,10 @@ INSERT INTO phpbb_forums (forum_name, forum_desc, left_id, right_id, parent_id,
|
||||
INSERT INTO phpbb_forums (forum_name, forum_desc, left_id, right_id, parent_id, forum_type, forum_posts_approved, forum_posts_unapproved, forum_posts_softdeleted, forum_topics_approved, forum_topics_unapproved, forum_topics_softdeleted, forum_last_post_id, forum_last_poster_id, forum_last_poster_name, forum_last_poster_colour, forum_last_post_subject, forum_last_post_time, forum_link, forum_password, forum_image, forum_rules, forum_rules_link, forum_rules_uid, forum_desc_uid, prune_freq, prune_days, prune_viewed, forum_parents, forum_flags) VALUES ('{L_FORUMS_TEST_FORUM_TITLE}', '{L_FORUMS_TEST_FORUM_DESC}', 2, 3, 1, 1, 1, 0, 0, 1, 0, 0, 1, 2, 'Admin', 'AA0000', '{L_TOPICS_TOPIC_TITLE}', 972086460, '', '', '', '', '', '', '', 1, 7, 7, '', 48);
|
||||
|
||||
# -- Users / Anonymous user
|
||||
INSERT INTO phpbb_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_jabber, user_actkey, user_newpasswd, user_allow_massemail) VALUES (2, 1, 'Anonymous', 'anonymous', 0, '', '', 'en', 1, 0, '', 0, '', '', '', '', '', 't', 'a', 't', 'd', '', '', '', '', '', '', 0);
|
||||
INSERT INTO phpbb_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_jabber, user_actkey, user_actkey_expiration, user_newpasswd, user_allow_massemail) VALUES (2, 1, 'Anonymous', 'anonymous', 0, '', '', 'en', 1, 0, '', 0, '', '', '', '', '', 't', 'a', 't', 'd', '', '', '', '', '', 0, '', 0);
|
||||
|
||||
# -- username: Admin password: admin (change this or remove it once everything is working!)
|
||||
INSERT INTO phpbb_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_jabber, user_actkey, user_newpasswd) VALUES (3, 5, 'Admin', 'admin', 0, '21232f297a57a5a743894a0e4a801fc3', 'admin@yourdomain.com', 'en', 1, 1, 'AA0000', 1, '', '', '', '', '', 't', 'a', 't', 'd', '', '', '', '', '', '');
|
||||
INSERT INTO phpbb_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_jabber, user_actkey, user_actkey_expiration, user_newpasswd) VALUES (3, 5, 'Admin', 'admin', 0, '21232f297a57a5a743894a0e4a801fc3', 'admin@yourdomain.com', 'en', 1, 1, 'AA0000', 1, '', '', '', '', '', 't', 'a', 't', 'd', '', '', '', '', '', 0, '');
|
||||
|
||||
# -- Groups
|
||||
INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('GUESTS', 3, 0, '', 0, '', '', '', 5);
|
||||
|
@@ -51,7 +51,15 @@ function installer_msg_handler($errno, $msg_text, $errfile, $errline)
|
||||
{
|
||||
global $phpbb_installer_container, $msg_long_text;
|
||||
|
||||
if (error_reporting() == 0)
|
||||
// Acording to https://www.php.net/manual/en/language.operators.errorcontrol.php
|
||||
// error_reporting() return a different error code inside the error handler after php 8.0
|
||||
$suppresed = E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR | E_PARSE;
|
||||
if (PHP_VERSION_ID < 80000)
|
||||
{
|
||||
$suppresed = 0;
|
||||
}
|
||||
|
||||
if (error_reporting() == $suppresed)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@@ -88,6 +88,20 @@ $lang = array_merge($lang, array(
|
||||
'LOCAL_URL' => 'A local URL. The URL must be relative to the topic page and cannot contain a server name or protocol, as links are prefixed with “%s”',
|
||||
'RELATIVE_URL' => 'A relative URL. You can use this to match parts of a URL, but be careful: a full URL is a valid relative URL. When you want to use relative URLs of your board, use the LOCAL_URL token.',
|
||||
'COLOR' => 'A HTML colour, can be either in the numeric form <samp>#FF1234</samp> or a <a href="http://www.w3.org/TR/CSS21/syndata.html#value-def-color">CSS colour keyword</a> such as <samp>fuchsia</samp> or <samp>InactiveBorder</samp>',
|
||||
'ALNUM' => 'Characters from the latin alphabet (A-Z) and numbers.',
|
||||
'CHOICE' => 'A choice of specified values, e.g. <samp>{CHOICE=spades,hearts,diamonds,clubs}</samp>. The values are treated as case-insensitive by default and can be treated case-sensitive by specifying the <samp>caseSensitive</samp> option: <samp>{CHOICE=Spades,Hearts,Diamonds,Clubs;caseSensitive}</samp>',
|
||||
'FLOAT' => 'A decimal value, e.g. <samp>0.5</samp>.',
|
||||
'HASHMAP' => 'Maps strings to their replacement in the form <samp>{HASHMAP=string1:replacement1,string2:replacement2}</samp>. Case-sensitive. Preserves unknown values by default.',
|
||||
'INT' => 'An integer value, e.g. <samp>2</samp>.',
|
||||
'IP' => 'A valid IPv4 or IPv6 address.',
|
||||
'IPPORT' => 'A valid IPv4 or IPv6 address with port number.',
|
||||
'IPV4' => 'A valid IPv4 address.',
|
||||
'IPV6' => 'A valid IPv6 address.',
|
||||
'MAP' => 'Maps strings to their replacement in the form <samp>{MAP=string1:replacement1,string2:replacement2}</samp>. Case-insensitive. Preserves unknown values by default.',
|
||||
'RANGE' => 'Accepts an integer in the given range, e.g. <samp>{RANGE=-10,42}</samp>.',
|
||||
'REGEXP' => 'Validates its value against a given regexp, e.g. <samp>{REGEXP=/^foo\w+bar$/}</samp>.',
|
||||
'TIMESTAMP' => 'A timestamp such as <samp>1h30m10s</samp> which will be converted to a number of seconds. Also accepts a number.',
|
||||
'UINT' => 'An unsigned integer value. Same as <samp>{INT}</samp>, but rejects values less than 0.',
|
||||
),
|
||||
));
|
||||
|
||||
|
@@ -108,6 +108,8 @@ $lang = array_merge($lang, array(
|
||||
'CLI_DESCRIPTION_USER_ADD_OPTION_NOTIFY' => 'Send account activation email to the new user (not sent by default)',
|
||||
'CLI_DESCRIPTION_USER_DELETE' => 'Delete a user account.',
|
||||
'CLI_DESCRIPTION_USER_DELETE_USERNAME' => 'Username of the user to delete',
|
||||
'CLI_DESCRIPTION_USER_DELETE_ID' => 'Delete user accounts by ID.',
|
||||
'CLI_DESCRIPTION_USER_DELETE_ID_OPTION_ID' => 'User IDs of the users to delete',
|
||||
'CLI_DESCRIPTION_USER_DELETE_OPTION_POSTS' => 'Delete all posts by the user. Without this option, the user’s posts will be retained.',
|
||||
'CLI_DESCRIPTION_USER_RECLEAN' => 'Re-clean usernames.',
|
||||
|
||||
@@ -155,10 +157,14 @@ $lang = array_merge($lang, array(
|
||||
'CLI_THUMBNAIL_NOTHING_TO_GENERATE' => 'No thumbnails to generate.',
|
||||
'CLI_THUMBNAIL_NOTHING_TO_DELETE' => 'No thumbnails to delete.',
|
||||
|
||||
'CLI_USER_ADD_SUCCESS' => 'Successfully added user %s.',
|
||||
'CLI_USER_DELETE_CONFIRM' => 'Are you sure you want to delete ‘%s’? [y/N]',
|
||||
'CLI_USER_RECLEAN_START' => 'Re-cleaning usernames',
|
||||
'CLI_USER_RECLEAN_DONE' => [
|
||||
'CLI_USER_ADD_SUCCESS' => 'Successfully added user %s.',
|
||||
'CLI_USER_DELETE_CONFIRM' => 'Are you sure you want to delete ‘%s’? [y/N]',
|
||||
'CLI_USER_DELETE_ID_CONFIRM' => 'Are you sure you want to delete the user IDs ‘%s’? [y/N]',
|
||||
'CLI_USER_DELETE_ID_SUCCESS' => 'Successfully deleted user IDs.',
|
||||
'CLI_USER_DELETE_ID_START' => 'Deleting users by ID',
|
||||
'CLI_USER_DELETE_NONE' => 'No users were deleted by user ID.',
|
||||
'CLI_USER_RECLEAN_START' => 'Re-cleaning usernames',
|
||||
'CLI_USER_RECLEAN_DONE' => [
|
||||
0 => 'Re-cleaning complete. No usernames needed to be cleaned.',
|
||||
1 => 'Re-cleaning complete. %d username was cleaned.',
|
||||
2 => 'Re-cleaning complete. %d usernames were cleaned.',
|
||||
|
@@ -64,6 +64,7 @@ $lang = array_merge($lang, array(
|
||||
'ACCOUNT_DEACTIVATED' => 'Your account has been manually deactivated and is only able to be reactivated by an administrator.',
|
||||
'ACP' => 'Administration Control Panel',
|
||||
'ACP_SHORT' => 'ACP',
|
||||
'ACTIVATION_ALREADY_SENT' => 'The activation email has already been sent to your email address. You can try again after 24 hours. If you continue to have problems activating your account, please contact a board administrator.',
|
||||
'ACTIVE' => 'active',
|
||||
'ACTIVE_ERROR' => 'The specified username is currently inactive. If you have problems activating your account, please contact a board administrator.',
|
||||
'ADMINISTRATOR' => 'Administrator',
|
||||
|
@@ -941,10 +941,19 @@ switch ($mode)
|
||||
}
|
||||
else if ($topic_id)
|
||||
{
|
||||
$sql = 'SELECT f.parent_id, f.forum_parents, f.left_id, f.right_id, f.forum_type, f.forum_name, f.forum_id, f.forum_desc, f.forum_desc_uid, f.forum_desc_bitfield, f.forum_desc_options, f.forum_options, t.topic_title
|
||||
FROM ' . FORUMS_TABLE . ' as f,
|
||||
' . TOPICS_TABLE . ' as t
|
||||
WHERE t.forum_id = f.forum_id';
|
||||
// Generate the navlinks based on the selected topic
|
||||
$navlinks_sql_array = [
|
||||
'SELECT' => 'f.parent_id, f.forum_parents, f.left_id, f.right_id, f.forum_type, f.forum_name,
|
||||
f.forum_id, f.forum_desc, f.forum_desc_uid, f.forum_desc_bitfield, f.forum_desc_options,
|
||||
f.forum_options, t.topic_title',
|
||||
'FROM' => [
|
||||
FORUMS_TABLE => 'f',
|
||||
TOPICS_TABLE => 't',
|
||||
],
|
||||
'WHERE' => 't.forum_id = f.forum_id AND t.topic_id = ' . (int) $topic_id,
|
||||
];
|
||||
|
||||
$sql = $db->sql_build_query('SELECT', $navlinks_sql_array);
|
||||
$result = $db->sql_query($sql);
|
||||
$topic_data = $db->sql_fetchrow($result);
|
||||
$db->sql_freeresult($result);
|
||||
@@ -1036,7 +1045,7 @@ switch ($mode)
|
||||
if ($auth->acl_get('u_viewonline'))
|
||||
{
|
||||
$sort_key_text['l'] = $user->lang['SORT_LAST_ACTIVE'];
|
||||
$sort_key_sql['l'] = 'u.user_lastvisit';
|
||||
$sort_key_sql['l'] = 'u.user_last_active';
|
||||
}
|
||||
|
||||
$sort_key_text['m'] = $user->lang['SORT_RANK'];
|
||||
@@ -1138,15 +1147,15 @@ switch ($mode)
|
||||
{
|
||||
if ($active_select === 'lt' && (int) $active[0] == 0 && (int) $active[1] == 0 && (int) $active[2] == 0)
|
||||
{
|
||||
$sql_where .= ' AND u.user_lastvisit = 0';
|
||||
$sql_where .= ' AND u.user_last_active = 0';
|
||||
}
|
||||
else if ($active_select === 'gt')
|
||||
{
|
||||
$sql_where .= ' AND u.user_lastvisit ' . $find_key_match[$active_select] . ' ' . $active_time;
|
||||
$sql_where .= ' AND u.user_last_active ' . $find_key_match[$active_select] . ' ' . $active_time;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sql_where .= ' AND (u.user_lastvisit > 0 AND u.user_lastvisit < ' . $active_time . ')';
|
||||
$sql_where .= ' AND (u.user_last_active > 0 AND u.user_last_active < ' . $active_time . ')';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1713,7 +1722,7 @@ switch ($mode)
|
||||
{
|
||||
$row['session_time'] = $session_ary[$row['user_id']]['session_time'] ?? 0;
|
||||
$row['session_viewonline'] = $session_ary[$row['user_id']]['session_viewonline'] ?? 0;
|
||||
$row['last_visit'] = (!empty($row['session_time'])) ? $row['session_time'] : $row['user_lastvisit'];
|
||||
$row['last_visit'] = $row['user_last_active'] ?: $row['session_time'];
|
||||
|
||||
$id_cache[$row['user_id']] = $row;
|
||||
}
|
||||
|
25
phpBB/phpbb/.htaccess
Normal file
25
phpBB/phpbb/.htaccess
Normal file
@@ -0,0 +1,25 @@
|
||||
# With Apache 2.4 the "Order, Deny" syntax has been deprecated and moved from
|
||||
# module mod_authz_host to a new module called mod_access_compat (which may be
|
||||
# disabled) and a new "Require" syntax has been introduced to mod_authz_core.
|
||||
# We could just conditionally provide both versions, but unfortunately Apache
|
||||
# does not explicitly tell us its version if the module mod_version is not
|
||||
# available. In this case, we check for the availability of module
|
||||
# mod_authz_core (which should be on 2.4 or higher only) as a best guess.
|
||||
<IfModule mod_version.c>
|
||||
<IfVersion < 2.4>
|
||||
Order Allow,Deny
|
||||
Deny from All
|
||||
</IfVersion>
|
||||
<IfVersion >= 2.4>
|
||||
Require all denied
|
||||
</IfVersion>
|
||||
</IfModule>
|
||||
<IfModule !mod_version.c>
|
||||
<IfModule !mod_authz_core.c>
|
||||
Order Allow,Deny
|
||||
Deny from All
|
||||
</IfModule>
|
||||
<IfModule mod_authz_core.c>
|
||||
Require all denied
|
||||
</IfModule>
|
||||
</IfModule>
|
@@ -21,7 +21,7 @@ class gravatar extends \phpbb\avatar\driver\driver
|
||||
/**
|
||||
* The URL for the gravatar service
|
||||
*/
|
||||
const GRAVATAR_URL = '//secure.gravatar.com/avatar/';
|
||||
const GRAVATAR_URL = '//gravatar.com/avatar/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -29,7 +29,7 @@ class gravatar extends \phpbb\avatar\driver\driver
|
||||
public function get_data($row)
|
||||
{
|
||||
return array(
|
||||
'src' => $row['avatar'],
|
||||
'src' => $this->get_gravatar_url($row),
|
||||
'width' => $row['avatar_width'],
|
||||
'height' => $row['avatar_height'],
|
||||
);
|
||||
@@ -53,7 +53,7 @@ class gravatar extends \phpbb\avatar\driver\driver
|
||||
{
|
||||
$template->assign_vars(array(
|
||||
'AVATAR_GRAVATAR_WIDTH' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar_width']) ? $row['avatar_width'] : $request->variable('avatar_gravatar_width', ''),
|
||||
'AVATAR_GRAVATAR_HEIGHT' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar_height']) ? $row['avatar_height'] : $request->variable('avatar_gravatar_width', ''),
|
||||
'AVATAR_GRAVATAR_HEIGHT' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar_height']) ? $row['avatar_height'] : $request->variable('avatar_gravatar_height', ''),
|
||||
'AVATAR_GRAVATAR_EMAIL' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar']) ? $row['avatar'] : '',
|
||||
));
|
||||
|
||||
@@ -175,7 +175,7 @@ class gravatar extends \phpbb\avatar\driver\driver
|
||||
global $phpbb_dispatcher;
|
||||
|
||||
$url = self::GRAVATAR_URL;
|
||||
$url .= md5(strtolower(trim($row['avatar'])));
|
||||
$url .= hash('sha256', strtolower(trim($row['avatar'])));
|
||||
|
||||
if ($row['avatar_width'] || $row['avatar_height'])
|
||||
{
|
||||
|
40
phpBB/phpbb/cache/driver/file.php
vendored
40
phpBB/phpbb/cache/driver/file.php
vendored
@@ -330,6 +330,27 @@ class file extends \phpbb\cache\driver\base
|
||||
return $query_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup when loading invalid data global file
|
||||
*
|
||||
* @param string $file Filename
|
||||
* @param resource $handle
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function cleanup_invalid_data_global(string $file, $handle): void
|
||||
{
|
||||
if (is_resource($handle))
|
||||
{
|
||||
fclose($handle);
|
||||
}
|
||||
|
||||
$this->vars = $this->var_expires = [];
|
||||
$this->is_modified = false;
|
||||
|
||||
$this->remove_file($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read cached data from a specified file
|
||||
*
|
||||
@@ -372,14 +393,7 @@ class file extends \phpbb\cache\driver\base
|
||||
|
||||
if (!is_numeric($bytes) || ($bytes = (int) $bytes) === 0)
|
||||
{
|
||||
// We cannot process the file without a valid number of bytes
|
||||
// so we discard it
|
||||
fclose($handle);
|
||||
|
||||
$this->vars = $this->var_expires = array();
|
||||
$this->is_modified = false;
|
||||
|
||||
$this->remove_file($file);
|
||||
$this->cleanup_invalid_data_global($file, $handle);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -392,9 +406,17 @@ class file extends \phpbb\cache\driver\base
|
||||
}
|
||||
|
||||
$var_name = substr(fgets($handle), 0, -1);
|
||||
$data_length = $bytes - strlen($var_name);
|
||||
|
||||
if ($data_length <= 0)
|
||||
{
|
||||
$this->cleanup_invalid_data_global($file, $handle);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the length of bytes that consists of data.
|
||||
$data = fread($handle, $bytes - strlen($var_name));
|
||||
$data = fread($handle, $data_length);
|
||||
$data = @unserialize($data);
|
||||
|
||||
// Don't use the data if it was invalid
|
||||
|
10
phpBB/phpbb/cache/driver/redis.php
vendored
10
phpBB/phpbb/cache/driver/redis.php
vendored
@@ -129,6 +129,10 @@ class redis extends \phpbb\cache\driver\memory
|
||||
/**
|
||||
* Store data in the cache
|
||||
*
|
||||
* For the info, see https://phpredis.github.io/phpredis/Redis.html#method_set,
|
||||
* https://redis.io/docs/latest/commands/set/
|
||||
* and https://redis.io/docs/latest/commands/expire/#appendix-redis-expires
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @param mixed $data Data to store
|
||||
@@ -137,11 +141,7 @@ class redis extends \phpbb\cache\driver\memory
|
||||
*/
|
||||
function _write($var, $data, $ttl = 2592000)
|
||||
{
|
||||
if ($ttl == 0)
|
||||
{
|
||||
return $this->redis->set($var, $data);
|
||||
}
|
||||
return $this->redis->setex($var, $ttl, $data);
|
||||
return $this->redis->set($var, $data, ['EXAT' => time() + $ttl]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -359,6 +359,7 @@ class recaptcha_v3 extends captcha_abstract
|
||||
if ($result->isSuccess())
|
||||
{
|
||||
$this->solved = true;
|
||||
$this->confirm_code = $this->code;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@@ -100,7 +100,15 @@ class update_hashes extends \phpbb\console\command\command
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$old_hash = preg_replace('/^\$CP\$/', '', $row['user_password']);
|
||||
$new_hash = $this->passwords_manager->hash($old_hash, array($this->default_type));
|
||||
|
||||
// If stored hash type is unknown then it's md5 hash with no prefix
|
||||
// First rehash it using $H$ as hash type identifier (salted_md5)
|
||||
if (!$this->passwords_manager->detect_algorithm($old_hash))
|
||||
{
|
||||
$old_hash = $this->passwords_manager->hash($old_hash, '$H$');
|
||||
}
|
||||
|
||||
$new_hash = $this->passwords_manager->hash($old_hash, [$this->default_type]);
|
||||
|
||||
$sql = 'UPDATE ' . USERS_TABLE . "
|
||||
SET user_password = '" . $this->db->sql_escape($new_hash) . "'
|
||||
|
@@ -290,18 +290,17 @@ class add extends command
|
||||
{
|
||||
case USER_ACTIVATION_SELF:
|
||||
$email_template = 'user_welcome_inactive';
|
||||
$user_actkey = gen_rand_string(mt_rand(6, 10));
|
||||
break;
|
||||
case USER_ACTIVATION_ADMIN:
|
||||
$email_template = 'admin_welcome_inactive';
|
||||
$user_actkey = gen_rand_string(mt_rand(6, 10));
|
||||
break;
|
||||
default:
|
||||
$email_template = 'user_welcome';
|
||||
$user_actkey = '';
|
||||
break;
|
||||
}
|
||||
|
||||
$user_actkey = $this->get_activation_key($user_id);
|
||||
|
||||
if (!class_exists('messenger'))
|
||||
{
|
||||
require($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext);
|
||||
@@ -321,6 +320,35 @@ class add extends command
|
||||
$messenger->send(NOTIFY_EMAIL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user activation key
|
||||
*
|
||||
* @param int $user_id User ID
|
||||
*
|
||||
* @return string User activation key for user
|
||||
*/
|
||||
protected function get_activation_key(int $user_id): string
|
||||
{
|
||||
$user_actkey = '';
|
||||
|
||||
if ($this->config['require_activation'] == USER_ACTIVATION_SELF || $this->config['require_activation'] == USER_ACTIVATION_ADMIN)
|
||||
{
|
||||
$user_actkey = gen_rand_string(mt_rand(6, 10));
|
||||
|
||||
$sql_ary = [
|
||||
'user_actkey' => $user_actkey,
|
||||
'user_actkey_expiration' => user::get_token_expiration(),
|
||||
];
|
||||
|
||||
$sql = 'UPDATE ' . USERS_TABLE . '
|
||||
SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . '
|
||||
WHERE user_id = ' . (int) $user_id;
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
|
||||
return $user_actkey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to translate questions to the user
|
||||
*
|
||||
|
227
phpBB/phpbb/console/command/user/delete_id.php
Normal file
227
phpBB/phpbb/console/command/user/delete_id.php
Normal file
@@ -0,0 +1,227 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\console\command\user;
|
||||
|
||||
use phpbb\console\command\command;
|
||||
use phpbb\db\driver\driver_interface;
|
||||
use phpbb\language\language;
|
||||
use phpbb\log\log_interface;
|
||||
use phpbb\user;
|
||||
use phpbb\user_loader;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class delete_id extends command
|
||||
{
|
||||
/** @var driver_interface */
|
||||
protected $db;
|
||||
|
||||
/** @var language */
|
||||
protected $language;
|
||||
|
||||
/** @var log_interface */
|
||||
protected $log;
|
||||
|
||||
/** @var user_loader */
|
||||
protected $user_loader;
|
||||
|
||||
/** @var string Bots table */
|
||||
protected $bots_table;
|
||||
|
||||
/** @var string User group table */
|
||||
protected $user_group_table;
|
||||
|
||||
/** @var string Users table */
|
||||
protected $users_table;
|
||||
|
||||
/** @var string phpBB root path */
|
||||
protected $phpbb_root_path;
|
||||
|
||||
/** @var string PHP extension */
|
||||
protected $php_ext;
|
||||
|
||||
/**
|
||||
* Construct method
|
||||
*
|
||||
* @param driver_interface $db
|
||||
* @param language $language
|
||||
* @param log_interface $log
|
||||
* @param user $user
|
||||
* @param user_loader $user_loader
|
||||
* @param string $bots_table
|
||||
* @param string $user_group_table
|
||||
* @param string $users_table
|
||||
* @param string $phpbb_root_path
|
||||
* @param string $php_ext
|
||||
*/
|
||||
public function __construct(driver_interface $db, language $language, log_interface $log, user $user, user_loader $user_loader,
|
||||
string $bots_table, string $user_group_table, string $users_table, string $phpbb_root_path, string $php_ext)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->language = $language;
|
||||
$this->log = $log;
|
||||
$this->user_loader = $user_loader;
|
||||
$this->bots_table = $bots_table;
|
||||
$this->user_group_table = $user_group_table;
|
||||
$this->users_table = $users_table;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
$this->php_ext = $php_ext;
|
||||
|
||||
$this->language->add_lang('acp/users');
|
||||
parent::__construct($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command name and description
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName('user:delete_id')
|
||||
->setDescription($this->language->lang('CLI_DESCRIPTION_USER_DELETE_ID'))
|
||||
->addArgument(
|
||||
'user_ids',
|
||||
InputArgument::REQUIRED | InputArgument::IS_ARRAY,
|
||||
$this->language->lang('CLI_DESCRIPTION_USER_DELETE_ID_OPTION_ID')
|
||||
)
|
||||
->addOption(
|
||||
'delete-posts',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
$this->language->lang('CLI_DESCRIPTION_USER_DELETE_OPTION_POSTS')
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command user:delete_ids
|
||||
*
|
||||
* Deletes a list of user ids from the database. An option to delete the users' posts
|
||||
* is available, by default posts will be retained.
|
||||
*
|
||||
* @param InputInterface $input The input stream used to get the options
|
||||
* @param OutputInterface $output The output stream, used to print messages
|
||||
*
|
||||
* @return int 0 if all is well, 1 if any errors occurred
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$user_ids = $input->getArgument('user_ids');
|
||||
$mode = ($input->getOption('delete-posts')) ? 'remove' : 'retain';
|
||||
$deleted_users = 0;
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
if (count($user_ids) > 0)
|
||||
{
|
||||
$this->user_loader->load_users($user_ids);
|
||||
|
||||
$progress = $this->create_progress_bar(count($user_ids), $io, $output);
|
||||
$progress->setMessage($this->language->lang('CLI_USER_DELETE_ID_START'));
|
||||
$progress->start();
|
||||
|
||||
foreach ($user_ids as $user_id)
|
||||
{
|
||||
$user_row = $this->user_loader->get_user($user_id);
|
||||
|
||||
// Skip anonymous user
|
||||
if ($user_row['user_id'] == ANONYMOUS)
|
||||
{
|
||||
$progress->advance();
|
||||
continue;
|
||||
}
|
||||
else if ($user_row['user_type'] == USER_IGNORE)
|
||||
{
|
||||
$this->delete_bot_user($user_row);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!function_exists('user_delete'))
|
||||
{
|
||||
require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
|
||||
}
|
||||
|
||||
user_delete($mode, $user_row['user_id'], $user_row['username']);
|
||||
|
||||
$this->log->add('admin', ANONYMOUS, '', 'LOG_USER_DELETED', false, array($user_row['username']));
|
||||
}
|
||||
|
||||
$progress->advance();
|
||||
$deleted_users++;
|
||||
}
|
||||
|
||||
$progress->finish();
|
||||
|
||||
if ($deleted_users > 0)
|
||||
{
|
||||
$io->success($this->language->lang('CLI_USER_DELETE_ID_SUCCESS'));
|
||||
}
|
||||
}
|
||||
|
||||
if (!$deleted_users)
|
||||
{
|
||||
$io->note($this->language->lang('CLI_USER_DELETE_NONE'));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interacts with the user.
|
||||
* Confirm they really want to delete the account...last chance!
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*/
|
||||
protected function interact(InputInterface $input, OutputInterface $output): void
|
||||
{
|
||||
$helper = $this->getHelper('question');
|
||||
|
||||
$user_ids = $input->getArgument('user_ids');
|
||||
if (count($user_ids) > 0)
|
||||
{
|
||||
$question = new ConfirmationQuestion(
|
||||
$this->language->lang('CLI_USER_DELETE_ID_CONFIRM', implode(',', $user_ids)),
|
||||
false
|
||||
);
|
||||
|
||||
if (!$helper->ask($input, $output, $question))
|
||||
{
|
||||
$input->setArgument('user_ids', []);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a bot user
|
||||
*
|
||||
* @param array $user_row
|
||||
* @return void
|
||||
*/
|
||||
protected function delete_bot_user(array $user_row): void
|
||||
{
|
||||
$delete_tables = [$this->bots_table, $this->user_group_table, $this->users_table];
|
||||
foreach ($delete_tables as $table)
|
||||
{
|
||||
$sql = "DELETE FROM $table
|
||||
WHERE user_id = " . (int) $user_row['user_id'];
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
}
|
||||
}
|
@@ -85,9 +85,8 @@ class cron_runner_listener implements EventSubscriberInterface
|
||||
{
|
||||
$task->run();
|
||||
}
|
||||
|
||||
$this->cron_lock->release();
|
||||
}
|
||||
$this->cron_lock->release();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -107,7 +107,15 @@ class update_hashes extends \phpbb\cron\task\base
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$old_hash = preg_replace('/^\$CP\$/', '', $row['user_password']);
|
||||
$new_hash = $this->passwords_manager->hash($old_hash, array($this->default_type));
|
||||
|
||||
// If stored hash type is unknown then it's md5 hash with no prefix
|
||||
// First rehash it using $H$ as hash type identifier (salted_md5)
|
||||
if (!$this->passwords_manager->detect_algorithm($old_hash))
|
||||
{
|
||||
$old_hash = $this->passwords_manager->hash($old_hash, '$H$');
|
||||
}
|
||||
|
||||
$new_hash = $this->passwords_manager->hash($old_hash, [$this->default_type]);
|
||||
|
||||
// Increase number so we know that users were selected from the database
|
||||
$affected_rows++;
|
||||
|
@@ -155,7 +155,9 @@ class mysqli extends \phpbb\db\driver\mysql_base
|
||||
switch ($status)
|
||||
{
|
||||
case 'begin':
|
||||
return @mysqli_autocommit($this->db_connect_id, false);
|
||||
@mysqli_autocommit($this->db_connect_id, false);
|
||||
$result = @mysqli_begin_transaction($this->db_connect_id);
|
||||
return $result;
|
||||
break;
|
||||
|
||||
case 'commit':
|
||||
|
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\migration\data\v33x;
|
||||
|
||||
use phpbb\db\migration\migration;
|
||||
|
||||
class add_resend_activation_expiration extends migration
|
||||
{
|
||||
public static function depends_on(): array
|
||||
{
|
||||
return [
|
||||
'\phpbb\db\migration\data\v33x\v3311',
|
||||
];
|
||||
}
|
||||
|
||||
public function update_schema(): array
|
||||
{
|
||||
return [
|
||||
'add_columns' => [
|
||||
$this->table_prefix . 'users' => [
|
||||
'user_actkey_expiration' => ['TIMESTAMP', 0, 'after' => 'user_actkey'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function revert_schema(): array
|
||||
{
|
||||
return [
|
||||
'drop_columns' => [
|
||||
$this->table_prefix . 'users' => [
|
||||
'user_actkey_expiration',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
79
phpBB/phpbb/db/migration/data/v33x/add_user_last_active.php
Normal file
79
phpBB/phpbb/db/migration/data/v33x/add_user_last_active.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\migration\data\v33x;
|
||||
|
||||
use phpbb\db\migration\migration;
|
||||
|
||||
class add_user_last_active extends migration
|
||||
{
|
||||
public static function depends_on()
|
||||
{
|
||||
return [
|
||||
'\phpbb\db\migration\data\v33x\v3311',
|
||||
];
|
||||
}
|
||||
|
||||
public function update_schema()
|
||||
{
|
||||
return [
|
||||
'add_columns' => [
|
||||
$this->table_prefix . 'users' => [
|
||||
'user_last_active' => ['TIMESTAMP', 0, 'after' => 'user_lastvisit'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function revert_schema()
|
||||
{
|
||||
return [
|
||||
'drop_columns' => [
|
||||
$this->table_prefix . 'users' => ['user_last_active'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function update_data()
|
||||
{
|
||||
return [
|
||||
['custom', [[$this, 'set_user_last_active']]],
|
||||
];
|
||||
}
|
||||
|
||||
public function set_user_last_active($start = 0)
|
||||
{
|
||||
// Get maximum user id from database
|
||||
$sql = "SELECT MAX(user_id) AS max_user_id
|
||||
FROM {$this->table_prefix}users";
|
||||
$result = $this->db->sql_query($sql);
|
||||
$max_id = (int) $this->db->sql_fetchfield('max_user_id');
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if ($start > $max_id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep setting user_last_active time
|
||||
$next_start = $start + 10000;
|
||||
|
||||
$sql = 'UPDATE ' . $this->table_prefix . 'users
|
||||
SET user_last_active = user_lastvisit
|
||||
WHERE user_id > ' . (int) $start . '
|
||||
AND user_id <= ' . (int) ($next_start);
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
return $next_start;
|
||||
}
|
||||
}
|
38
phpBB/phpbb/db/migration/data/v33x/v3312.php
Normal file
38
phpBB/phpbb/db/migration/data/v33x/v3312.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\migration\data\v33x;
|
||||
|
||||
class v3312 extends \phpbb\db\migration\migration
|
||||
{
|
||||
public function effectively_installed()
|
||||
{
|
||||
return version_compare($this->config['version'], '3.3.12', '>=');
|
||||
}
|
||||
|
||||
public static function depends_on()
|
||||
{
|
||||
return [
|
||||
'\phpbb\db\migration\data\v33x\add_resend_activation_expiration',
|
||||
'\phpbb\db\migration\data\v33x\add_user_last_active',
|
||||
'\phpbb\db\migration\data\v33x\v3312rc1',
|
||||
];
|
||||
}
|
||||
|
||||
public function update_data()
|
||||
{
|
||||
return [
|
||||
['config.update', ['version', '3.3.12']],
|
||||
];
|
||||
}
|
||||
}
|
36
phpBB/phpbb/db/migration/data/v33x/v3313rc1.php
Normal file
36
phpBB/phpbb/db/migration/data/v33x/v3313rc1.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\migration\data\v33x;
|
||||
|
||||
class v3313rc1 extends \phpbb\db\migration\migration
|
||||
{
|
||||
public function effectively_installed()
|
||||
{
|
||||
return version_compare($this->config['version'], '3.3.13-RC1', '>=');
|
||||
}
|
||||
|
||||
public static function depends_on()
|
||||
{
|
||||
return [
|
||||
'\phpbb\db\migration\data\v33x\v3312',
|
||||
];
|
||||
}
|
||||
|
||||
public function update_data()
|
||||
{
|
||||
return [
|
||||
['config.update', ['version', '3.3.13-RC1']],
|
||||
];
|
||||
}
|
||||
}
|
@@ -435,15 +435,14 @@ class permission implements \phpbb\db\migration\tool\tool_interface
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if (empty($new_auth))
|
||||
$type = (string) $type; // Prevent PHP bug.
|
||||
if (empty($new_auth) || !in_array($type, ['role','group']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$current_auth = array();
|
||||
|
||||
$type = (string) $type; // Prevent PHP bug.
|
||||
|
||||
switch ($type)
|
||||
{
|
||||
case 'role':
|
||||
@@ -525,40 +524,32 @@ class permission implements \phpbb\db\migration\tool\tool_interface
|
||||
break;
|
||||
}
|
||||
|
||||
$sql_ary = array();
|
||||
switch ($type)
|
||||
$sql_ary = $auth_update_list = [];
|
||||
$table = $type == 'role' ? ACL_ROLES_DATA_TABLE : ACL_GROUPS_TABLE;
|
||||
foreach ($new_auth as $auth_option_id)
|
||||
{
|
||||
case 'role':
|
||||
foreach ($new_auth as $auth_option_id)
|
||||
{
|
||||
if (!isset($current_auth[$auth_option_id]))
|
||||
{
|
||||
$sql_ary[] = array(
|
||||
'role_id' => $role_id,
|
||||
'auth_option_id' => $auth_option_id,
|
||||
'auth_setting' => $has_permission,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!isset($current_auth[$auth_option_id]))
|
||||
{
|
||||
$sql_ary[] = [
|
||||
$type . '_id' => ${$type . '_id'},
|
||||
'auth_option_id' => $auth_option_id,
|
||||
'auth_setting' => (int) $has_permission,
|
||||
];
|
||||
}
|
||||
else
|
||||
{
|
||||
$auth_update_list[] = $auth_option_id;
|
||||
}
|
||||
}
|
||||
$this->db->sql_multi_insert($table, $sql_ary);
|
||||
|
||||
$this->db->sql_multi_insert(ACL_ROLES_DATA_TABLE, $sql_ary);
|
||||
break;
|
||||
|
||||
case 'group':
|
||||
foreach ($new_auth as $auth_option_id)
|
||||
{
|
||||
if (!isset($current_auth[$auth_option_id]))
|
||||
{
|
||||
$sql_ary[] = array(
|
||||
'group_id' => $group_id,
|
||||
'auth_option_id' => $auth_option_id,
|
||||
'auth_setting' => $has_permission,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->db->sql_multi_insert(ACL_GROUPS_TABLE, $sql_ary);
|
||||
break;
|
||||
if (count($auth_update_list))
|
||||
{
|
||||
$sql = 'UPDATE ' . $table . '
|
||||
SET auth_setting = ' . (int) $has_permission . '
|
||||
WHERE ' . $this->db->sql_in_set('auth_option_id', $auth_update_list) . '
|
||||
AND ' . $type . '_id = ' . (int) ${$type . '_id'};
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
|
||||
$this->auth->acl_clear_prefetch();
|
||||
|
@@ -31,6 +31,7 @@ class manager
|
||||
protected $php_ext;
|
||||
protected $extensions;
|
||||
protected $extension_table;
|
||||
protected $filesystem;
|
||||
protected $phpbb_root_path;
|
||||
protected $cache_name;
|
||||
|
||||
|
@@ -144,7 +144,7 @@ class install_extensions extends \phpbb\install\task_base
|
||||
if (isset($extensions[$ext_name]) && $extensions[$ext_name]['ext_active'])
|
||||
{
|
||||
// Create log
|
||||
$this->log->add('admin', ANONYMOUS, '', 'LOG_EXT_ENABLE', time(), array($ext_name));
|
||||
$this->log->add('admin', ANONYMOUS, $this->user->ip, 'LOG_EXT_ENABLE', time(), array($ext_name));
|
||||
$this->iohandler->add_success_message(array('CLI_EXTENSION_ENABLE_SUCCESS', $ext_name));
|
||||
}
|
||||
else
|
||||
|
@@ -174,7 +174,7 @@ class update_extensions extends task_base
|
||||
if (isset($extensions[$ext_name]) && $extensions[$ext_name]['ext_active'])
|
||||
{
|
||||
// Create log
|
||||
$this->log->add('admin', ANONYMOUS, '', 'LOG_EXT_UPDATE', time(), array($ext_name));
|
||||
$this->log->add('admin', ANONYMOUS, $this->user->ip, 'LOG_EXT_UPDATE', time(), array($ext_name));
|
||||
$this->iohandler->add_success_message(array('CLI_EXTENSION_UPDATE_SUCCESS', $ext_name));
|
||||
}
|
||||
else
|
||||
|
@@ -299,7 +299,11 @@ class fulltext_native extends \phpbb\search\base
|
||||
);
|
||||
|
||||
$keywords = preg_replace($match, $replace, $keywords);
|
||||
$num_keywords = count(explode(' ', $keywords));
|
||||
|
||||
// Ensure a space exists before +, - and | to make the split and count work correctly
|
||||
$countable_keywords = preg_replace('/(?<!\s)(\+|\-|\|)/', ' $1', $keywords);
|
||||
|
||||
$num_keywords = count(explode(' ', $countable_keywords));
|
||||
|
||||
// We limit the number of allowed keywords to minimize load on the database
|
||||
if ($this->config['max_num_search_keywords'] && $num_keywords > $this->config['max_num_search_keywords'])
|
||||
|
@@ -440,10 +440,10 @@ class session
|
||||
// Is user banned? Are they excluded? Won't return on ban, exists within method
|
||||
$this->check_ban_for_current_session($config);
|
||||
|
||||
// Update user last visit time accordingly, but in a minute or so
|
||||
if ((int) $this->data['session_time'] - (int) $this->data['user_lastvisit'] > 60)
|
||||
// Update user last active time accordingly, but in a minute or so
|
||||
if ($this->time_now - (int) $this->data['user_last_active'] > 60)
|
||||
{
|
||||
$this->update_user_lastvisit();
|
||||
$this->update_last_active_time();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -690,8 +690,8 @@ class session
|
||||
{
|
||||
$this->session_id = $this->data['session_id'];
|
||||
|
||||
// Only sync user last visit time in a minute or so after last session data update or if the page changes
|
||||
if ((int) $this->data['session_time'] - (int) $this->data['user_lastvisit'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page']))
|
||||
// Only update session DB a minute or so after last update or if page changes
|
||||
if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page']))
|
||||
{
|
||||
// Update the last visit time
|
||||
$this->update_user_lastvisit();
|
||||
@@ -818,22 +818,26 @@ class session
|
||||
$this->data['user_form_salt'] = unique_id();
|
||||
// Update the form key
|
||||
$sql = 'UPDATE ' . USERS_TABLE . '
|
||||
SET user_form_salt = \'' . $db->sql_escape($this->data['user_form_salt']) . '\'
|
||||
SET user_form_salt = \'' . $db->sql_escape($this->data['user_form_salt']) . '\',
|
||||
user_last_active = ' . (int) $this->time_now . '
|
||||
WHERE user_id = ' . (int) $this->data['user_id'];
|
||||
$db->sql_query($sql);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->update_last_active_time();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->data['session_time'] = $this->data['session_last_visit'] = $this->time_now;
|
||||
|
||||
$this->update_user_lastvisit();
|
||||
|
||||
$SID = '?sid=';
|
||||
$_SID = '';
|
||||
}
|
||||
|
||||
// Update the last visit time
|
||||
$this->update_user_lastvisit();
|
||||
|
||||
$session_data = $sql_ary;
|
||||
/**
|
||||
* Event to send new session data to extension
|
||||
@@ -960,8 +964,8 @@ class session
|
||||
}
|
||||
|
||||
/**
|
||||
* Get most recent session for each registered user to sync user last visit with it
|
||||
* Inner SELECT gets most recent sessions for each unique session_user_id
|
||||
* Get expired sessions for registered users, only most recent for each user
|
||||
* Inner SELECT gets most recent expired sessions for unique session_user_id
|
||||
* Outer SELECT gets data for them
|
||||
*/
|
||||
$sql_select = 'SELECT s1.session_page, s1.session_user_id, s1.session_time AS recent_time
|
||||
@@ -969,7 +973,8 @@ class session
|
||||
INNER JOIN (
|
||||
SELECT session_user_id, MAX(session_time) AS recent_time
|
||||
FROM ' . SESSIONS_TABLE . '
|
||||
WHERE session_user_id <> ' . ANONYMOUS . '
|
||||
WHERE session_time < ' . ($this->time_now - (int) $config['session_length']) . '
|
||||
AND session_user_id <> ' . ANONYMOUS . '
|
||||
GROUP BY session_user_id
|
||||
) AS s2
|
||||
ON s1.session_user_id = s2.session_user_id
|
||||
@@ -1807,7 +1812,26 @@ class session
|
||||
if (isset($this->data['session_time'], $this->data['user_id']))
|
||||
{
|
||||
$sql = 'UPDATE ' . USERS_TABLE . '
|
||||
SET user_lastvisit = ' . (int) $this->data['session_time'] . '
|
||||
SET user_lastvisit = ' . (int) $this->data['session_time'] . ',
|
||||
user_last_active = ' . $this->time_now . '
|
||||
WHERE user_id = ' . (int) $this->data['user_id'];
|
||||
$db->sql_query($sql);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user's last active time
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function update_last_active_time()
|
||||
{
|
||||
global $db;
|
||||
|
||||
if (isset($this->time_now, $this->data['user_id']))
|
||||
{
|
||||
$sql = 'UPDATE ' . USERS_TABLE . '
|
||||
SET user_last_active = ' . $this->time_now . '
|
||||
WHERE user_id = ' . (int) $this->data['user_id'];
|
||||
$db->sql_query($sql);
|
||||
}
|
||||
|
134
phpBB/phpbb/ucp/controller/delete_cookies.php
Normal file
134
phpBB/phpbb/ucp/controller/delete_cookies.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\ucp\controller;
|
||||
|
||||
use phpbb\config\config;
|
||||
use phpbb\event\dispatcher_interface;
|
||||
use phpbb\language\language;
|
||||
use phpbb\request\request_interface;
|
||||
use phpbb\user;
|
||||
|
||||
class delete_cookies
|
||||
{
|
||||
/** @var config */
|
||||
private $config;
|
||||
|
||||
/** @var dispatcher_interface */
|
||||
private $dispatcher;
|
||||
|
||||
/** @var language */
|
||||
private $language;
|
||||
|
||||
/** @var request_interface */
|
||||
private $request;
|
||||
|
||||
/** @var user */
|
||||
private $user;
|
||||
|
||||
/** @var string phpBB root path */
|
||||
private $phpbb_root_path;
|
||||
|
||||
/** @var string PHP extension */
|
||||
private $php_ext;
|
||||
|
||||
/**
|
||||
* Constructor for delete_cookies controller
|
||||
*
|
||||
* @param config $config
|
||||
* @param dispatcher_interface $dispatcher
|
||||
* @param language $language
|
||||
* @param request_interface $request
|
||||
* @param user $user
|
||||
*/
|
||||
public function __construct(config $config, dispatcher_interface $dispatcher, language $language, request_interface $request, user $user, string $phpbb_root_path, string $php_ext)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->language = $language;
|
||||
$this->request = $request;
|
||||
$this->user = $user;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
$this->php_ext = $php_ext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle delete cookies requests
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->language->add_lang(['ucp']);
|
||||
|
||||
// Delete Cookies with dynamic names (do NOT delete poll cookies)
|
||||
if (confirm_box(true))
|
||||
{
|
||||
$set_time = time() - 31536000;
|
||||
|
||||
foreach ($this->request->variable_names(request_interface::COOKIE) as $cookie_name)
|
||||
{
|
||||
// Only delete board cookies
|
||||
if (strpos($cookie_name, $this->config['cookie_name'] . '_') !== 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$cookie_name = str_replace($this->config['cookie_name'] . '_', '', $cookie_name);
|
||||
|
||||
/**
|
||||
* Event to save custom cookies from deletion
|
||||
*
|
||||
* @event core.ucp_delete_cookies
|
||||
* @var string cookie_name Cookie name to checking
|
||||
* @var bool retain_cookie Do we retain our cookie or not, true if retain
|
||||
* @since 3.1.3-RC1
|
||||
* @changed 3.3.13-RC1 Moved to new delete_cookies controller
|
||||
*/
|
||||
$retain_cookie = false;
|
||||
$vars = ['cookie_name', 'retain_cookie'];
|
||||
extract($this->dispatcher->trigger_event('core.ucp_delete_cookies', compact($vars)));
|
||||
if ($retain_cookie)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Polls are stored as {cookie_name}_poll_{topic_id}, cookie_name_ got removed, therefore checking for poll_
|
||||
if (strpos($cookie_name, 'poll_') !== 0)
|
||||
{
|
||||
$this->user->set_cookie($cookie_name, '', $set_time);
|
||||
}
|
||||
}
|
||||
|
||||
$this->user->set_cookie('track', '', $set_time);
|
||||
$this->user->set_cookie('u', '', $set_time);
|
||||
$this->user->set_cookie('k', '', $set_time);
|
||||
$this->user->set_cookie('sid', '', $set_time);
|
||||
|
||||
// We destroy the session here, the user will be logged out nevertheless
|
||||
$this->user->session_kill();
|
||||
$this->user->session_begin();
|
||||
|
||||
meta_refresh(3, append_sid("{$this->phpbb_root_path}index.$this->php_ext"));
|
||||
|
||||
$message = $this->language->lang('COOKIES_DELETED') . '<br><br>' . $this->language->lang('RETURN_INDEX', '<a href="' . append_sid("{$this->phpbb_root_path}index.$this->php_ext") . '">', '</a>');
|
||||
trigger_error($message);
|
||||
}
|
||||
else
|
||||
{
|
||||
confirm_box(false, 'DELETE_COOKIES', '');
|
||||
}
|
||||
|
||||
redirect(append_sid("{$this->phpbb_root_path}index.$this->php_ext"));
|
||||
}
|
||||
}
|
@@ -242,7 +242,7 @@ class reset_password
|
||||
|
||||
$sql_ary = [
|
||||
'reset_token' => $reset_token,
|
||||
'reset_token_expiration' => strtotime('+1 day'),
|
||||
'reset_token_expiration' => $this->user::get_token_expiration(),
|
||||
];
|
||||
|
||||
$sql = 'UPDATE ' . $this->users_table . '
|
||||
|
@@ -57,7 +57,7 @@ class user extends \phpbb\session
|
||||
* @param \phpbb\language\language $lang phpBB's Language loader
|
||||
* @param string $datetime_class Class name of datetime class
|
||||
*/
|
||||
function __construct(\phpbb\language\language $lang, $datetime_class)
|
||||
public function __construct(\phpbb\language\language $lang, $datetime_class)
|
||||
{
|
||||
global $phpbb_root_path;
|
||||
|
||||
@@ -78,6 +78,16 @@ class user extends \phpbb\session
|
||||
return $this->is_setup_flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get expiration time for user tokens, e.g. activation or reset password tokens
|
||||
*
|
||||
* @return int Expiration for user tokens
|
||||
*/
|
||||
public static function get_token_expiration(): int
|
||||
{
|
||||
return strtotime('+1 day') ?: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic getter for BC compatibility
|
||||
*
|
||||
|
@@ -848,6 +848,7 @@ if ($save && $user->data['is_registered'] && $auth->acl_get('u_savedrafts') && (
|
||||
'disable_smilies' => false,
|
||||
'disable_magic_url' => false,
|
||||
'attach_sig' => true,
|
||||
'notify' => false,
|
||||
'lock_topic' => false,
|
||||
|
||||
'topic_type' => POST_NORMAL,
|
||||
@@ -1966,7 +1967,7 @@ $page_data = array(
|
||||
'S_BBCODE_CHECKED' => ($bbcode_checked) ? ' checked="checked"' : '',
|
||||
'S_SMILIES_ALLOWED' => $smilies_status,
|
||||
'S_SMILIES_CHECKED' => ($smilies_checked) ? ' checked="checked"' : '',
|
||||
'S_SIG_ALLOWED' => ($auth->acl_get('f_sigs', $forum_id) && $config['allow_sig'] && $user->data['is_registered']) ? true : false,
|
||||
'S_SIG_ALLOWED' => ($user->data['is_registered'] && $config['allow_sig'] && $auth->acl_get('f_sigs', $forum_id) && $auth->acl_get('u_sig')) ? true : false,
|
||||
'S_SIGNATURE_CHECKED' => ($sig_checked) ? ' checked="checked"' : '',
|
||||
'S_NOTIFY_ALLOWED' => (!$user->data['is_registered'] || ($mode == 'edit' && $user->data['user_id'] != $post_data['poster_id']) || !$config['allow_topic_notify'] || !$config['email_enable']) ? false : true,
|
||||
'S_NOTIFY_CHECKED' => ($notify_checked) ? ' checked="checked"' : '',
|
||||
|
@@ -21,8 +21,8 @@
|
||||
# General Information about this style
|
||||
name = prosilver
|
||||
copyright = © phpBB Limited, 2007
|
||||
style_version = 3.3.12
|
||||
phpbb_version = 3.3.12
|
||||
style_version = 3.3.13
|
||||
phpbb_version = 3.3.13
|
||||
|
||||
# Defining a different template bitfield
|
||||
# template_bitfield = //g=
|
||||
|
@@ -337,30 +337,6 @@ $('[data-ajax]').each(function() {
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent accidental double submission of form
|
||||
$('[data-prevent-flood] input[type=submit]').click(function(event) {
|
||||
const $submitButton = $(this); // Store the button element
|
||||
const $form = $submitButton.closest('form');
|
||||
|
||||
// Always add the disabled class for visual feedback
|
||||
$submitButton.addClass('disabled');
|
||||
|
||||
// Submit form if it hasn't been submitted yet
|
||||
if (!$form.prop('data-form-submitted')) {
|
||||
$form.prop('data-form-submitted', true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent default submission for subsequent clicks within 5 seconds
|
||||
event.preventDefault();
|
||||
|
||||
setTimeout(() => {
|
||||
$form.prop('removeProp', 'data-form-submitted');
|
||||
$submitButton.removeClass('disabled'); // Re-enable after 5 seconds
|
||||
}, 5000);
|
||||
});
|
||||
|
||||
/**
|
||||
* This simply appends #preview to the action of the
|
||||
* QR action when you click the Full Editor & Preview button
|
||||
|
@@ -329,17 +329,6 @@ function parseDocument($container) {
|
||||
}, 100);
|
||||
});
|
||||
|
||||
/**
|
||||
* Adjust HTML code for IE8 and older versions
|
||||
*/
|
||||
// if (oldBrowser) {
|
||||
// // Fix .linklist.bulletin lists
|
||||
// $container
|
||||
// .find('ul.linklist.bulletin > li')
|
||||
// .filter(':first-child, .rightside:last-child')
|
||||
// .addClass('no-bulletin');
|
||||
// }
|
||||
|
||||
/**
|
||||
* Resize navigation (breadcrumbs) block to keep all links on same line
|
||||
*/
|
||||
|
@@ -78,6 +78,7 @@
|
||||
<p class="author"><span><i class="icon fa-file fa-fw icon-lightgray icon-md" aria-hidden="true"></i><span class="sr-only">{MINI_POST_IMG}</span></span> {L_POSTED} {L_POST_BY_AUTHOR} {POST_AUTHOR_FULL} » {POST_DATE}</p>
|
||||
<!-- ENDIF -->
|
||||
|
||||
{% if S_CAN_APPROVE %}
|
||||
<!-- IF S_POST_UNAPPROVED -->
|
||||
<form method="post" id="mcp_approve" action="{U_APPROVE_ACTION}">
|
||||
|
||||
@@ -101,6 +102,7 @@
|
||||
</p>
|
||||
</form>
|
||||
<!-- ENDIF -->
|
||||
{% endif %}
|
||||
|
||||
{% if S_POST_REPORTED and not S_MCP_REPORT %}
|
||||
<p class="post-notice reported">
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<div class="inner">
|
||||
|
||||
<!-- IF AVATAR_IMG -->
|
||||
<dl class="left-box">
|
||||
<dl class="left-box avatar-rank-container">
|
||||
<dt class="profile-avatar">{AVATAR_IMG}</dt>
|
||||
<!-- EVENT memberlist_view_rank_avatar_before -->
|
||||
<!-- IF RANK_TITLE --><dd style="text-align: center;">{RANK_TITLE}</dd><!-- ENDIF -->
|
||||
|
@@ -40,8 +40,10 @@
|
||||
<!-- END notifications -->
|
||||
</ul>
|
||||
|
||||
{% EVENT notification_dropdown_footer_before %}
|
||||
<div class="footer">
|
||||
<a href="{U_VIEW_ALL_NOTIFICATIONS}"><span>{L_SEE_ALL}</span></a>
|
||||
</div>
|
||||
{% EVENT notification_dropdown_footer_after %}
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -100,7 +100,7 @@
|
||||
<!-- IF not S_SHOW_DRAFTS and not $SIG_EDIT eq 1 -->
|
||||
<div class="panel bg2">
|
||||
<div class="inner">
|
||||
<fieldset class="submit-buttons" data-prevent-flood>
|
||||
<fieldset class="submit-buttons">
|
||||
{S_HIDDEN_ADDRESS_FIELD}
|
||||
{S_HIDDEN_FIELDS}
|
||||
<!-- EVENT posting_editor_submit_buttons -->
|
||||
|
@@ -31,7 +31,11 @@
|
||||
<ul class="recipients">
|
||||
<!-- BEGIN to_recipient -->
|
||||
<li>
|
||||
<!-- IF not S_EDIT_POST --><input type="submit" name="remove_{to_recipient.TYPE}[{to_recipient.UG_ID}]" value="x" class="button2" /><!-- ENDIF -->
|
||||
<!-- IF not S_EDIT_POST -->
|
||||
<button type="submit" name="remove_{to_recipient.TYPE}[{to_recipient.UG_ID}]">
|
||||
<i class="icon fa-times icon-red" aria-hidden="true"></i><span class="sr-only">{L_REMOVE}</span>
|
||||
</button>
|
||||
<!-- ENDIF -->
|
||||
<!-- IF to_recipient.IS_GROUP --><a href="{to_recipient.U_VIEW}" style="color: {{ to_recipient.COLOUR }}"><strong>{to_recipient.NAME}</strong></a><!-- ELSE -->{to_recipient.NAME_FULL}<!-- ENDIF -->
|
||||
</li>
|
||||
<!-- END to_recipient -->
|
||||
@@ -48,7 +52,11 @@
|
||||
<ul class="recipients">
|
||||
<!-- BEGIN bcc_recipient -->
|
||||
<li>
|
||||
<!-- IF not S_EDIT_POST --><input type="submit" name="remove_{bcc_recipient.TYPE}[{bcc_recipient.UG_ID}]" value="x" class="button2" /><!-- ENDIF -->
|
||||
<!-- IF not S_EDIT_POST -->
|
||||
<button type="submit" name="remove_{bcc_recipient.TYPE}[{bcc_recipient.UG_ID}]">
|
||||
<i class="icon fa-times icon-red" aria-hidden="true"></i><span class="sr-only">{L_REMOVE}</span>
|
||||
</button>
|
||||
<!-- ENDIF -->
|
||||
<!-- IF bcc_recipient.IS_GROUP --><a href="{bcc_recipient.U_VIEW}" style="color: {{ bcc_recipient.COLOUR }}"><strong>{bcc_recipient.NAME}</strong></a><!-- ELSE -->{bcc_recipient.NAME_FULL}<!-- ENDIF -->
|
||||
</li>
|
||||
<!-- END bcc_recipient -->
|
||||
@@ -69,8 +77,12 @@
|
||||
<ul class="recipients">
|
||||
<!-- BEGIN to_recipient -->
|
||||
<li>
|
||||
<!-- IF to_recipient.IS_GROUP --><a href="{to_recipient.U_VIEW}"><strong>{to_recipient.NAME}</strong></a><!-- ELSE -->{to_recipient.NAME_FULL}<!-- ENDIF -->
|
||||
<!-- IF not S_EDIT_POST --><input type="submit" name="remove_{to_recipient.TYPE}[{to_recipient.UG_ID}]" value="x" class="button2" /><!-- ENDIF -->
|
||||
<!-- IF not S_EDIT_POST -->
|
||||
<button type="submit" name="remove_{to_recipient.TYPE}[{to_recipient.UG_ID}]">
|
||||
<i class="icon fa-times icon-red" aria-hidden="true"></i><span class="sr-only">{L_REMOVE}</span>
|
||||
</button>
|
||||
<!-- ENDIF -->
|
||||
<!-- IF to_recipient.IS_GROUP --><a href="{to_recipient.U_VIEW}"><strong>{to_recipient.NAME}</strong></a><!-- ELSE -->{to_recipient.NAME_FULL}<!-- ENDIF -->
|
||||
</li>
|
||||
<!-- END to_recipient -->
|
||||
</ul>
|
||||
|
@@ -52,6 +52,7 @@
|
||||
<h3>{L_GROUP_SETTINGS_SAVE}</h3>
|
||||
|
||||
<fieldset>
|
||||
<!-- EVENT ucp_group_settings_before -->
|
||||
<dl>
|
||||
<dt><label for="group_colour">{L_GROUP_COLOR}{L_COLON}</label><br /><span>{L_GROUP_COLOR_EXPLAIN}</span></dt>
|
||||
<dd>
|
||||
@@ -65,6 +66,7 @@
|
||||
<dt><label for="group_rank">{L_GROUP_RANK}{L_COLON}</label></dt>
|
||||
<dd><select name="group_rank" id="group_rank">{S_RANK_OPTIONS}</select></dd>
|
||||
</dl>
|
||||
<!-- EVENT ucp_group_settings_after -->
|
||||
</fieldset>
|
||||
|
||||
</div>
|
||||
|
@@ -23,6 +23,7 @@
|
||||
<label for="smilies0"><input type="radio" name="smilies" id="smilies0" value="0"<!-- IF not S_SMILIES --> checked="checked"<!-- ENDIF --> /> {L_NO}</label>
|
||||
</dd>
|
||||
</dl>
|
||||
{% if S_SIG_ALLOWED %}
|
||||
<dl>
|
||||
<dt><label for="sig1">{L_DEFAULT_ADD_SIG}{L_COLON}</label></dt>
|
||||
<dd>
|
||||
@@ -30,6 +31,7 @@
|
||||
<label for="sig0"><input type="radio" name="sig" id="sig0" value="0"<!-- IF not S_SIG --> checked="checked"<!-- ENDIF --> /> {L_NO}</label>
|
||||
</dd>
|
||||
</dl>
|
||||
{% endif %}
|
||||
<dl>
|
||||
<dt><label for="notify1">{L_DEFAULT_NOTIFY}{L_COLON}</label></dt>
|
||||
<dd>
|
||||
|
@@ -731,6 +731,10 @@ table.info tbody th {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.avatar-rank-container {
|
||||
max-width: 20%;
|
||||
}
|
||||
|
||||
.left-box.profile-details {
|
||||
width: 80%;
|
||||
}
|
||||
@@ -780,12 +784,6 @@ fieldset.fields1 dd.recipients {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
fieldset.fields1 ul.recipients input.button2 {
|
||||
font-size: 0.8em;
|
||||
margin-right: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
fieldset.fields1 dl.pmlist > dt {
|
||||
width: auto !important;
|
||||
}
|
||||
|
@@ -412,6 +412,10 @@
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.avatar-rank-container {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* Polls
|
||||
----------------------------------------*/
|
||||
fieldset.polls dt {
|
||||
|
@@ -10,7 +10,7 @@
|
||||
@import url("normalize.css?hash=48eb3f89");
|
||||
@import url("base.css?hash=7c5543be");
|
||||
@import url("utilities.css?hash=d8f72c42");
|
||||
@import url("common.css?hash=a9741ba1");
|
||||
@import url("common.css?hash=843d5d5f");
|
||||
@import url("links.css?hash=18286e16");
|
||||
@import url("content.css?hash=d0e24377");
|
||||
@import url("buttons.css?hash=56f0d25f");
|
||||
@@ -18,4 +18,4 @@
|
||||
@import url("forms.css?hash=9016b55c");
|
||||
@import url("icons.css?hash=64da33ce");
|
||||
@import url("colours.css?hash=fcb2f289");
|
||||
@import url("responsive.css?hash=91525545");
|
||||
@import url("responsive.css?hash=c9d32cba");
|
||||
|
@@ -154,68 +154,11 @@ switch ($mode)
|
||||
break;
|
||||
|
||||
case 'delete_cookies':
|
||||
/** @var \phpbb\controller\helper $controller_helper */
|
||||
$controller_helper = $phpbb_container->get('controller.helper');
|
||||
|
||||
// Delete Cookies with dynamic names (do NOT delete poll cookies)
|
||||
if (confirm_box(true))
|
||||
{
|
||||
$set_time = time() - 31536000;
|
||||
|
||||
foreach ($request->variable_names(\phpbb\request\request_interface::COOKIE) as $cookie_name)
|
||||
{
|
||||
$cookie_data = $request->variable($cookie_name, '', true, \phpbb\request\request_interface::COOKIE);
|
||||
|
||||
// Only delete board cookies, no other ones...
|
||||
if (strpos($cookie_name, $config['cookie_name'] . '_') !== 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$cookie_name = str_replace($config['cookie_name'] . '_', '', $cookie_name);
|
||||
|
||||
/**
|
||||
* Event to save custom cookies from deletion
|
||||
*
|
||||
* @event core.ucp_delete_cookies
|
||||
* @var string cookie_name Cookie name to checking
|
||||
* @var bool retain_cookie Do we retain our cookie or not, true if retain
|
||||
* @since 3.1.3-RC1
|
||||
*/
|
||||
$retain_cookie = false;
|
||||
$vars = array('cookie_name', 'retain_cookie');
|
||||
extract($phpbb_dispatcher->trigger_event('core.ucp_delete_cookies', compact($vars)));
|
||||
if ($retain_cookie)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Polls are stored as {cookie_name}_poll_{topic_id}, cookie_name_ got removed, therefore checking for poll_
|
||||
if (strpos($cookie_name, 'poll_') !== 0)
|
||||
{
|
||||
$user->set_cookie($cookie_name, '', $set_time);
|
||||
}
|
||||
}
|
||||
|
||||
$user->set_cookie('track', '', $set_time);
|
||||
$user->set_cookie('u', '', $set_time);
|
||||
$user->set_cookie('k', '', $set_time);
|
||||
$user->set_cookie('sid', '', $set_time);
|
||||
|
||||
// We destroy the session here, the user will be logged out nevertheless
|
||||
$user->session_kill();
|
||||
$user->session_begin();
|
||||
|
||||
meta_refresh(3, append_sid("{$phpbb_root_path}index.$phpEx"));
|
||||
|
||||
$message = $user->lang['COOKIES_DELETED'] . '<br /><br />' . sprintf($user->lang['RETURN_INDEX'], '<a href="' . append_sid("{$phpbb_root_path}index.$phpEx") . '">', '</a>');
|
||||
trigger_error($message);
|
||||
}
|
||||
else
|
||||
{
|
||||
confirm_box(false, 'DELETE_COOKIES', '');
|
||||
}
|
||||
|
||||
redirect(append_sid("{$phpbb_root_path}index.$phpEx"));
|
||||
|
||||
// Redirect to controller
|
||||
redirect($controller_helper->route('phpbb_ucp_delete_cookies_controller'));
|
||||
break;
|
||||
|
||||
case 'switch_perm':
|
||||
|
@@ -2071,7 +2071,7 @@ for ($i = 0, $end = count($post_list); $i < $end; ++$i)
|
||||
'U_EMAIL' => $user_cache[$poster_id]['email'],
|
||||
'U_JABBER' => $user_cache[$poster_id]['jabber'],
|
||||
|
||||
'U_APPROVE_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", "i=queue&p={$row['post_id']}&redirect=" . urlencode(str_replace('&', '&', $viewtopic_url . '&p=' . $row['post_id'] . '#p' . $row['post_id']))),
|
||||
'U_APPROVE_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", "i=queue&p={$row['post_id']}&f={$row['forum_id']}&redirect=" . urlencode(str_replace('&', '&', $viewtopic_url . '&p=' . $row['post_id'] . '#p' . $row['post_id']))),
|
||||
'U_REPORT' => ($auth->acl_get('f_report', $forum_id)) ? $phpbb_container->get('controller.helper')->route('phpbb_report_post_controller', array('id' => $row['post_id'])) : '',
|
||||
'U_MCP_REPORT' => ($auth->acl_get('m_report', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&mode=report_details&p=' . $row['post_id'], true, $user->session_id) : '',
|
||||
'U_MCP_APPROVE' => ($auth->acl_get('m_approve', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=approve_details&p=' . $row['post_id'], true, $user->session_id) : '',
|
||||
|
@@ -28,6 +28,33 @@
|
||||
</requestFiltering>
|
||||
</security>
|
||||
</system.webServer>
|
||||
<location path="config">
|
||||
<system.webServer>
|
||||
<security>
|
||||
<requestFiltering>
|
||||
<hiddenSegments>
|
||||
<add segment="default" />
|
||||
<add segment="development" />
|
||||
<add segment="installer" />
|
||||
<add segment="production" />
|
||||
<add segment="test" />
|
||||
<add segment=".htaccess" />
|
||||
</hiddenSegments>
|
||||
</requestFiltering>
|
||||
</security>
|
||||
</system.webServer>
|
||||
</location>
|
||||
<location path="ext">
|
||||
<system.webServer>
|
||||
<security>
|
||||
<requestFiltering>
|
||||
<hiddenSegments>
|
||||
<remove segment="phpbb" />
|
||||
</hiddenSegments>
|
||||
</requestFiltering>
|
||||
</security>
|
||||
</system.webServer>
|
||||
</location>
|
||||
<location path="images/avatars">
|
||||
<system.webServer>
|
||||
<security>
|
||||
|
@@ -115,6 +115,7 @@ class phpbb_auth_provider_apache_test extends phpbb_database_test_case
|
||||
'user_email' => 'example@example.com',
|
||||
'user_birthday' => '',
|
||||
'user_lastvisit' => 0,
|
||||
'user_last_active' => 0,
|
||||
'user_lastmark' => 0,
|
||||
'user_lastpost_time' => 0,
|
||||
'user_lastpage' => '',
|
||||
@@ -161,6 +162,7 @@ class phpbb_auth_provider_apache_test extends phpbb_database_test_case
|
||||
'user_sig_bbcode_bitfield' => '',
|
||||
'user_jabber' => '',
|
||||
'user_actkey' => '',
|
||||
'user_actkey_expiration' => 0,
|
||||
'user_newpasswd' => '',
|
||||
'user_form_salt' => '',
|
||||
'user_new' => 1,
|
||||
|
217
tests/avatar/driver_gravatar_test.php
Normal file
217
tests/avatar/driver_gravatar_test.php
Normal file
@@ -0,0 +1,217 @@
|
||||
<?php
|
||||
|
||||
use phpbb\avatar\driver\gravatar;
|
||||
use phpbb\request\request;
|
||||
use phpbb\request\request_interface;
|
||||
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
class phpbb_avatar_driver_gravatar_test extends \phpbb_database_test_case
|
||||
{
|
||||
|
||||
/** @var \phpbb\config\config */
|
||||
private $config;
|
||||
|
||||
/** @var gravatar */
|
||||
private $gravatar;
|
||||
|
||||
/** @var request_interface */
|
||||
private $request;
|
||||
|
||||
/** @var \phpbb\template\template */
|
||||
private $template;
|
||||
|
||||
/** @var \phpbb\user */
|
||||
private $user;
|
||||
|
||||
private $template_data = [];
|
||||
|
||||
public function getDataSet()
|
||||
{
|
||||
return $this->createXMLDataSet(__DIR__ . '/fixtures/users.xml');
|
||||
}
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
global $phpbb_root_path, $phpEx;
|
||||
|
||||
$this->config = new \phpbb\config\config(array());
|
||||
$this->request = $this->getMockBuilder(request::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['get_super_global'])
|
||||
->getMock();
|
||||
$this->request->method('get_super_global')
|
||||
->willReturn([]);
|
||||
$this->template = $this->getMockBuilder(\phpbb\template\twig\twig::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['assign_vars'])
|
||||
->getMock();
|
||||
$this->template->method('assign_vars')
|
||||
->will($this->returnCallback([$this, 'template_assign_vars']));
|
||||
$this->user = $this->getMockBuilder(\phpbb\user::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$filesystem = new \phpbb\filesystem\filesystem();
|
||||
$imagesize = new \FastImageSize\FastImageSize();
|
||||
$cache = $this->createMock('\phpbb\cache\driver\driver_interface');
|
||||
$path_helper = new \phpbb\path_helper(
|
||||
new \phpbb\symfony_request(
|
||||
$this->request
|
||||
),
|
||||
$filesystem,
|
||||
$this->request,
|
||||
$phpbb_root_path,
|
||||
$phpEx
|
||||
);
|
||||
|
||||
global $phpbb_dispatcher;
|
||||
$phpbb_dispatcher = $this->getMockBuilder(\phpbb\event\dispatcher::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['trigger_event'])
|
||||
->getMock();
|
||||
$phpbb_dispatcher->method('trigger_event')
|
||||
->willReturnArgument(1);
|
||||
|
||||
$this->gravatar = new gravatar($this->config, $imagesize, $phpbb_root_path, $phpEx, $path_helper, $cache);
|
||||
$this->gravatar->set_name('avatar.driver.gravatar');
|
||||
}
|
||||
|
||||
public function template_assign_vars($data)
|
||||
{
|
||||
$this->template_data = array_merge($this->template_data, $data);
|
||||
}
|
||||
|
||||
public function data_prepare_form(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
// Only default empty values, no request data
|
||||
[
|
||||
'AVATAR_GRAVATAR_WIDTH' => '',
|
||||
'AVATAR_GRAVATAR_HEIGHT' => '',
|
||||
'AVATAR_GRAVATAR_EMAIL' => '',
|
||||
],
|
||||
[],
|
||||
[
|
||||
'avatar_type' => '',
|
||||
'avatar_width' => '',
|
||||
'avatar_height' => '',
|
||||
]
|
||||
],
|
||||
[
|
||||
// Only default empty values, request data set
|
||||
[
|
||||
'AVATAR_GRAVATAR_WIDTH' => '80',
|
||||
'AVATAR_GRAVATAR_HEIGHT' => '90',
|
||||
'AVATAR_GRAVATAR_EMAIL' => '',
|
||||
],
|
||||
[
|
||||
request_interface::POST => [
|
||||
'avatar_type' => 'avatar.driver.gravatar',
|
||||
'avatar_gravatar_width' => '80',
|
||||
'avatar_gravatar_height' => '90',
|
||||
],
|
||||
],
|
||||
[
|
||||
'avatar_type' => '',
|
||||
'avatar_width' => '80',
|
||||
'avatar_height' => '90',
|
||||
]
|
||||
],
|
||||
[
|
||||
// Only default empty values, request data set
|
||||
[
|
||||
'AVATAR_GRAVATAR_WIDTH' => '70',
|
||||
'AVATAR_GRAVATAR_HEIGHT' => '60',
|
||||
'AVATAR_GRAVATAR_EMAIL' => 'bar@foo.com',
|
||||
],
|
||||
[
|
||||
request_interface::POST => [
|
||||
'avatar_type' => 'avatar.driver.gravatar',
|
||||
'avatar_gravatar_width' => '80',
|
||||
'avatar_gravatar_height' => '90',
|
||||
],
|
||||
],
|
||||
[
|
||||
'avatar_type' => 'avatar.driver.gravatar',
|
||||
'avatar' => 'bar@foo.com',
|
||||
'avatar_width' => '70',
|
||||
'avatar_height' => '60',
|
||||
]
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider data_prepare_form
|
||||
*/
|
||||
public function test_prepare_form($expected_vars, $request_data, $row)
|
||||
{
|
||||
$error = [];
|
||||
$this->template_data = [];
|
||||
|
||||
$request = $this->getMockBuilder(request::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['get_super_global'])
|
||||
->getMock();
|
||||
$request->method('get_super_global')
|
||||
->willReturn([]);
|
||||
|
||||
$requestInputReflection = new \ReflectionProperty($request, 'input');
|
||||
$requestInputReflection->setAccessible(true);
|
||||
$request_data[request_interface::GET] = $request_data[request_interface::GET] ?? [];
|
||||
$request_data[request_interface::POST] = $request_data[request_interface::POST] ?? [];
|
||||
$request_data[request_interface::REQUEST] = $request_data[request_interface::GET] + $request_data[request_interface::POST];
|
||||
$requestInputReflection->setValue($request, $request_data);
|
||||
$requestTypeCastHelperReflection = new \ReflectionProperty($request, 'type_cast_helper');
|
||||
$requestTypeCastHelperReflection->setAccessible(true);
|
||||
$requestTypeCastHelperReflection->setValue($request, new \phpbb\request\type_cast_helper());
|
||||
|
||||
$this->gravatar->prepare_form($request, $this->template, $this->user, $row, $error);
|
||||
|
||||
// Error not touched by gravatar
|
||||
$this->assertEquals([], $error);
|
||||
|
||||
$this->assertEquals($expected_vars, $this->template_data);
|
||||
}
|
||||
|
||||
public function test_gravatar_misc(): void
|
||||
{
|
||||
$this->assertEquals('ucp_avatar_options_gravatar.html', $this->gravatar->get_template_name());
|
||||
$this->assertEquals('acp_avatar_options_gravatar.html', $this->gravatar->get_acp_template_name());
|
||||
|
||||
$row = [
|
||||
'avatar_type' => 'avatar.driver.gravatar',
|
||||
'avatar' => 'bar@foo.com',
|
||||
'avatar_width' => '70',
|
||||
'avatar_height' => '60',
|
||||
];
|
||||
$this->assertEquals('<img src="//gravatar.com/avatar/e0ee9d02824d4320a999507150c5b8a371c635c41f645ba3a7205f36384dc199?s=70" width="70" height="60" alt="" />', $this->gravatar->get_custom_html($this->user, $row));
|
||||
}
|
||||
|
||||
public function test_get_data(): void
|
||||
{
|
||||
$row = [
|
||||
'avatar_type' => 'avatar.driver.gravatar',
|
||||
'avatar' => 'bar@foo.com',
|
||||
'avatar_width' => '70',
|
||||
'avatar_height' => '60',
|
||||
];
|
||||
|
||||
$this->assertEquals([
|
||||
'src' => '//gravatar.com/avatar/e0ee9d02824d4320a999507150c5b8a371c635c41f645ba3a7205f36384dc199?s=70',
|
||||
'width' => '70',
|
||||
'height' => '60',
|
||||
], $this->gravatar->get_data($row));
|
||||
}
|
||||
}
|
145
tests/cache/file_driver_test.php
vendored
145
tests/cache/file_driver_test.php
vendored
@@ -17,6 +17,9 @@ class phpbb_cache_file_driver_test extends phpbb_cache_common_test_case
|
||||
{
|
||||
private $cache_dir;
|
||||
|
||||
/** @var \phpbb\cache\driver\file */
|
||||
private $cache_file;
|
||||
|
||||
public function getDataSet()
|
||||
{
|
||||
return $this->createXMLDataSet(__DIR__ . '/fixtures/config.xml');
|
||||
@@ -36,7 +39,8 @@ class phpbb_cache_file_driver_test extends phpbb_cache_common_test_case
|
||||
}
|
||||
$this->create_cache_dir();
|
||||
|
||||
$this->driver = new \phpbb\cache\driver\file($this->cache_dir);
|
||||
$this->cache_file = new \phpbb\cache\driver\file($this->cache_dir);
|
||||
$this->driver = $this->cache_file;
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
@@ -49,6 +53,145 @@ class phpbb_cache_file_driver_test extends phpbb_cache_common_test_case
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function test_read_not_readable()
|
||||
{
|
||||
if (strtolower(substr(PHP_OS, 0, 3)) === 'win')
|
||||
{
|
||||
$this->markTestSkipped('Unable to test unreadable files on Windows');
|
||||
}
|
||||
|
||||
global $phpEx;
|
||||
|
||||
// Create file that is not readable
|
||||
$this->assertTrue($this->cache_file->_write('unreadable', 'foo', time() + 86400));
|
||||
|
||||
$filename = "{$this->cache_dir}unreadable.$phpEx";
|
||||
@chmod($filename, 0000);
|
||||
$this->assertFalse($this->cache_file->_read('unreadable'));
|
||||
@chmod($filename, 0600);
|
||||
$this->assertNotFalse($this->cache_file->_read('unreadable'));
|
||||
}
|
||||
|
||||
public function test_read_data_global_invalid()
|
||||
{
|
||||
global $phpEx;
|
||||
|
||||
$reflectionCacheVars = new \ReflectionProperty($this->cache_file, 'vars');
|
||||
$reflectionCacheVars->setAccessible(true);
|
||||
$reflectionCacheVars->setValue($this->cache_file, ['foo' => 'bar']);
|
||||
|
||||
$reflectionCacheVarExpires = new \ReflectionProperty($this->cache_file, 'var_expires');
|
||||
$reflectionCacheVarExpires->setAccessible(true);
|
||||
$reflectionCacheVarExpires->setValue($this->cache_file, ['foo' => time() + 86400]);
|
||||
|
||||
// Create file in invalid format
|
||||
$this->assertTrue($this->cache_file->_write('data_global'));
|
||||
$filename = "{$this->cache_dir}data_global.$phpEx";
|
||||
$cache_data = file_get_contents($filename);
|
||||
// Force negative read when retrieving data_global
|
||||
$cache_data = str_replace("\n13\n", "\n1\n", $cache_data);
|
||||
file_put_contents($filename, $cache_data);
|
||||
|
||||
$this->assertFalse($this->cache_file->_read('data_global'));
|
||||
}
|
||||
|
||||
public function test_read_data_global_zero_bytes()
|
||||
{
|
||||
global $phpEx;
|
||||
|
||||
$reflectionCacheVars = new \ReflectionProperty($this->cache_file, 'vars');
|
||||
$reflectionCacheVars->setAccessible(true);
|
||||
$reflectionCacheVars->setValue($this->cache_file, ['foo' => 'bar']);
|
||||
|
||||
$reflectionCacheVarExpires = new \ReflectionProperty($this->cache_file, 'var_expires');
|
||||
$reflectionCacheVarExpires->setAccessible(true);
|
||||
$reflectionCacheVarExpires->setValue($this->cache_file, ['foo' => time() + 86400]);
|
||||
|
||||
// Create file in invalid format
|
||||
$this->assertTrue($this->cache_file->_write('data_global'));
|
||||
$filename = "{$this->cache_dir}data_global.$phpEx";
|
||||
$cache_data = file_get_contents($filename);
|
||||
// Force negative read when retrieving data_global
|
||||
$cache_data = str_replace("\n13\n", "\n0\n", $cache_data);
|
||||
file_put_contents($filename, $cache_data);
|
||||
|
||||
$this->assertFalse($this->cache_file->_read('data_global'));
|
||||
}
|
||||
|
||||
public function test_read_data_global_hex_bytes()
|
||||
{
|
||||
global $phpEx;
|
||||
|
||||
$reflectionCacheVars = new \ReflectionProperty($this->cache_file, 'vars');
|
||||
$reflectionCacheVars->setAccessible(true);
|
||||
$reflectionCacheVars->setValue($this->cache_file, ['foo' => 'bar']);
|
||||
|
||||
$reflectionCacheVarExpires = new \ReflectionProperty($this->cache_file, 'var_expires');
|
||||
$reflectionCacheVarExpires->setAccessible(true);
|
||||
$reflectionCacheVarExpires->setValue($this->cache_file, ['foo' => time() + 86400]);
|
||||
|
||||
// Create file in invalid format
|
||||
$this->assertTrue($this->cache_file->_write('data_global'));
|
||||
$filename = "{$this->cache_dir}data_global.$phpEx";
|
||||
$cache_data = file_get_contents($filename);
|
||||
// Force negative read when retrieving data_global
|
||||
$cache_data = str_replace("\n13\n", "\nA\n", $cache_data);
|
||||
file_put_contents($filename, $cache_data);
|
||||
|
||||
$this->assertFalse($this->cache_file->_read('data_global'));
|
||||
}
|
||||
|
||||
public function test_read_data_global_expired()
|
||||
{
|
||||
$reflectionCacheVars = new \ReflectionProperty($this->cache_file, 'vars');
|
||||
$reflectionCacheVars->setAccessible(true);
|
||||
$reflectionCacheVars->setValue($this->cache_file, ['foo' => 'bar']);
|
||||
|
||||
$reflectionCacheVarExpires = new \ReflectionProperty($this->cache_file, 'var_expires');
|
||||
$reflectionCacheVarExpires->setAccessible(true);
|
||||
$reflectionCacheVarExpires->setValue($this->cache_file, ['foo' => time() - 86400]);
|
||||
|
||||
// Create file in invalid format
|
||||
$this->assertTrue($this->cache_file->_write('data_global'));
|
||||
|
||||
// Clear data
|
||||
$reflectionCacheVars->setValue($this->cache_file, []);
|
||||
$reflectionCacheVarExpires->setValue($this->cache_file, []);
|
||||
|
||||
$this->assertTrue($this->cache_file->_read('data_global'));
|
||||
|
||||
// Check data, should be empty
|
||||
$this->assertEquals([], $reflectionCacheVars->getValue($this->cache_file));
|
||||
}
|
||||
|
||||
public function test_read_data_global()
|
||||
{
|
||||
$reflectionCacheVars = new \ReflectionProperty($this->cache_file, 'vars');
|
||||
$reflectionCacheVars->setAccessible(true);
|
||||
$expectedVars = ['foo' => 'bar'];
|
||||
$reflectionCacheVars->setValue($this->cache_file, $expectedVars);
|
||||
|
||||
$reflectionCacheVarExpires = new \ReflectionProperty($this->cache_file, 'var_expires');
|
||||
$reflectionCacheVarExpires->setAccessible(true);
|
||||
$expectedVarExpires = ['foo' => time() + 86400];
|
||||
$reflectionCacheVarExpires->setValue($this->cache_file, $expectedVarExpires);
|
||||
|
||||
// Create file in invalid format
|
||||
$this->assertTrue($this->cache_file->_write('data_global'));
|
||||
|
||||
// Clear data
|
||||
$reflectionCacheVars->setValue($this->cache_file, []);
|
||||
$reflectionCacheVarExpires->setValue($this->cache_file, []);
|
||||
$this->assertEquals([], $reflectionCacheVars->getValue($this->cache_file));
|
||||
$this->assertEquals([], $reflectionCacheVarExpires->getValue($this->cache_file));
|
||||
|
||||
$this->assertTrue($this->cache_file->_read('data_global'));
|
||||
|
||||
// Check data, should be empty
|
||||
$this->assertEquals($expectedVars, $reflectionCacheVars->getValue($this->cache_file));
|
||||
$this->assertEquals($expectedVarExpires, $reflectionCacheVarExpires->getValue($this->cache_file));
|
||||
}
|
||||
|
||||
private function create_cache_dir()
|
||||
{
|
||||
$this->get_test_case_helpers()->makedirs($this->cache_dir);
|
||||
|
129
tests/console/user/delete_id_test.php
Normal file
129
tests/console/user/delete_id_test.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
use phpbb\console\command\user\delete_id;
|
||||
|
||||
require_once __DIR__ . '/base.php';
|
||||
|
||||
class phpbb_console_user_delete_ids_test extends phpbb_console_user_base
|
||||
{
|
||||
public function get_command_tester()
|
||||
{
|
||||
$application = new Application();
|
||||
$application->add(new delete_id(
|
||||
$this->db,
|
||||
$this->language,
|
||||
$this->log,
|
||||
$this->user,
|
||||
$this->user_loader,
|
||||
BOTS_TABLE,
|
||||
USER_GROUP_TABLE,
|
||||
USERS_TABLE,
|
||||
$this->phpbb_root_path,
|
||||
$this->php_ext
|
||||
));
|
||||
|
||||
$command = $application->find('user:delete_id');
|
||||
$this->command_name = $command->getName();
|
||||
$this->question = $command->getHelper('question');
|
||||
|
||||
return new CommandTester($command);
|
||||
}
|
||||
|
||||
public function test_delete()
|
||||
{
|
||||
$command_tester = $this->get_command_tester();
|
||||
|
||||
$command_tester->setInputs(['yes', '']);
|
||||
|
||||
$command_tester->execute(array(
|
||||
'command' => $this->command_name,
|
||||
'user_ids' => [3, 4],
|
||||
'--delete-posts' => false,
|
||||
));
|
||||
|
||||
$this->assertNull($this->get_user_id('Test'));
|
||||
$this->assertNull($this->get_user_id('Test 2'));
|
||||
$this->assertStringContainsString('CLI_USER_DELETE_ID_SUCCESS', $command_tester->getDisplay());
|
||||
}
|
||||
|
||||
public function test_delete_one()
|
||||
{
|
||||
$command_tester = $this->get_command_tester();
|
||||
|
||||
$command_tester->setInputs(['yes', '']);
|
||||
|
||||
$command_tester->execute(array(
|
||||
'command' => $this->command_name,
|
||||
'user_ids' => [3],
|
||||
'--delete-posts' => false,
|
||||
));
|
||||
|
||||
$this->assertNull($this->get_user_id('Test'));
|
||||
$this->assertNotNull($this->get_user_id('Test 2'));
|
||||
$this->assertStringContainsString('CLI_USER_DELETE_ID_SUCCESS', $command_tester->getDisplay());
|
||||
}
|
||||
|
||||
public function test_delete_bot()
|
||||
{
|
||||
$command_tester = $this->get_command_tester();
|
||||
|
||||
$this->assertNotNull($this->get_user_id('Test Bot'));
|
||||
|
||||
$command_tester->setInputs(['yes', '']);
|
||||
|
||||
$command_tester->execute(array(
|
||||
'command' => $this->command_name,
|
||||
'user_ids' => [6],
|
||||
'--delete-posts' => false,
|
||||
));
|
||||
|
||||
$this->assertNull($this->get_user_id('Test Bot'));
|
||||
$this->assertStringContainsString('CLI_USER_DELETE_ID_SUCCESS', $command_tester->getDisplay());
|
||||
}
|
||||
|
||||
public function test_delete_non_user()
|
||||
{
|
||||
$command_tester = $this->get_command_tester();
|
||||
|
||||
$command_tester->setInputs(['yes', '']);
|
||||
|
||||
$command_tester->execute(array(
|
||||
'command' => $this->command_name,
|
||||
'user_ids' => [999],
|
||||
'--delete-posts' => false,
|
||||
));
|
||||
|
||||
$this->assertStringContainsString('CLI_USER_DELETE_NONE', $command_tester->getDisplay());
|
||||
}
|
||||
|
||||
public function test_delete_cancel()
|
||||
{
|
||||
$command_tester = $this->get_command_tester();
|
||||
|
||||
$this->assertEquals(3, $this->get_user_id('Test'));
|
||||
|
||||
$command_tester->setInputs(['no', '']);
|
||||
|
||||
$command_tester->execute(array(
|
||||
'command' => $this->command_name,
|
||||
'user_ids' => [3, 4],
|
||||
'--delete-posts' => false,
|
||||
));
|
||||
|
||||
$this->assertNotNull($this->get_user_id('Test'));
|
||||
$this->assertNotNull($this->get_user_id('Test 2'));
|
||||
}
|
||||
}
|
@@ -47,6 +47,14 @@
|
||||
<value></value>
|
||||
<value>0</value>
|
||||
</row>
|
||||
<row>
|
||||
<value>6</value>
|
||||
<value></value>
|
||||
<value>Test Bot</value>
|
||||
<value>Test Bot</value>
|
||||
<value></value>
|
||||
<value>2</value>
|
||||
</row>
|
||||
</table>
|
||||
<table name="phpbb_groups">
|
||||
<column>group_id</column>
|
||||
@@ -59,5 +67,23 @@
|
||||
<value>3</value>
|
||||
<value>foobar</value>
|
||||
</row>
|
||||
<row>
|
||||
<value>6</value>
|
||||
<value>BOTS</value>
|
||||
<value>3</value>
|
||||
<value></value>
|
||||
</row>
|
||||
</table>
|
||||
<table name="phpbb_user_group">
|
||||
<column>group_id</column>
|
||||
<column>user_id</column>
|
||||
<column>group_leader</column>
|
||||
<column>user_pending</column>
|
||||
<row>
|
||||
<value>6</value>
|
||||
<value>6</value>
|
||||
<value>0</value>
|
||||
<value>0</value>
|
||||
</row>
|
||||
</table>
|
||||
</dataset>
|
||||
|
@@ -28,6 +28,12 @@ class phpbb_dbal_migrator_tool_permission_role_test extends phpbb_database_test_
|
||||
'ADMINISTRATORS' => 5,
|
||||
];
|
||||
|
||||
public $role_ids = [
|
||||
'ROLE_ADMIN_STANDARD' => 1,
|
||||
'ROLE_USER_FULL' => 5,
|
||||
'ROLE_MOD_FULL' => 10,
|
||||
];
|
||||
|
||||
public $new_roles = [
|
||||
[
|
||||
'ROLE_ADMIN_NEW',
|
||||
@@ -196,4 +202,32 @@ class phpbb_dbal_migrator_tool_permission_role_test extends phpbb_database_test_
|
||||
$this->assertFalse($this->db->sql_fetchfield('auth_role_id'));
|
||||
$this->db->sql_freeresult($result);
|
||||
}
|
||||
|
||||
public function test_copied_permission_set()
|
||||
{
|
||||
$sql = 'SELECT rdt.auth_setting
|
||||
FROM ' . ACL_OPTIONS_TABLE. ' ot, ' . ACL_ROLES_DATA_TABLE . ' rdt
|
||||
WHERE rdt.role_id = ' . $this->role_ids['ROLE_ADMIN_STANDARD'] . "
|
||||
AND auth_option = 'u_copied_permission'
|
||||
AND ot.auth_option_id = rdt.auth_option_id";
|
||||
|
||||
// Add new local 'u_copied_permission' copied from 'u_test'
|
||||
// It should be added to the ROLE_ADMIN_STANDARD role automatically similar to 'u_test' permission
|
||||
$this->tool->add('u_copied_permission', false, 'u_test');
|
||||
$this->assertEquals(true, $this->tool->exists('u_copied_permission', false));
|
||||
|
||||
// Copied permission setting should be equal to what it was copied from
|
||||
$result = $this->db->sql_query($sql);
|
||||
$this->assertEquals(0, $this->db->sql_fetchfield('auth_setting'));
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
// Set new permission for copied auth option for the role
|
||||
$this->tool->permission_set('ROLE_ADMIN_STANDARD', 'u_copied_permission', 'role', true);
|
||||
|
||||
// Copied permission setting should be updated
|
||||
$result = $this->db->sql_query($sql);
|
||||
$this->assertEquals(1, $this->db->sql_fetchfield('auth_setting'));
|
||||
$this->db->sql_freeresult($result);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -73,6 +73,67 @@ class phpbb_dbal_write_test extends phpbb_database_test_case
|
||||
$db->sql_freeresult($result);
|
||||
}
|
||||
|
||||
public function test_delete_rollback()
|
||||
{
|
||||
$db = $this->new_dbal();
|
||||
|
||||
$is_myisam = false;
|
||||
if ($db->get_sql_layer() === 'mysqli')
|
||||
{
|
||||
$table_status = $db->get_table_status('phpbb_config');
|
||||
$is_myisam = isset($table_status['Engine']) && $table_status['Engine'] === 'MyISAM';
|
||||
}
|
||||
|
||||
$db->sql_transaction('begin');
|
||||
|
||||
$sql = "DELETE FROM phpbb_config
|
||||
WHERE config_name = 'config1'";
|
||||
$db->sql_query($sql);
|
||||
|
||||
// Rollback and check that nothing was changed
|
||||
$db->sql_transaction('rollback');
|
||||
|
||||
$sql = 'SELECT *
|
||||
FROM phpbb_config';
|
||||
$result = $db->sql_query($sql);
|
||||
$rows = $db->sql_fetchrowset($result);
|
||||
$db->sql_freeresult($result);
|
||||
|
||||
if (!$is_myisam)
|
||||
{
|
||||
$this->assertEquals(2, count($rows));
|
||||
$this->assertEquals('config1', $rows[0]['config_name']);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Rollback does not work on MyISAM
|
||||
$this->assertEquals(1, count($rows));
|
||||
$this->assertEquals('config2', $rows[0]['config_name']);
|
||||
|
||||
// Restore deleted config value on MyISAM
|
||||
$sql = "INSERT INTO phpbb_config (config_name, config_value, is_dynamic) VALUES ('config1', 'foo', 0)";
|
||||
$db->sql_query($sql);
|
||||
}
|
||||
|
||||
$db->sql_transaction('begin');
|
||||
|
||||
$sql = "DELETE FROM phpbb_config
|
||||
WHERE config_name = 'config1'";
|
||||
$db->sql_query($sql);
|
||||
|
||||
// Commit and check that data was actually changed
|
||||
$db->sql_transaction('commit');
|
||||
|
||||
$sql = 'SELECT *
|
||||
FROM phpbb_config';
|
||||
$result = $db->sql_query($sql);
|
||||
$rows = $db->sql_fetchrowset($result);
|
||||
$db->sql_freeresult($result);
|
||||
|
||||
$this->assertEquals(1, count($rows));
|
||||
$this->assertEquals('config2', $rows[0]['config_name']);
|
||||
}
|
||||
|
||||
public function test_multiple_insert()
|
||||
{
|
||||
$db = $this->new_dbal();
|
||||
|
@@ -146,7 +146,7 @@ abstract class phpbb_functional_search_base extends phpbb_functional_test_case
|
||||
|
||||
foreach (['', 'a', 't', 'f', 'i', 's'] as $sort_key)
|
||||
{
|
||||
$this->assert_search_found('phpbb3+installation', 1, 3, $sort_key);
|
||||
$this->assert_search_found('phpbb3+installation', 1, 4, $sort_key);
|
||||
$this->assert_search_found('foosubject+barsearch', 1, 2, $sort_key);
|
||||
$this->assert_search_found('barsearch-testing', 1, 2, $sort_key); // test hyphen ignored
|
||||
$this->assert_search_found('barsearch+-+testing', 1, 2, $sort_key); // test hyphen wrapped with space ignored
|
||||
|
70
tests/functional/switch_permissions_test.php
Normal file
70
tests/functional/switch_permissions_test.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @group functional
|
||||
*/
|
||||
class phpbb_functional_switch_permissions_test extends phpbb_functional_test_case
|
||||
{
|
||||
private const TEST_USER = 'switch-permissions-test';
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->login();
|
||||
$this->admin_login();
|
||||
|
||||
$this->add_lang(['common', 'ucp']);
|
||||
}
|
||||
|
||||
public function test_switch_permissions()
|
||||
{
|
||||
$user_id = $this->create_user(self::TEST_USER);
|
||||
|
||||
// Open user administration page for new user
|
||||
$crawler = self::request('GET', "adm/index.php?i=users&mode=overview&u={$user_id}&sid={$this->sid}");
|
||||
|
||||
// Use permissions
|
||||
$link = $crawler->selectLink($this->lang('USE_PERMISSIONS'))->link();
|
||||
$crawler = self::$client->click($link);
|
||||
|
||||
// Check that we switched permissions to test user
|
||||
$this->assertStringContainsString(
|
||||
str_replace('<br />', '<br>', $this->lang('PERMISSIONS_TRANSFERRED', self::TEST_USER)),
|
||||
$crawler->html()
|
||||
);
|
||||
|
||||
// Check that ACP pages get forced to acp main with restore permission info
|
||||
$this->add_lang('acp/common');
|
||||
$crawler = self::request('GET', "adm/index.php?i=users&mode=overview&u={$user_id}&sid={$this->sid}");
|
||||
$this->assertStringContainsString(
|
||||
$this->lang('PERMISSIONS_TRANSFERRED'),
|
||||
$crawler->text()
|
||||
);
|
||||
|
||||
// Check that restore permissions link exists
|
||||
$crawler = self::$client->request('GET', '../index.php?sid=' . $this->sid);
|
||||
$this->assertStringContainsString(
|
||||
$this->lang('RESTORE_PERMISSIONS'),
|
||||
$crawler->text()
|
||||
);
|
||||
|
||||
// Check that restore permissions works
|
||||
$crawler = self::$client->request('GET', 'ucp.php?mode=restore_perm&sid=' . $this->sid);
|
||||
$this->assertStringContainsString(
|
||||
$this->lang('PERMISSIONS_RESTORED'),
|
||||
$crawler->text()
|
||||
);
|
||||
}
|
||||
}
|
@@ -18,10 +18,14 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca
|
||||
{
|
||||
protected $user_data;
|
||||
|
||||
protected const TEST_USER = 'reset-password-test-user';
|
||||
|
||||
protected const TEST_EMAIL = 'reset-password-test-user@test.com';
|
||||
|
||||
public function test_password_reset()
|
||||
{
|
||||
$this->add_lang('ucp');
|
||||
$user_id = $this->create_user('reset-password-test-user', 'reset-password-test-user@test.com');
|
||||
$user_id = $this->create_user(self::TEST_USER, self::TEST_EMAIL);
|
||||
|
||||
// test without email
|
||||
$crawler = self::request('GET', "ucp.php?mode=sendpassword&sid={$this->sid}");
|
||||
@@ -41,13 +45,13 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca
|
||||
// test with correct email
|
||||
$crawler = self::request('GET', "app.php/user/forgot_password?sid={$this->sid}");
|
||||
$form = $crawler->selectButton('submit')->form(array(
|
||||
'email' => 'reset-password-test-user@test.com',
|
||||
'email' => self::TEST_EMAIL,
|
||||
));
|
||||
$crawler = self::submit($form);
|
||||
$this->assertContainsLang('PASSWORD_RESET_LINK_SENT', $crawler->text());
|
||||
|
||||
// Check if columns in database were updated for password reset
|
||||
$this->get_user_data('reset-password-test-user');
|
||||
$this->get_user_data(self::TEST_USER);
|
||||
$this->assertNotEmpty($this->user_data['reset_token']);
|
||||
$this->assertNotEmpty($this->user_data['reset_token_expiration']);
|
||||
$reset_token = $this->user_data['reset_token'];
|
||||
@@ -56,31 +60,31 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca
|
||||
// Check that reset token is only created once per day
|
||||
$crawler = self::request('GET', "app.php/user/forgot_password?sid={$this->sid}");
|
||||
$form = $crawler->selectButton('submit')->form(array(
|
||||
'email' => 'reset-password-test-user@test.com',
|
||||
'email' => self::TEST_EMAIL,
|
||||
));
|
||||
$crawler = self::submit($form);
|
||||
$this->assertContainsLang('PASSWORD_RESET_LINK_SENT', $crawler->text());
|
||||
|
||||
$this->get_user_data('reset-password-test-user');
|
||||
$this->get_user_data(self::TEST_USER);
|
||||
$this->assertNotEmpty($this->user_data['reset_token']);
|
||||
$this->assertNotEmpty($this->user_data['reset_token_expiration']);
|
||||
$this->assertEquals($reset_token, $this->user_data['reset_token']);
|
||||
$this->assertEquals($reset_token_expiration, $this->user_data['reset_token_expiration']);
|
||||
|
||||
// Create another user with the same email
|
||||
$this->create_user('reset-password-test-user1', 'reset-password-test-user@test.com');
|
||||
$this->create_user('reset-password-test-user1', self::TEST_EMAIL);
|
||||
|
||||
// Test that username is now also required
|
||||
$crawler = self::request('GET', "app.php/user/forgot_password?sid={$this->sid}");
|
||||
$form = $crawler->selectButton('submit')->form(array(
|
||||
'email' => 'reset-password-test-user@test.com',
|
||||
'email' => self::TEST_EMAIL,
|
||||
));
|
||||
$crawler = self::submit($form);
|
||||
$this->assertContainsLang('EMAIL_NOT_UNIQUE', $crawler->text());
|
||||
|
||||
// Provide both username and email
|
||||
$form = $crawler->selectButton('submit')->form(array(
|
||||
'email' => 'reset-password-test-user@test.com',
|
||||
'email' => self::TEST_EMAIL,
|
||||
'username' => 'reset-password-test-user1',
|
||||
));
|
||||
$crawler = self::submit($form);
|
||||
@@ -95,7 +99,7 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca
|
||||
|
||||
public function test_login_after_reset()
|
||||
{
|
||||
$this->login('reset-password-test-user');
|
||||
$this->login(self::TEST_USER);
|
||||
}
|
||||
|
||||
public function data_reset_user_password()
|
||||
@@ -117,7 +121,7 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca
|
||||
public function test_reset_user_password($expected, $user_id, $token)
|
||||
{
|
||||
$this->add_lang('ucp');
|
||||
$this->get_user_data('reset-password-test-user');
|
||||
$this->get_user_data(self::TEST_USER);
|
||||
$user_id = !$user_id ? $this->user_data['user_id'] : $user_id;
|
||||
$token = !$token ? $this->user_data['reset_token'] : $token;
|
||||
|
||||
@@ -131,8 +135,8 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca
|
||||
{
|
||||
$form = $crawler->filter('input[type=submit]')->form();
|
||||
$values = array_merge($form->getValues(), [
|
||||
'new_password' => 'reset-password-test-user',
|
||||
'new_password_confirm' => 'reset-password-test-user',
|
||||
'new_password' => self::TEST_USER,
|
||||
'new_password_confirm' => self::TEST_USER,
|
||||
]);
|
||||
$crawler = self::submit($form, $values);
|
||||
$this->assertContainsLang('PASSWORD_RESET', $crawler->text());
|
||||
@@ -146,7 +150,7 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca
|
||||
$this->assertStringContainsString($this->lang('LOGIN_EXPLAIN_UCP'), $crawler->filter('html')->text());
|
||||
|
||||
$form = $crawler->selectButton($this->lang('LOGIN'))->form();
|
||||
$crawler = self::submit($form, array('username' => 'reset-password-test-user', 'password' => 'reset-password-test-user'));
|
||||
$crawler = self::submit($form, array('username' => self::TEST_USER, 'password' => self::TEST_USER));
|
||||
$this->assertStringNotContainsString($this->lang('LOGIN'), $crawler->filter('.navbar')->text());
|
||||
|
||||
$cookies = self::$cookieJar->all();
|
||||
@@ -167,17 +171,17 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca
|
||||
|
||||
$form = $crawler->selectButton($this->lang('LOGIN'))->form();
|
||||
// Try logging in with the old password
|
||||
$crawler = self::submit($form, array('username' => 'reset-password-test-user', 'password' => 'reset-password-test-userreset-password-test-user'));
|
||||
$crawler = self::submit($form, array('username' => self::TEST_USER, 'password' => 'reset-password-test-userreset-password-test-user'));
|
||||
$this->assertStringContainsString($this->lang('LOGIN_ERROR_PASSWORD', '', ''), $crawler->filter('html')->text());
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends test_login
|
||||
*/
|
||||
public function test_acivateAfterDeactivate()
|
||||
public function test_activateAfterDeactivate()
|
||||
{
|
||||
// User is active, actkey should not exist
|
||||
$this->get_user_data('reset-password-test-user');
|
||||
$this->get_user_data(self::TEST_USER);
|
||||
$this->assertEmpty($this->user_data['user_actkey']);
|
||||
|
||||
$this->login();
|
||||
@@ -189,7 +193,7 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca
|
||||
$this->assertContainsLang('FIND_USERNAME', $crawler->filter('html')->text());
|
||||
|
||||
$form = $crawler->selectButton('Submit')->form();
|
||||
$crawler = self::submit($form, array('username' => 'reset-password-test-user'));
|
||||
$crawler = self::submit($form, array('username' => self::TEST_USER));
|
||||
|
||||
// Deactivate account and go back to overview of current user
|
||||
$this->assertContainsLang('USER_TOOLS', $crawler->filter('html')->text());
|
||||
@@ -201,7 +205,7 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca
|
||||
$crawler = self::request('GET', preg_replace('#(.+)(adm/index.php.+)#', '$2', $link->getUri()));
|
||||
|
||||
// Ensure again that actkey is empty after deactivation
|
||||
$this->get_user_data('reset-password-test-user');
|
||||
$this->get_user_data(self::TEST_USER);
|
||||
$this->assertEmpty($this->user_data['user_actkey']);
|
||||
|
||||
// Force reactivation of account and check that act key is not empty anymore
|
||||
@@ -210,8 +214,50 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca
|
||||
$crawler = self::submit($form, array('action' => 'reactivate'));
|
||||
$this->assertContainsLang('FORCE_REACTIVATION_SUCCESS', $crawler->filter('html')->text());
|
||||
|
||||
$this->get_user_data('reset-password-test-user');
|
||||
$this->get_user_data(self::TEST_USER);
|
||||
$this->assertNotEmpty($this->user_data['user_actkey']);
|
||||
|
||||
// Logout and try resending activation email, account is deactivated though
|
||||
$this->logout();
|
||||
$this->add_lang('ucp');
|
||||
|
||||
$crawler = self::request('GET', 'ucp.php?mode=resend_act');
|
||||
$this->assertContainsLang('UCP_RESEND', $crawler->filter('html')->text());
|
||||
$form = $crawler->filter('input[name=submit]')->selectButton('Submit')->form();
|
||||
$crawler = self::submit($form, [
|
||||
'username' => self::TEST_USER,
|
||||
'email' => self::TEST_EMAIL,
|
||||
]);
|
||||
$this->assertContainsLang('ACCOUNT_DEACTIVATED', $crawler->filter('html')->text());
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends test_activateAfterDeactivate
|
||||
*/
|
||||
public function test_resendActivation()
|
||||
{
|
||||
// User is deactivated and should have actkey, actkey should not exist
|
||||
$this->get_user_data(self::TEST_USER);
|
||||
$this->assertNotEmpty($this->user_data['user_actkey']);
|
||||
|
||||
// Change reason for inactivity
|
||||
$db = $this->get_db();
|
||||
|
||||
$sql = 'UPDATE ' . USERS_TABLE . '
|
||||
SET user_inactive_reason = ' . INACTIVE_REMIND . '
|
||||
WHERE user_id = ' . (int) $this->user_data['user_id'];
|
||||
$db->sql_query($sql);
|
||||
|
||||
$this->add_lang('ucp');
|
||||
|
||||
$crawler = self::request('GET', 'ucp.php?mode=resend_act');
|
||||
$this->assertContainsLang('UCP_RESEND', $crawler->filter('html')->text());
|
||||
$form = $crawler->filter('input[name=submit]')->selectButton('Submit')->form();
|
||||
$crawler = self::submit($form, [
|
||||
'username' => self::TEST_USER,
|
||||
'email' => self::TEST_EMAIL,
|
||||
]);
|
||||
$this->assertContainsLang('ACTIVATION_ALREADY_SENT', $crawler->filter('html')->text());
|
||||
}
|
||||
|
||||
protected function get_user_data($username)
|
||||
|
127
tests/functions_content/get_context_test.php
Normal file
127
tests/functions_content/get_context_test.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class phpbb_functions_content_get_context_test extends TestCase
|
||||
{
|
||||
/**
|
||||
* Data provider for get_context test cases.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function data_get_context(): array
|
||||
{
|
||||
return [
|
||||
'text contains words and length greater than text' => [
|
||||
'text' => 'This is a sample text containing several words, including sample, text, and words.',
|
||||
'words' => ['sample', 'words'],
|
||||
'length' => 100,
|
||||
'expected' => 'This is a sample text containing several words, including sample, text, and words.',
|
||||
],
|
||||
'text contains words and length less than text' => [
|
||||
'text' => 'This is a sample text containing several words, including sample, text, and words.',
|
||||
'words' => ['sample', 'words'],
|
||||
'length' => 50,
|
||||
'expected' => 'This is a sample text containing several words ...',
|
||||
],
|
||||
'text does not contain words' => [
|
||||
'text' => 'This is a sample text containing several words, but none of them match the given words.',
|
||||
'words' => ['nonexistent'],
|
||||
'length' => 50,
|
||||
'expected' => 'This is a sample text containing several words ...',
|
||||
],
|
||||
'desired length equal to text length' => [
|
||||
'text' => 'Exact length text.',
|
||||
'words' => ['Exact', 'text'],
|
||||
'length' => 18,
|
||||
'expected' => 'Exact length text.',
|
||||
],
|
||||
'text with html entities' => [
|
||||
'text' => 'This is a sample text containing & and < and > entities.',
|
||||
'words' => ['sample', 'containing'],
|
||||
'length' => 50,
|
||||
'expected' => 'This is a sample text containing & and < and ...',
|
||||
],
|
||||
'text with html entities and contains last word' => [
|
||||
'text' => 'This is a sample text containing & and < and > entities.',
|
||||
'words' => ['sample', 'entities'],
|
||||
'length' => 50,
|
||||
'expected' => 'This is a sample text ... and < and > entities.',
|
||||
],
|
||||
'text with multiple spaces and special characters' => [
|
||||
'text' => 'This is a sample text containing several words.',
|
||||
'words' => ['sample', 'several'],
|
||||
'length' => 50,
|
||||
'expected' => 'This is a sample text containing several words.',
|
||||
],
|
||||
'empty text' => [
|
||||
'text' => '',
|
||||
'words' => ['sample', 'words'],
|
||||
'length' => 50,
|
||||
'expected' => '',
|
||||
],
|
||||
'empty words array' => [
|
||||
'text' => 'This is a sample text containing several words.',
|
||||
'words' => [],
|
||||
'length' => 50,
|
||||
'expected' => 'This is a sample text containing several words.',
|
||||
],
|
||||
'zero length' => [
|
||||
'text' => 'This is a sample text.',
|
||||
'words' => ['sample'],
|
||||
'length' => 0,
|
||||
'expected' => '...',
|
||||
],
|
||||
'negative length' => [
|
||||
'text' => 'This is a sample text.',
|
||||
'words' => ['sample'],
|
||||
'length' => -10,
|
||||
'expected' => '...',
|
||||
],
|
||||
'ellipses_beginning' => [
|
||||
'text' => 'foo foo foo foo foo foo foo foo bar',
|
||||
'words' => ['bar'],
|
||||
'length' => 10,
|
||||
'expected' => '... foo foo bar',
|
||||
],
|
||||
'ellipsis_end' => [
|
||||
'text' => 'bar foo foo foo foo foo foo foo foo',
|
||||
'words' => ['bar'],
|
||||
'length' => 10,
|
||||
'expected' => 'bar foo foo ...',
|
||||
],
|
||||
'ellipsis_middle' => [
|
||||
'text' => 'foo word1 foo foo foo foo foo foo foo foo foo word2 foo',
|
||||
'words' => ['word1', 'word2'],
|
||||
'length' => 10,
|
||||
'expected' => '... word1 ... word2 ...',
|
||||
],
|
||||
'ellipsis_middle2' => [
|
||||
'text' => 'word1 foo foo foo foo foo foo foo foo foo word2',
|
||||
'words' => ['word1', 'word2'],
|
||||
'length' => 10,
|
||||
'expected' => 'word1 ... word2',
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider data_get_context
|
||||
*/
|
||||
public function test_get_context($text, $words, $length, $expected)
|
||||
{
|
||||
$this->assertEquals($expected, get_context($text, $words, $length));
|
||||
}
|
||||
|
||||
}
|
@@ -25,19 +25,24 @@ class phpbb_search_native_test extends phpbb_search_test_case
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
global $phpbb_root_path, $phpEx, $config, $user, $cache;
|
||||
global $phpbb_root_path, $phpEx, $config, $cache;
|
||||
|
||||
parent::setUp();
|
||||
|
||||
// dbal uses cache
|
||||
$cache = new phpbb_mock_cache();
|
||||
|
||||
$lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
|
||||
$lang = new \phpbb\language\language($lang_loader);
|
||||
$user = new \phpbb\user($lang, '\phpbb\datetime');;
|
||||
|
||||
$this->db = $this->new_dbal();
|
||||
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
|
||||
$error = null;
|
||||
$class = self::get_search_wrapper('\phpbb\search\fulltext_native');
|
||||
$config['fulltext_native_min_chars'] = 2;
|
||||
$config['fulltext_native_max_chars'] = 14;
|
||||
$config['max_num_search_keywords'] = 10;
|
||||
$this->search = new $class($error, $phpbb_root_path, $phpEx, null, $config, $this->db, $user, $phpbb_dispatcher);
|
||||
}
|
||||
|
||||
@@ -259,4 +264,78 @@ class phpbb_search_native_test extends phpbb_search_test_case
|
||||
}
|
||||
$this->assert_array_content_equals($common, $this->search->get_common_words());
|
||||
}
|
||||
|
||||
public function data_split_keywords_max(): array
|
||||
{
|
||||
return [
|
||||
'character count within limits separated by more spaces' => [
|
||||
'foo bar baz boo far faz roo rar raz zoo',
|
||||
'all',
|
||||
false,
|
||||
],
|
||||
'character count within limits separated by spaces' => [
|
||||
'foo bar baz boo far faz roo rar raz zoo',
|
||||
'all',
|
||||
false,
|
||||
],
|
||||
'character count within limits separated by +, spaces after +' => [
|
||||
'foo+ bar+ baz+ boo+ far+ faz+ roo+ rar+ raz+ zoo',
|
||||
'all',
|
||||
false,
|
||||
],
|
||||
'character count within limits separated by +, no spaces' => [
|
||||
'foo+bar+baz+boo+far+faz+roo+rar+raz+zoo',
|
||||
'all',
|
||||
false,
|
||||
],
|
||||
'character count outside limits separated by +, no spaces' => [
|
||||
'foo+bar+baz+boo+far+faz+roo+rar+raz+zoo+zar',
|
||||
'all',
|
||||
true,
|
||||
],
|
||||
'character count outside limits separated by + and spaces' => [
|
||||
'foo +bar +baz +boo +far +faz +roo +rar +raz +zoo +zar',
|
||||
'all',
|
||||
true,
|
||||
],
|
||||
'character count outside limits separated by spaces' => [
|
||||
'foo bar baz boo far faz roo rar raz zoo zar',
|
||||
'all',
|
||||
true,
|
||||
],
|
||||
'character count outside limits separated by -, no spaces' => [
|
||||
'foo-bar-baz-boo-far-faz-roo-rar-raz-zoo-zar',
|
||||
'all',
|
||||
true,
|
||||
],
|
||||
'character count outside limits separated by - and spaces' => [
|
||||
'foo -bar -baz -boo -far -faz -roo -rar -raz -zoo -zar',
|
||||
'all',
|
||||
true,
|
||||
],
|
||||
'character count outside limits separated by |, no spaces' => [
|
||||
'foo|bar|baz|boo|far|faz|roo|rar|raz|zoo|zar',
|
||||
'all',
|
||||
true,
|
||||
],
|
||||
'character count outside limits separated by | and spaces' => [
|
||||
'foo |bar |baz |boo |far |faz |roo |rar |raz |zoo |zar',
|
||||
'all',
|
||||
true,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider data_split_keywords_max
|
||||
*/
|
||||
public function test_split_max_keywords($keywords, $terms, $expect_error)
|
||||
{
|
||||
if ($expect_error)
|
||||
{
|
||||
$this->setExpectedTriggerError(E_USER_NOTICE, 'MAX_NUM_SEARCH_KEYWORDS_REFINE');
|
||||
}
|
||||
|
||||
$this->assertTrue($this->search->split_keywords($keywords, $terms));
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user