diff --git a/.github/workflows/check_merge_to_master.yml b/.github/workflows/check_merge_to_master.yml new file mode 100644 index 0000000000..45288a072a --- /dev/null +++ b/.github/workflows/check_merge_to_master.yml @@ -0,0 +1,70 @@ +name: Check merge to master + +on: + pull_request_target: + types: [ opened, synchronize, reopened ] + branches: + - 3.3.x + +jobs: + merge-check: + if: github.event_name == 'pull_request_target' && github.event.pull_request.base.ref == '3.3.x' + runs-on: ubuntu-latest + steps: + - name: Checkout the repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 # Ensure full history is fetched + + - name: Set up Git user + run: | + git config --global user.name "github-actions" + git config --global user.email "github-actions@github.com" + + - name: Fetch all branches + run: git fetch origin + + - name: Simulate merging PR into 3.3.x + id: simulate_merge + run: | + git checkout 3.3.x + git fetch origin pull/${{ github.event.pull_request.number }}/head + git merge --no-ff FETCH_HEAD || exit 1 + + - name: Attempt to merge updated 3.3.x into master + id: merge_master + run: | + git checkout master + if git merge --no-ff 3.3.x --no-commit; then + echo "mergeable=true" >> $GITHUB_OUTPUT + else + echo "mergeable=false" >> $GITHUB_OUTPUT + git merge --abort + fi + + - name: Find Comment + uses: peter-evans/find-comment@v3 + id: fc + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: 'github-actions[bot]' + body-includes: The attempt to merge branch `3.3.x` into `master` has completed + + - name: Post comment on PR + if: always() # Ensure this step always runs, regardless of merge result + uses: peter-evans/create-or-update-comment@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + issue-number: ${{ github.event.pull_request.number }} + comment-id: ${{ steps.fc.outputs.comment-id }} + edit-mode: replace + body: | + The attempt to merge branch `3.3.x` into `master` has completed after considering the changes in this PR. + + - Merge result: ${{ steps.merge_master.outputs.mergeable == 'true' && 'Success ✅' || 'Conflict ❌' }} + + ${{ steps.merge_master.outputs.mergeable == 'true' && 'This PR is ready to be merged.' || 'A separate PR will be needed to merge `3.3.x` into `master`.' }} + + - name: Mark job as succeeded + if: always() + run: echo "Merge check completed. Ignoring the result to avoid failed status." diff --git a/.github/workflows/merge_3.3.x_to_master.yml b/.github/workflows/merge_3.3.x_to_master.yml new file mode 100644 index 0000000000..9aea009c3a --- /dev/null +++ b/.github/workflows/merge_3.3.x_to_master.yml @@ -0,0 +1,60 @@ +name: Merge 3.3.x into master + +on: + push: + branches: + - 3.3.x + +jobs: + merge-branch: + runs-on: ubuntu-latest + + steps: + - uses: actions/create-github-app-token@v1 + id: app-token + with: + app-id: ${{ vars.MERGE_MASTER_APP_ID }} + private-key: ${{ secrets.MERGE_MASTER_SECRET }} + + - name: Checkout the repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetch full history for proper merging + ref: 3.3.x # Checkout the 3.3.x branch + token: ${{ steps.app-token.outputs.token }} + + - name: Fetch the latest commit information + id: get-commit-info + run: | + # Get the latest commit SHA and its author details + COMMIT_SHA=$(git rev-parse HEAD) + COMMIT_AUTHOR_NAME=$(git log -1 --pretty=format:'%an' $COMMIT_SHA) + COMMIT_AUTHOR_EMAIL=$(git log -1 --pretty=format:'%ae' $COMMIT_SHA) + + # Save them as output for later steps + echo "commit_sha=$COMMIT_SHA" >> $GITHUB_ENV + echo "commit_author_name=$COMMIT_AUTHOR_NAME" >> $GITHUB_ENV + echo "commit_author_email=$COMMIT_AUTHOR_EMAIL" >> $GITHUB_ENV + + - name: Set up Git with the pull request author's info + run: | + git config --global user.name "${{ env.commit_author_name }}" + git config --global user.email "${{ env.commit_author_email }}" + + - name: Fetch all branches + run: git fetch --all + + - name: Merge 3.3.x into master + run: | + git checkout master + if git merge --no-ff 3.3.x; then + echo "merge_failed=false" >> $GITHUB_ENV + else + echo "merge_failed=true" >> $GITHUB_ENV + fi + + - name: Push changes to master if merge was successful + if: env.merge_failed == 'false' + run: git push origin master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cbf31fc288..3795b00a7e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -137,6 +137,10 @@ jobs: db: "mysql:5.7" - php: '8.3' db: "mariadb:10.2" + - php: '8.4' + db: "mysql:8.0" + - php: '8.4' + db: "mariadb:10.3" name: PHP ${{ matrix.php }} - ${{ matrix.db_alias != '' && matrix.db_alias || matrix.db }} @@ -272,6 +276,8 @@ jobs: db: "postgres:9.5" - php: '8.3' db: "postgres:9.5" + - php: '8.4' + db: "postgres:9.5" name: PHP ${{ matrix.php }} - ${{ matrix.db }} @@ -364,7 +370,7 @@ jobs: # Other database types, namely sqlite3 and mssql other-tests: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 strategy: matrix: include: @@ -374,17 +380,17 @@ jobs: db: "mcr.microsoft.com/mssql/server:2017-latest" db_alias: 'MSSQL 2017' - php: '8.1' - db: "mcr.microsoft.com/mssql/server:2019-latest" + db: "mcr.microsoft.com/mssql/server:2019-CU27-ubuntu-20.04" db_alias: 'MSSQL 2019' - php: '8.1' - db: "mcr.microsoft.com/mssql/server:2022-latest" + db: "mcr.microsoft.com/mssql/server:2022-CU13-ubuntu-22.04" db_alias: 'MSSQL 2022' name: PHP ${{ matrix.php }} - ${{ matrix.db_alias != '' && matrix.db_alias || matrix.db }} services: mssql: - image: ${{ matrix.db != 'mcr.microsoft.com/mssql/server:2017-latest' && matrix.db != 'mcr.microsoft.com/mssql/server:2019-latest' && matrix.db != 'mcr.microsoft.com/mssql/server:2022-latest' && 'mcr.microsoft.com/mssql/server:2017-latest' || matrix.db }} + image: ${{ matrix.db != 'mcr.microsoft.com/mssql/server:2017-latest' && matrix.db != 'mcr.microsoft.com/mssql/server:2019-CU27-ubuntu-20.04' && matrix.db != 'mcr.microsoft.com/mssql/server:2022-CU13-ubuntu-22.04' && 'mcr.microsoft.com/mssql/server:2017-latest' || matrix.db }} env: SA_PASSWORD: "Pssw0rd_12" ACCEPT_EULA: "y" @@ -416,7 +422,7 @@ jobs: env: MATRIX_DB: ${{ matrix.db }} run: | - if [ $MATRIX_DB == 'mcr.microsoft.com/mssql/server:2017-latest' ] || [ $MATRIX_DB == 'mcr.microsoft.com/mssql/server:2019-latest' ] || [ $MATRIX_DB == 'mcr.microsoft.com/mssql/server:2022-latest' ] + if [ $MATRIX_DB == 'mcr.microsoft.com/mssql/server:2017-latest' ] || [ $MATRIX_DB == 'mcr.microsoft.com/mssql/server:2019-CU27-ubuntu-20.04' ] || [ $MATRIX_DB == 'mcr.microsoft.com/mssql/server:2022-CU13-ubuntu-22.04' ] then db='mssql' else @@ -480,7 +486,7 @@ jobs: strategy: matrix: type: ['unit', 'functional'] - php: ['8.1', '8.2'] + php: ['8.1', '8.2', '8.3'] db: ['postgres'] name: Windows - ${{ matrix.type }} - PHP ${{ matrix.php }} - ${{ matrix.db }} diff --git a/README.md b/README.md index af3fb91de7..228d62047f 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,8 @@ We have unit and functional tests in order to prevent regressions. You can view Branch | Description | GitHub Actions | ------- | ----------- | -------------- | -**master** | Latest development version | ![Tests](https://github.com/phpbb/phpbb/workflows/Tests/badge.svg?branch=master) | -**3.3.x** | Development of version 3.3.x | ![Tests](https://github.com/phpbb/phpbb/workflows/Tests/badge.svg?branch=3.3.x) | +**master** | Latest development version | ![Tests](https://github.com/phpbb/phpbb/actions/workflows/tests.yml/badge.svg?branch=master) | +**3.3.x** | Development of version 3.3.x | ![Tests](https://github.com/phpbb/phpbb/actions/workflows/tests.yml/badge.svg?branch=3.3.x) | ## 📜 License diff --git a/Vagrantfile b/Vagrantfile index ab225c9ad9..c80dfd98f8 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -11,15 +11,15 @@ aliasesPath = "vagrant/aliases" require File.expand_path(confDir + '/scripts/homestead.rb') Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| - if File.exists? aliasesPath then + if File.exist? aliasesPath then config.vm.provision "file", source: aliasesPath, destination: "~/.bash_aliases" end - if File.exists? homesteadYamlPath then + if File.exist? homesteadYamlPath then Homestead.configure(config, YAML::load(File.read(homesteadYamlPath))) end - if File.exists? afterScriptPath then + if File.exist? afterScriptPath then config.vm.provision "shell", path: afterScriptPath end end diff --git a/build/build.xml b/build/build.xml index 65b99b14c2..b6391b011d 100644 --- a/build/build.xml +++ b/build/build.xml @@ -3,8 +3,8 @@ - - + + @@ -181,6 +181,7 @@ + diff --git a/package-lock.json b/package-lock.json index d21a035c1f..102d21cd0a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -595,10 +595,11 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, + "license": "MIT", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -608,7 +609,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -623,6 +624,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -631,7 +633,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/boolbase": { "version": "1.0.0", @@ -650,12 +653,13 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -725,6 +729,7 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -734,6 +739,7 @@ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -1027,15 +1033,17 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1316,6 +1324,7 @@ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -1333,6 +1342,7 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -1342,6 +1352,7 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -1461,7 +1472,8 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/electron-to-chromium": { "version": "1.4.111", @@ -1476,10 +1488,11 @@ "dev": true }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -1516,6 +1529,7 @@ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4" }, @@ -1528,6 +1542,7 @@ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -1545,7 +1560,8 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/escape-string-regexp": { "version": "4.0.0", @@ -1739,6 +1755,7 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1768,37 +1785,38 @@ } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -1958,10 +1976,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -1970,13 +1989,14 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -1992,6 +2012,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -2000,7 +2021,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/find-up": { "version": "4.1.0", @@ -2122,6 +2144,7 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -2188,6 +2211,7 @@ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", @@ -2338,6 +2362,7 @@ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -2509,6 +2534,7 @@ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, @@ -2521,6 +2547,7 @@ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -2533,6 +2560,7 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -2545,6 +2573,7 @@ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -2605,6 +2634,7 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, + "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -2621,6 +2651,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -2851,6 +2882,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -3226,6 +3258,7 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -3269,10 +3302,14 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge2": { "version": "1.4.1", @@ -3293,12 +3330,13 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -3310,6 +3348,7 @@ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -3587,10 +3626,14 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3627,6 +3670,7 @@ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -3763,6 +3807,7 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3822,10 +3867,11 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "dev": true, + "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", @@ -4443,12 +4489,13 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -4497,6 +4544,7 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4506,6 +4554,7 @@ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, + "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -4854,10 +4903,11 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -4882,6 +4932,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -4890,24 +4941,37 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, + "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" @@ -4918,6 +4982,7 @@ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -4934,7 +4999,8 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/shebang-command": { "version": "2.0.0", @@ -4962,6 +5028,7 @@ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -5086,6 +5153,7 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -5519,6 +5587,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -5543,6 +5612,7 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.6" } @@ -5585,6 +5655,7 @@ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -5640,6 +5711,7 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -6389,9 +6461,9 @@ } }, "body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "requires": { "bytes": "3.1.2", @@ -6402,7 +6474,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -6442,12 +6514,12 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "browserslist": { @@ -6709,9 +6781,9 @@ "dev": true }, "cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true }, "cookie-signature": { @@ -7033,9 +7105,9 @@ "dev": true }, "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true }, "end-of-stream": { @@ -7246,37 +7318,37 @@ } }, "express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dev": true, "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -7408,22 +7480,22 @@ } }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "requires": { "to-regex-range": "^5.0.1" } }, "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, "requires": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -8402,9 +8474,9 @@ } }, "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "dev": true }, "merge2": { @@ -8420,12 +8492,12 @@ "dev": true }, "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "requires": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" } }, @@ -8637,9 +8709,9 @@ } }, "object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true }, "object.defaults": { @@ -8809,9 +8881,9 @@ "dev": true }, "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", "dev": true }, "path-type": { @@ -9201,12 +9273,12 @@ "dev": true }, "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "requires": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" } }, "queue-microtask": { @@ -9493,9 +9565,9 @@ } }, "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "requires": { "debug": "2.6.9", @@ -9530,6 +9602,12 @@ } } }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -9539,15 +9617,15 @@ } }, "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, "requires": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" } }, "set-function-length": { diff --git a/phpBB/adm/style/acp_captcha.html b/phpBB/adm/style/acp_captcha.html index 4353becd2f..0c9d3bf0af 100644 --- a/phpBB/adm/style/acp_captcha.html +++ b/phpBB/adm/style/acp_captcha.html @@ -1,79 +1,85 @@ - +{% include 'overall_header.html' %} -

{L_ACP_VC_SETTINGS}

+

{{ lang('ACP_VC_SETTINGS') }}

-

{L_ACP_VC_SETTINGS_EXPLAIN}

+

{{ lang('ACP_VC_SETTINGS_EXPLAIN') }}

-

{L_ACP_VC_EXT_GET_MORE}

+

{{ lang('ACP_VC_EXT_GET_MORE') }}

- +{% if ERRORS %}
-

{L_WARNING}

-

{ERROR_MSG}

+

{{ lang('WARNING') }}

+

{{ ERRORS|join('
') }}

- +{% endif %} -
+
-{L_GENERAL_OPTIONS} +{{ lang('GENERAL_OPTIONS') }}
-

{L_VISUAL_CONFIRM_REG_EXPLAIN}
-
-
+

{{ lang('VISUAL_CONFIRM_REG_EXPLAIN') }}
+
+ + +
-

{L_REG_LIMIT_EXPLAIN}
-
+

{{ lang('REG_LIMIT_EXPLAIN') }}
+
-

{L_MAX_LOGIN_ATTEMPTS_EXPLAIN}
-
+

{{ lang('MAX_LOGIN_ATTEMPTS_EXPLAIN') }}
+
-

{L_VISUAL_CONFIRM_POST_EXPLAIN}
-
-
+

{{ lang('VISUAL_CONFIRM_POST_EXPLAIN') }}
+
+ + +
-

{L_VISUAL_CONFIRM_REFRESH_EXPLAIN}
-
-
+

{{ lang('VISUAL_CONFIRM_REFRESH_EXPLAIN') }}
+
+ + +
-{L_AVAILABLE_CAPTCHAS} -
-

{L_CAPTCHA_SELECT_EXPLAIN}
-
-
- -
-

{L_CAPTCHA_CONFIGURE_EXPLAIN}
-
-
- +{{ lang('AVAILABLE_CAPTCHAS') }} +
+

{{ lang('CAPTCHA_SELECT_EXPLAIN') }}
+
{{ FormsSelect(CAPTCHA_SELECT | merge({id: 'captcha_select', onchange: "(document.getElementById('acp_captcha')).submit()"})) }}
+
+ {% if S_CAPTCHA_HAS_CONFIG %} +
+

{{ lang('CAPTCHA_CONFIGURE_EXPLAIN') }}
+
+
+ {% endif %}
- +{% if CAPTCHA_PREVIEW_TPL %}
- {L_PREVIEW} - + {{ lang('PREVIEW') }} + {% include CAPTCHA_PREVIEW_TPL %}
- +{% endif %}
- {L_ACP_SUBMIT_CHANGES} + {{ lang('ACP_SUBMIT_CHANGES') }}

-   -   +   +  

- {S_FORM_TOKEN} + {{ S_FORM_TOKEN }}
- +{% include 'overall_footer.html' %} diff --git a/phpBB/adm/style/acp_ext_list.html b/phpBB/adm/style/acp_ext_list.html index bb22ac861c..af21b4f6b1 100644 --- a/phpBB/adm/style/acp_ext_list.html +++ b/phpBB/adm/style/acp_ext_list.html @@ -42,82 +42,94 @@ - - - {L_EXTENSIONS_ENABLED} - - - - {enabled.META_DISPLAY_NAME} - - - {enabled.META_VERSION} - {{ Icon('font', 'circle-exclamation', '', true, 'fas outdated-ext') }} - - {enabled.META_VERSION} - - - {L_DETAILS} - - - style="color: #bc2a4d;" title="{enabled.actions.L_ACTION_EXPLAIN}">{enabled.actions.L_ACTION} -  |  - - - - - - - - - {L_EXTENSIONS_DISABLED} - - - - {disabled.META_DISPLAY_NAME} - - - {disabled.META_VERSION} - {{ Icon('font', 'circle-exclamation', '', true, 'fas outdated-ext') }} - - {disabled.META_VERSION} - - - - {L_DETAILS} - - - - style="color: #bc2a4d;" title="{disabled.actions.L_ACTION_EXPLAIN}">{disabled.actions.L_ACTION} -  |  - - - - - + {% for list in ['enabled', 'disabled', 'not_installed'] %} + {% set blockname = attribute(loops, list) %} + {% if blockname|length %} + + {{ lang('EXTENSIONS_' ~ list|upper) }} + {% if list == 'enabled' %} + {% EVENT acp_ext_list_enabled_title_after %} + {% elseif list == 'disabled' %} + {% EVENT acp_ext_list_disabled_title_after %} + {% elseif list == 'not_installed' %} + {% EVENT acp_ext_list_not_installed_title_after %} + {% endif %} + + + {% for data in blockname %} + + {{ data.META_DISPLAY_NAME }} + {% if list == 'enabled' %} + {% EVENT acp_ext_list_enabled_name_after %} + {% elseif list == 'disabled' %} + {% EVENT acp_ext_list_disabled_name_after %} + {% elseif list == 'not_installed' %} + {% EVENT acp_ext_list_not_installed_name_after %} + {% endif %} + + + {% if data.S_VERSIONCHECK %} + {{ data.META_VERSION }} + {% if not data.S_UP_TO_DATE %}{{ Icon('font', 'circle-exclamation', '', true, 'fas outdated-ext') }}{% endif %} + {% else %} + {{ data.META_VERSION }} + {% endif %} + + + {% if data.U_DETAILS %}{{ lang ('DETAILS') }}{% endif %} + + + {% for actions in data.actions %} + {{ actions.L_ACTION }} + {% if not actions.S_LAST_ROW %} | {% endif %} + {% endfor %} + + + {% endfor %} + {% endif %} + {% endfor %} - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + +
{L_EXTENSION_INSTALL_HEADLINE}
{L_EXTENSION_INSTALL_EXPLAIN}
{L_EXTENSION_UPDATE_HEADLINE}
{L_EXTENSION_UPDATE_EXPLAIN}
{L_EXTENSION_REMOVE_HEADLINE}
{L_EXTENSION_REMOVE_EXPLAIN}
{L_EXTENSION_INSTALLING_HEADLINE}
+
    + {% for step in lang_raw('EXTENSION_INSTALLING_EXPLAIN') %} +
  1. {{ step }}
  2. + {% endfor %} +
+
{L_EXTENSION_UPDATING_HEADLINE}
+
    + {% for step in lang_raw('EXTENSION_UPDATING_EXPLAIN') %} +
  1. {{ step }}
  2. + {% endfor %} +
+
{L_EXTENSION_REMOVING_HEADLINE}
+
    + {% for step in lang_raw('EXTENSION_REMOVING_EXPLAIN') %} +
  1. {{ step }}
  2. + {% endfor %} +
+
diff --git a/phpBB/adm/style/acp_forums.html b/phpBB/adm/style/acp_forums.html index 613a054b32..d030d2e587 100644 --- a/phpBB/adm/style/acp_forums.html +++ b/phpBB/adm/style/acp_forums.html @@ -181,7 +181,14 @@
-
+
+ +
diff --git a/phpBB/adm/style/acp_forums_copy_perm.html b/phpBB/adm/style/acp_forums_copy_perm.html deleted file mode 100644 index 1fcf2f62a4..0000000000 --- a/phpBB/adm/style/acp_forums_copy_perm.html +++ /dev/null @@ -1,22 +0,0 @@ - - -

{L_COPY_PERMISSIONS}

- -

{L_COPY_PERMISSIONS_EXPLAIN}

-

{L_ACL_LINK}

- -
- -
-
-

{L_COPY_PERMISSIONS_EXPLAIN}
-
-
-
{S_FORM_TOKEN}{S_HIDDEN_FIELDS} -   -
-
- -
- - diff --git a/phpBB/adm/style/acp_icons.html b/phpBB/adm/style/acp_icons.html index 25d5cb5207..9a5179419e 100644 --- a/phpBB/adm/style/acp_icons.html +++ b/phpBB/adm/style/acp_icons.html @@ -105,7 +105,7 @@ - {items.TEXT_ALT} + {items.TEXT_ALT} [{items.IMG}] diff --git a/phpBB/adm/style/acp_posting_buttons.html b/phpBB/adm/style/acp_posting_buttons.html index e5f96b0c22..c0c5aacd74 100644 --- a/phpBB/adm/style/acp_posting_buttons.html +++ b/phpBB/adm/style/acp_posting_buttons.html @@ -28,7 +28,7 @@ - diff --git a/phpBB/adm/style/captcha_qa_acp.html b/phpBB/adm/style/captcha_qa_acp.html index 26598c7c2b..1118a1f32e 100644 --- a/phpBB/adm/style/captcha_qa_acp.html +++ b/phpBB/adm/style/captcha_qa_acp.html @@ -18,11 +18,13 @@ {L_QUESTIONS} + {% if questions %} {L_QUESTION_TEXT} {L_QUESTION_LANG} {L_ACTION} + {% endif %} @@ -33,6 +35,10 @@ {{ question.QUESTION_LANG }} {{ ICON_EDIT }} {{ ICON_DELETE }} + {% else %} + + {{ lang('QA_NO_QUESTIONS') }} + {% endfor %} diff --git a/phpBB/adm/style/captcha_turnstile_acp.html b/phpBB/adm/style/captcha_turnstile_acp.html new file mode 100644 index 0000000000..a187e1e41b --- /dev/null +++ b/phpBB/adm/style/captcha_turnstile_acp.html @@ -0,0 +1,64 @@ +{% include('overall_header.html') %} + + + +

{{ lang('ACP_VC_SETTINGS') }}

+ +

{{ lang('ACP_VC_SETTINGS_EXPLAIN') }}

+ +
+
+ {{ lang('GENERAL_OPTIONS') }} +
+
+
+ {{ lang('CAPTCHA_TURNSTILE_SITEKEY_EXPLAIN') }} +
+
+
+
+
+
+ {{ lang('CAPTCHA_TURNSTILE_SECRET_EXPLAIN') }} +
+
+
+
+
+ +
{{ lang('CAPTCHA_TURNSTILE_THEME_EXPLAIN') }} +
+
+ {% for theme in CAPTCHA_TURNSTILE_THEMES %} + + {% endfor %} +
+
+
+
+ {{ lang('PREVIEW') }} + {% if PREVIEW %} +
+

{{ lang('WARNING') }}

+

{{ lang('CAPTCHA_PREVIEW_MSG') }}

+
+ {% endif %} + {% include(CAPTCHA_PREVIEW) %} +
+ +
+ {{ lang('ACP_SUBMIT_CHANGES') }} +

+   +   +

+ + + {{ S_FORM_TOKEN }} +
+
+ +{% include('overall_footer.html') %} diff --git a/phpBB/adm/style/captcha_turnstile_acp_demo.html b/phpBB/adm/style/captcha_turnstile_acp_demo.html new file mode 100644 index 0000000000..757d0a4bcb --- /dev/null +++ b/phpBB/adm/style/captcha_turnstile_acp_demo.html @@ -0,0 +1,23 @@ +
+
+
+{% INCLUDEJS U_TURNSTILE_SCRIPT %} + diff --git a/phpBB/assets/javascript/installer.js b/phpBB/assets/javascript/installer.js index a11b76b863..cfe685f88b 100644 --- a/phpBB/assets/javascript/installer.js +++ b/phpBB/assets/javascript/installer.js @@ -605,6 +605,8 @@ function interceptFormSubmit($form) { if (!$form.length) { return; + } else if ($form.find('input[name="admin_name"]').length > 0) { + setAdminTimezone($form); } $form.find(':submit').bind('click', function (event) { @@ -612,4 +614,20 @@ submitForm($form, $(this)); }); } + + /** + * Set admin timezone in form + * + * @param $form + */ + function setAdminTimezone($form) { + // Set admin timezone if it does not exist yet + if ($form.find('input[name="admin_timezone"]').length === 0) { + const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; + + // Add timezone as form entry + const timezoneEntry = $(''); + $form.append(timezoneEntry); + } + } })(jQuery); // Avoid conflicts with other libraries diff --git a/phpBB/assets/javascript/webpush.js b/phpBB/assets/javascript/webpush.js index c326fe1cff..4adb9ecf10 100644 --- a/phpBB/assets/javascript/webpush.js +++ b/phpBB/assets/javascript/webpush.js @@ -51,7 +51,7 @@ function PhpbbWebpush() { // Service workers are only supported in secure context if (window.isSecureContext !== true) { - subscribeButton.disabled = true; + setDisabledState(); return; } @@ -66,13 +66,33 @@ function PhpbbWebpush() { .catch(error => { console.info(error); // Service worker could not be registered - subscribeButton.disabled = true; + setDisabledState(); }); } else { - subscribeButton.disabled = true; + setDisabledState(); } }; + /** + * Disable subscribing buttons, update subscribe button text and hide dropdown toggle + * + * @return void + */ + function setDisabledState() { + subscribeButton.disabled = true; + + const notificationList = document.getElementById('notification-menu'); + const subscribeToggle = notificationList.querySelector('.webpush-subscribe'); + + if (subscribeToggle) { + subscribeToggle.style.display = 'none'; + } + + if (subscribeButton.type === 'submit' || subscribeButton.classList.contains('button')) { + subscribeButton.value = subscribeButton.getAttribute('data-disabled-msg'); + } + } + /** * Update button state depending on notifications state * @@ -150,6 +170,7 @@ function PhpbbWebpush() { // Prevent the user from clicking the subscribe button multiple times. const result = await Notification.requestPermission(); if (result === 'denied') { + phpbb.alert(subscribeButton.getAttribute('data-l-err'), subscribeButton.getAttribute('data-l-msg')); return; } diff --git a/phpBB/composer.json b/phpBB/composer.json index 9d4f28689c..2d75027ff0 100644 --- a/phpBB/composer.json +++ b/phpBB/composer.json @@ -58,7 +58,7 @@ "symfony/routing": "^6.3", "symfony/twig-bridge": "^6.3", "symfony/yaml": "^6.3", - "twig/twig": "3.8.0" + "twig/twig": "^3.14" }, "require-dev": { "laravel/homestead": "~14.4", @@ -73,9 +73,6 @@ "vimeo/psalm": "^5.18.0", "psalm/plugin-symfony": "^v5.1.0" }, - "suggest": { - "ext-mbstring": "Better performance in search" - }, "extra": { "branch-alias": { "dev-master": "4.0.x-dev" diff --git a/phpBB/composer.lock b/phpBB/composer.lock index a8651e11a9..8fe9b37b7e 100644 --- a/phpBB/composer.lock +++ b/phpBB/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3c21881b6c8a81fbd83d57004763049d", + "content-hash": "504e019821be33ba6ad322b37d698744", "packages": [ { "name": "bantu/ini-get-wrapper", @@ -102,21 +102,24 @@ }, { "name": "carlos-mg89/oauth", - "version": "0.8.15", + "version": "0.8.16", "source": { "type": "git", "url": "https://github.com/carlos-mg89/PHPoAuthLib.git", - "reference": "c14c44e4f8993009a10d56a41e61c19291824a29" + "reference": "7c8aaace2004f0736c4598ad5d78307b43ccd858" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/carlos-mg89/PHPoAuthLib/zipball/c14c44e4f8993009a10d56a41e61c19291824a29", - "reference": "c14c44e4f8993009a10d56a41e61c19291824a29", + "url": "https://api.github.com/repos/carlos-mg89/PHPoAuthLib/zipball/7c8aaace2004f0736c4598ad5d78307b43ccd858", + "reference": "7c8aaace2004f0736c4598ad5d78307b43ccd858", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, + "replace": { + "lusitanian/oauth": "~0.3" + }, "require-dev": { "ext-curl": "*", "ext-dom": "*", @@ -164,9 +167,9 @@ ], "support": { "issues": "https://github.com/carlos-mg89/PHPoAuthLib/issues", - "source": "https://github.com/carlos-mg89/PHPoAuthLib/tree/0.8.15" + "source": "https://github.com/carlos-mg89/PHPoAuthLib/tree/0.8.16" }, - "time": "2022-07-15T08:38:14+00:00" + "time": "2024-08-09T10:00:52+00:00" }, { "name": "chita/topological_sort", @@ -213,16 +216,16 @@ }, { "name": "composer/ca-bundle", - "version": "1.5.0", + "version": "1.5.3", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "0c5ccfcfea312b5c5a190a21ac5cef93f74baf99" + "reference": "3b1fc3f0be055baa7c6258b1467849c3e8204eb2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/0c5ccfcfea312b5c5a190a21ac5cef93f74baf99", - "reference": "0c5ccfcfea312b5c5a190a21ac5cef93f74baf99", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/3b1fc3f0be055baa7c6258b1467849c3e8204eb2", + "reference": "3b1fc3f0be055baa7c6258b1467849c3e8204eb2", "shasum": "" }, "require": { @@ -232,8 +235,8 @@ }, "require-dev": { "phpstan/phpstan": "^1.10", - "psr/log": "^1.0", - "symfony/phpunit-bridge": "^4.2 || ^5", + "phpunit/phpunit": "^8 || ^9", + "psr/log": "^1.0 || ^2.0 || ^3.0", "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, "type": "library", @@ -269,7 +272,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.5.0" + "source": "https://github.com/composer/ca-bundle/tree/1.5.3" }, "funding": [ { @@ -285,20 +288,20 @@ "type": "tidelift" } ], - "time": "2024-03-15T14:00:32+00:00" + "time": "2024-11-04T10:15:26+00:00" }, { "name": "composer/class-map-generator", - "version": "1.3.4", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/composer/class-map-generator.git", - "reference": "b1b3fd0b4eaf3ddf3ee230bc340bf3fff454a1a3" + "reference": "98bbf6780e56e0fd2404fe4b82eb665a0f93b783" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/class-map-generator/zipball/b1b3fd0b4eaf3ddf3ee230bc340bf3fff454a1a3", - "reference": "b1b3fd0b4eaf3ddf3ee230bc340bf3fff454a1a3", + "url": "https://api.github.com/repos/composer/class-map-generator/zipball/98bbf6780e56e0fd2404fe4b82eb665a0f93b783", + "reference": "98bbf6780e56e0fd2404fe4b82eb665a0f93b783", "shasum": "" }, "require": { @@ -311,8 +314,8 @@ "phpstan/phpstan-deprecation-rules": "^1", "phpstan/phpstan-phpunit": "^1", "phpstan/phpstan-strict-rules": "^1.1", - "symfony/filesystem": "^5.4 || ^6", - "symfony/phpunit-bridge": "^5" + "phpunit/phpunit": "^8", + "symfony/filesystem": "^5.4 || ^6" }, "type": "library", "extra": { @@ -342,7 +345,7 @@ ], "support": { "issues": "https://github.com/composer/class-map-generator/issues", - "source": "https://github.com/composer/class-map-generator/tree/1.3.4" + "source": "https://github.com/composer/class-map-generator/tree/1.4.0" }, "funding": [ { @@ -358,52 +361,52 @@ "type": "tidelift" } ], - "time": "2024-06-12T14:13:04+00:00" + "time": "2024-10-03T18:14:00+00:00" }, { "name": "composer/composer", - "version": "2.7.7", + "version": "2.8.2", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "291942978f39435cf904d33739f98d7d4eca7b23" + "reference": "6e543d03187c882ea1c6ba43add2467754427803" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/291942978f39435cf904d33739f98d7d4eca7b23", - "reference": "291942978f39435cf904d33739f98d7d4eca7b23", + "url": "https://api.github.com/repos/composer/composer/zipball/6e543d03187c882ea1c6ba43add2467754427803", + "reference": "6e543d03187c882ea1c6ba43add2467754427803", "shasum": "" }, "require": { - "composer/ca-bundle": "^1.0", - "composer/class-map-generator": "^1.3.3", + "composer/ca-bundle": "^1.5", + "composer/class-map-generator": "^1.4.0", "composer/metadata-minifier": "^1.0", - "composer/pcre": "^2.1 || ^3.1", + "composer/pcre": "^2.2 || ^3.2", "composer/semver": "^3.3", "composer/spdx-licenses": "^1.5.7", "composer/xdebug-handler": "^2.0.2 || ^3.0.3", - "justinrainbow/json-schema": "^5.2.11", + "justinrainbow/json-schema": "^5.3", "php": "^7.2.5 || ^8.0", "psr/log": "^1.0 || ^2.0 || ^3.0", - "react/promise": "^2.8 || ^3", + "react/promise": "^3.2", "seld/jsonlint": "^1.4", "seld/phar-utils": "^1.2", "seld/signal-handler": "^2.0", - "symfony/console": "^5.4.11 || ^6.0.11 || ^7", - "symfony/filesystem": "^5.4 || ^6.0 || ^7", - "symfony/finder": "^5.4 || ^6.0 || ^7", + "symfony/console": "^5.4.35 || ^6.3.12 || ^7.0.3", + "symfony/filesystem": "^5.4.35 || ^6.3.12 || ^7.0.3", + "symfony/finder": "^5.4.35 || ^6.3.12 || ^7.0.3", "symfony/polyfill-php73": "^1.24", "symfony/polyfill-php80": "^1.24", "symfony/polyfill-php81": "^1.24", - "symfony/process": "^5.4 || ^6.0 || ^7" + "symfony/process": "^5.4.35 || ^6.3.12 || ^7.0.3" }, "require-dev": { - "phpstan/phpstan": "^1.11.0", + "phpstan/phpstan": "^1.11.8", "phpstan/phpstan-deprecation-rules": "^1.2.0", "phpstan/phpstan-phpunit": "^1.4.0", "phpstan/phpstan-strict-rules": "^1.6.0", "phpstan/phpstan-symfony": "^1.4.0", - "symfony/phpunit-bridge": "^6.4.1 || ^7.0.1" + "symfony/phpunit-bridge": "^6.4.3 || ^7.0.1" }, "suggest": { "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", @@ -416,7 +419,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.7-dev" + "dev-main": "2.8-dev" }, "phpstan": { "includes": [ @@ -456,7 +459,7 @@ "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/composer/issues", "security": "https://github.com/composer/composer/security/policy", - "source": "https://github.com/composer/composer/tree/2.7.7" + "source": "https://github.com/composer/composer/tree/2.8.2" }, "funding": [ { @@ -472,7 +475,7 @@ "type": "tidelift" } ], - "time": "2024-06-10T20:11:12+00:00" + "time": "2024-10-29T15:12:11+00:00" }, { "name": "composer/installers", @@ -769,30 +772,38 @@ }, { "name": "composer/pcre", - "version": "3.1.4", + "version": "3.3.1", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "04229f163664973f68f38f6f73d917799168ef24" + "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/04229f163664973f68f38f6f73d917799168ef24", - "reference": "04229f163664973f68f38f6f73d917799168ef24", + "url": "https://api.github.com/repos/composer/pcre/zipball/63aaeac21d7e775ff9bc9d45021e1745c97521c4", + "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4", "shasum": "" }, "require": { "php": "^7.4 || ^8.0" }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, "require-dev": { - "phpstan/phpstan": "^1.3", + "phpstan/phpstan": "^1.11.10", "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^5" + "phpunit/phpunit": "^8 || ^9" }, "type": "library", "extra": { "branch-alias": { "dev-main": "3.x-dev" + }, + "phpstan": { + "includes": [ + "extension.neon" + ] } }, "autoload": { @@ -820,7 +831,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.1.4" + "source": "https://github.com/composer/pcre/tree/3.3.1" }, "funding": [ { @@ -836,28 +847,28 @@ "type": "tidelift" } ], - "time": "2024-05-27T13:40:54+00:00" + "time": "2024-08-27T18:44:43+00:00" }, { "name": "composer/semver", - "version": "3.4.0", + "version": "3.4.3", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32" + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32", + "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.4", - "symfony/phpunit-bridge": "^4.2 || ^5" + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" }, "type": "library", "extra": { @@ -901,7 +912,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.0" + "source": "https://github.com/composer/semver/tree/3.4.3" }, "funding": [ { @@ -917,7 +928,7 @@ "type": "tidelift" } ], - "time": "2023-08-31T09:50:34+00:00" + "time": "2024-09-19T14:15:21+00:00" }, { "name": "composer/spdx-licenses", @@ -1843,20 +1854,20 @@ }, { "name": "justinrainbow/json-schema", - "version": "v5.2.13", + "version": "5.3.0", "source": { "type": "git", "url": "https://github.com/jsonrainbow/json-schema.git", - "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793" + "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/fbbe7e5d79f618997bc3332a6f49246036c45793", - "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", + "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "require-dev": { "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", @@ -1867,11 +1878,6 @@ "bin/validate-json" ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0.x-dev" - } - }, "autoload": { "psr-4": { "JsonSchema\\": "src/JsonSchema/" @@ -1907,34 +1913,34 @@ ], "support": { "issues": "https://github.com/jsonrainbow/json-schema/issues", - "source": "https://github.com/jsonrainbow/json-schema/tree/v5.2.13" + "source": "https://github.com/jsonrainbow/json-schema/tree/5.3.0" }, - "time": "2023-09-26T02:20:38+00:00" + "time": "2024-07-06T21:00:26+00:00" }, { "name": "laminas/laminas-code", - "version": "4.13.0", + "version": "4.15.1", "source": { "type": "git", "url": "https://github.com/laminas/laminas-code.git", - "reference": "7353d4099ad5388e84737dd16994316a04f48dbf" + "reference": "877ad42fe9c164785182fca8afa3f416a056884d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-code/zipball/7353d4099ad5388e84737dd16994316a04f48dbf", - "reference": "7353d4099ad5388e84737dd16994316a04f48dbf", + "url": "https://api.github.com/repos/laminas/laminas-code/zipball/877ad42fe9c164785182fca8afa3f416a056884d", + "reference": "877ad42fe9c164785182fca8afa3f416a056884d", "shasum": "" }, "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0" + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, "require-dev": { "doctrine/annotations": "^2.0.1", "ext-phar": "*", - "laminas/laminas-coding-standard": "^2.5.0", - "laminas/laminas-stdlib": "^3.17.0", - "phpunit/phpunit": "^10.3.3", - "psalm/plugin-phpunit": "^0.18.4", + "laminas/laminas-coding-standard": "^3.0.0", + "laminas/laminas-stdlib": "^3.18.0", + "phpunit/phpunit": "^10.5.37", + "psalm/plugin-phpunit": "^0.19.0", "vimeo/psalm": "^5.15.0" }, "suggest": { @@ -1972,7 +1978,7 @@ "type": "community_bridge" } ], - "time": "2023-10-18T10:00:55+00:00" + "time": "2024-10-25T10:15:16+00:00" }, { "name": "marc1706/fast-image-size", @@ -2103,24 +2109,24 @@ }, { "name": "paragonie/constant_time_encoding", - "version": "v2.7.0", + "version": "v3.0.0", "source": { "type": "git", "url": "https://github.com/paragonie/constant_time_encoding.git", - "reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105" + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/52a0d99e69f56b9ec27ace92ba56897fe6993105", - "reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/df1e7fde177501eee2037dd159cf04f5f301a512", + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512", "shasum": "" }, "require": { - "php": "^7|^8" + "php": "^8" }, "require-dev": { - "phpunit/phpunit": "^6|^7|^8|^9", - "vimeo/psalm": "^1|^2|^3|^4" + "phpunit/phpunit": "^9", + "vimeo/psalm": "^4|^5" }, "type": "library", "autoload": { @@ -2166,84 +2172,39 @@ "issues": "https://github.com/paragonie/constant_time_encoding/issues", "source": "https://github.com/paragonie/constant_time_encoding" }, - "time": "2024-05-08T12:18:48+00:00" - }, - { - "name": "paragonie/random_compat", - "version": "v9.99.100", - "source": { - "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", - "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", - "shasum": "" - }, - "require": { - "php": ">= 7" - }, - "require-dev": { - "phpunit/phpunit": "4.*|5.*", - "vimeo/psalm": "^1" - }, - "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Paragon Initiative Enterprises", - "email": "security@paragonie.com", - "homepage": "https://paragonie.com" - } - ], - "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", - "keywords": [ - "csprng", - "polyfill", - "pseudorandom", - "random" - ], - "support": { - "email": "info@paragonie.com", - "issues": "https://github.com/paragonie/random_compat/issues", - "source": "https://github.com/paragonie/random_compat" - }, - "time": "2020-10-15T08:29:30+00:00" + "time": "2024-05-08T12:36:18+00:00" }, { "name": "paragonie/sodium_compat", - "version": "v1.21.1", + "version": "v2.1.0", "source": { "type": "git", "url": "https://github.com/paragonie/sodium_compat.git", - "reference": "bb312875dcdd20680419564fe42ba1d9564b9e37" + "reference": "a673d5f310477027cead2e2f2b6db5d8368157cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/bb312875dcdd20680419564fe42ba1d9564b9e37", - "reference": "bb312875dcdd20680419564fe42ba1d9564b9e37", + "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/a673d5f310477027cead2e2f2b6db5d8368157cb", + "reference": "a673d5f310477027cead2e2f2b6db5d8368157cb", "shasum": "" }, "require": { - "paragonie/random_compat": ">=1", - "php": "^5.2.4|^5.3|^5.4|^5.5|^5.6|^7|^8" + "php": "^8.1", + "php-64bit": "*" }, "require-dev": { - "phpunit/phpunit": "^3|^4|^5|^6|^7|^8|^9" + "phpunit/phpunit": "^7|^8|^9", + "vimeo/psalm": "^4|^5" }, "suggest": { - "ext-libsodium": "PHP < 7.0: Better performance, password hashing (Argon2i), secure memory management (memzero), and better security.", - "ext-sodium": "PHP >= 7.0: Better performance, password hashing (Argon2i), secure memory management (memzero), and better security." + "ext-sodium": "Better performance, password hashing (Argon2i), secure memory management (memzero), and better security." }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, "autoload": { "files": [ "autoload.php" @@ -2300,9 +2261,9 @@ ], "support": { "issues": "https://github.com/paragonie/sodium_compat/issues", - "source": "https://github.com/paragonie/sodium_compat/tree/v1.21.1" + "source": "https://github.com/paragonie/sodium_compat/tree/v2.1.0" }, - "time": "2024-04-22T22:05:04+00:00" + "time": "2024-09-04T12:51:01+00:00" }, { "name": "psr/cache", @@ -2666,16 +2627,16 @@ }, { "name": "psr/log", - "version": "3.0.0", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { @@ -2710,9 +2671,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2021-07-14T16:46:02+00:00" + "time": "2024-09-11T13:17:53+00:00" }, { "name": "ralouphie/getallheaders", @@ -2921,16 +2882,16 @@ }, { "name": "s9e/text-formatter", - "version": "2.17.3", + "version": "2.18.0", "source": { "type": "git", "url": "https://github.com/s9e/TextFormatter.git", - "reference": "9adf2557f13e45c4524d0dc9886cab22822e337a" + "reference": "4970711f25d94306b4835b723b9cc5010170ea37" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/s9e/TextFormatter/zipball/9adf2557f13e45c4524d0dc9886cab22822e337a", - "reference": "9adf2557f13e45c4524d0dc9886cab22822e337a", + "url": "https://api.github.com/repos/s9e/TextFormatter/zipball/4970711f25d94306b4835b723b9cc5010170ea37", + "reference": "4970711f25d94306b4835b723b9cc5010170ea37", "shasum": "" }, "require": { @@ -2958,7 +2919,7 @@ }, "type": "library", "extra": { - "version": "2.17.3" + "version": "2.18.0" }, "autoload": { "psr-4": { @@ -2990,29 +2951,29 @@ ], "support": { "issues": "https://github.com/s9e/TextFormatter/issues", - "source": "https://github.com/s9e/TextFormatter/tree/2.17.3" + "source": "https://github.com/s9e/TextFormatter/tree/2.18.0" }, - "time": "2024-05-26T00:00:08+00:00" + "time": "2024-07-24T14:50:52+00:00" }, { "name": "seld/jsonlint", - "version": "1.10.2", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "9bb7db07b5d66d90f6ebf542f09fc67d800e5259" + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/9bb7db07b5d66d90f6ebf542f09fc67d800e5259", - "reference": "9bb7db07b5d66d90f6ebf542f09fc67d800e5259", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/1748aaf847fc731cfad7725aec413ee46f0cc3a2", + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2", "shasum": "" }, "require": { "php": "^5.3 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.5", + "phpstan/phpstan": "^1.11", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^8.5.13" }, "bin": [ @@ -3044,7 +3005,7 @@ ], "support": { "issues": "https://github.com/Seldaek/jsonlint/issues", - "source": "https://github.com/Seldaek/jsonlint/tree/1.10.2" + "source": "https://github.com/Seldaek/jsonlint/tree/1.11.0" }, "funding": [ { @@ -3056,7 +3017,7 @@ "type": "tidelift" } ], - "time": "2024-02-07T12:57:50+00:00" + "time": "2024-07-11T14:55:45+00:00" }, { "name": "seld/phar-utils", @@ -3345,16 +3306,16 @@ }, { "name": "symfony/config", - "version": "v6.4.8", + "version": "v6.4.14", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "12e7e52515ce37191b193cf3365903c4f3951e35" + "reference": "4e55e7e4ffddd343671ea972216d4509f46c22ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/12e7e52515ce37191b193cf3365903c4f3951e35", - "reference": "12e7e52515ce37191b193cf3365903c4f3951e35", + "url": "https://api.github.com/repos/symfony/config/zipball/4e55e7e4ffddd343671ea972216d4509f46c22ef", + "reference": "4e55e7e4ffddd343671ea972216d4509f46c22ef", "shasum": "" }, "require": { @@ -3400,7 +3361,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v6.4.8" + "source": "https://github.com/symfony/config/tree/v6.4.14" }, "funding": [ { @@ -3416,20 +3377,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-11-04T11:33:53+00:00" }, { "name": "symfony/console", - "version": "v6.4.8", + "version": "v6.4.14", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "be5854cee0e8c7b110f00d695d11debdfa1a2a91" + "reference": "897c2441ed4eec8a8a2c37b943427d24dba3f26b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/be5854cee0e8c7b110f00d695d11debdfa1a2a91", - "reference": "be5854cee0e8c7b110f00d695d11debdfa1a2a91", + "url": "https://api.github.com/repos/symfony/console/zipball/897c2441ed4eec8a8a2c37b943427d24dba3f26b", + "reference": "897c2441ed4eec8a8a2c37b943427d24dba3f26b", "shasum": "" }, "require": { @@ -3494,7 +3455,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.8" + "source": "https://github.com/symfony/console/tree/v6.4.14" }, "funding": [ { @@ -3510,20 +3471,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-11-05T15:34:40+00:00" }, { "name": "symfony/dependency-injection", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "d3b618176e8c3a9e5772151c51eba0c52a0c771c" + "reference": "728ae8f4e190133ce99d6d5f0bc1e8c8bd7c7a96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/d3b618176e8c3a9e5772151c51eba0c52a0c771c", - "reference": "d3b618176e8c3a9e5772151c51eba0c52a0c771c", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/728ae8f4e190133ce99d6d5f0bc1e8c8bd7c7a96", + "reference": "728ae8f4e190133ce99d6d5f0bc1e8c8bd7c7a96", "shasum": "" }, "require": { @@ -3575,7 +3536,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v6.4.8" + "source": "https://github.com/symfony/dependency-injection/tree/v6.4.13" }, "funding": [ { @@ -3591,7 +3552,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-10-25T15:07:50+00:00" }, { "name": "symfony/deprecation-contracts", @@ -3662,16 +3623,16 @@ }, { "name": "symfony/error-handler", - "version": "v6.4.8", + "version": "v6.4.14", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "ef836152bf13472dc5fb5b08b0c0c4cfeddc0fcc" + "reference": "9e024324511eeb00983ee76b9aedc3e6ecd993d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/ef836152bf13472dc5fb5b08b0c0c4cfeddc0fcc", - "reference": "ef836152bf13472dc5fb5b08b0c0c4cfeddc0fcc", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/9e024324511eeb00983ee76b9aedc3e6ecd993d9", + "reference": "9e024324511eeb00983ee76b9aedc3e6ecd993d9", "shasum": "" }, "require": { @@ -3717,7 +3678,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v6.4.8" + "source": "https://github.com/symfony/error-handler/tree/v6.4.14" }, "funding": [ { @@ -3733,20 +3694,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-11-05T15:34:40+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "8d7507f02b06e06815e56bb39aa0128e3806208b" + "reference": "0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8d7507f02b06e06815e56bb39aa0128e3806208b", - "reference": "8d7507f02b06e06815e56bb39aa0128e3806208b", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e", + "reference": "0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e", "shasum": "" }, "require": { @@ -3797,7 +3758,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.8" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.13" }, "funding": [ { @@ -3813,7 +3774,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -3893,16 +3854,16 @@ }, { "name": "symfony/filesystem", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "4d37529150e7081c51b3c5d5718c55a04a9503f3" + "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/4d37529150e7081c51b3c5d5718c55a04a9503f3", - "reference": "4d37529150e7081c51b3c5d5718c55a04a9503f3", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/4856c9cf585d5a0313d8d35afd681a526f038dd3", + "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3", "shasum": "" }, "require": { @@ -3939,7 +3900,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.8" + "source": "https://github.com/symfony/filesystem/tree/v6.4.13" }, "funding": [ { @@ -3955,20 +3916,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-10-25T15:07:50+00:00" }, { "name": "symfony/finder", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "3ef977a43883215d560a2cecb82ec8e62131471c" + "reference": "daea9eca0b08d0ed1dc9ab702a46128fd1be4958" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/3ef977a43883215d560a2cecb82ec8e62131471c", - "reference": "3ef977a43883215d560a2cecb82ec8e62131471c", + "url": "https://api.github.com/repos/symfony/finder/zipball/daea9eca0b08d0ed1dc9ab702a46128fd1be4958", + "reference": "daea9eca0b08d0ed1dc9ab702a46128fd1be4958", "shasum": "" }, "require": { @@ -4003,7 +3964,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.4.8" + "source": "https://github.com/symfony/finder/tree/v6.4.13" }, "funding": [ { @@ -4019,20 +3980,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-10-01T08:30:56+00:00" }, { "name": "symfony/http-client", - "version": "v6.4.8", + "version": "v6.4.14", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "61faba993e620fc22d4f0ab3b6bcf8fbb0d44b05" + "reference": "05d88cbd816ad6e0202edd9a9963cb9d615b8826" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/61faba993e620fc22d4f0ab3b6bcf8fbb0d44b05", - "reference": "61faba993e620fc22d4f0ab3b6bcf8fbb0d44b05", + "url": "https://api.github.com/repos/symfony/http-client/zipball/05d88cbd816ad6e0202edd9a9963cb9d615b8826", + "reference": "05d88cbd816ad6e0202edd9a9963cb9d615b8826", "shasum": "" }, "require": { @@ -4096,7 +4057,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.4.8" + "source": "https://github.com/symfony/http-client/tree/v6.4.14" }, "funding": [ { @@ -4112,7 +4073,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-11-05T16:39:55+00:00" }, { "name": "symfony/http-client-contracts", @@ -4194,16 +4155,16 @@ }, { "name": "symfony/http-foundation", - "version": "v6.4.8", + "version": "v6.4.14", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "27de8cc95e11db7a50b027e71caaab9024545947" + "reference": "ba020a321a95519303a3f09ec2824d34d601c388" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/27de8cc95e11db7a50b027e71caaab9024545947", - "reference": "27de8cc95e11db7a50b027e71caaab9024545947", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ba020a321a95519303a3f09ec2824d34d601c388", + "reference": "ba020a321a95519303a3f09ec2824d34d601c388", "shasum": "" }, "require": { @@ -4251,7 +4212,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.4.8" + "source": "https://github.com/symfony/http-foundation/tree/v6.4.14" }, "funding": [ { @@ -4267,20 +4228,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-11-05T16:39:55+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.4.8", + "version": "v6.4.14", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "6c519aa3f32adcfd1d1f18d923f6b227d9acf3c1" + "reference": "8278a947d0369754a47b758a9e17b72cab970951" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6c519aa3f32adcfd1d1f18d923f6b227d9acf3c1", - "reference": "6c519aa3f32adcfd1d1f18d923f6b227d9acf3c1", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/8278a947d0369754a47b758a9e17b72cab970951", + "reference": "8278a947d0369754a47b758a9e17b72cab970951", "shasum": "" }, "require": { @@ -4365,7 +4326,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.4.8" + "source": "https://github.com/symfony/http-kernel/tree/v6.4.14" }, "funding": [ { @@ -4381,20 +4342,20 @@ "type": "tidelift" } ], - "time": "2024-06-02T16:06:25+00:00" + "time": "2024-11-06T09:45:21+00:00" }, { "name": "symfony/mime", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "618597ab8b78ac86d1c75a9d0b35540cda074f33" + "reference": "1de1cf14d99b12c7ebbb850491ec6ae3ed468855" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/618597ab8b78ac86d1c75a9d0b35540cda074f33", - "reference": "618597ab8b78ac86d1c75a9d0b35540cda074f33", + "url": "https://api.github.com/repos/symfony/mime/zipball/1de1cf14d99b12c7ebbb850491ec6ae3ed468855", + "reference": "1de1cf14d99b12c7ebbb850491ec6ae3ed468855", "shasum": "" }, "require": { @@ -4408,7 +4369,7 @@ "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/mailer": "<5.4", - "symfony/serializer": "<6.3.2" + "symfony/serializer": "<6.4.3|>7.0,<7.0.3" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3.1|^4", @@ -4418,7 +4379,7 @@ "symfony/process": "^5.4|^6.4|^7.0", "symfony/property-access": "^5.4|^6.0|^7.0", "symfony/property-info": "^5.4|^6.0|^7.0", - "symfony/serializer": "^6.3.2|^7.0" + "symfony/serializer": "^6.4.3|^7.0.3" }, "type": "library", "autoload": { @@ -4450,7 +4411,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v6.4.8" + "source": "https://github.com/symfony/mime/tree/v6.4.13" }, "funding": [ { @@ -4466,24 +4427,24 @@ "type": "tidelift" } ], - "time": "2024-06-01T07:50:16+00:00" + "time": "2024-10-25T15:07:50+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -4529,7 +4490,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" }, "funding": [ { @@ -4545,24 +4506,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f" + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f", - "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -4607,7 +4568,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" }, "funding": [ { @@ -4623,26 +4584,25 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "a287ed7475f85bf6f61890146edbc932c0fff919" + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/a287ed7475f85bf6f61890146edbc932c0fff919", - "reference": "a287ed7475f85bf6f61890146edbc932c0fff919", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", "shasum": "" }, "require": { - "php": ">=7.1", - "symfony/polyfill-intl-normalizer": "^1.10", - "symfony/polyfill-php72": "^1.10" + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" }, "suggest": { "ext-intl": "For best performance" @@ -4691,7 +4651,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" }, "funding": [ { @@ -4707,24 +4667,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "bc45c394692b948b4d383a08d7753968bed9a83d" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d", - "reference": "bc45c394692b948b4d383a08d7753968bed9a83d", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -4772,7 +4732,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" }, "funding": [ { @@ -4788,24 +4748,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -4852,7 +4812,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" }, "funding": [ { @@ -4868,97 +4828,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" - }, - { - "name": "symfony/polyfill-php72", - "version": "v1.29.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/861391a8da9a04cbad2d232ddd9e4893220d6e25", - "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.29.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "21bd091060673a1177ae842c0ef8fe30893114d2" + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/21bd091060673a1177ae842c0ef8fe30893114d2", - "reference": "21bd091060673a1177ae842c0ef8fe30893114d2", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { @@ -5001,7 +4888,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.31.0" }, "funding": [ { @@ -5017,24 +4904,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", - "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { @@ -5081,7 +4968,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" }, "funding": [ { @@ -5097,24 +4984,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "c565ad1e63f30e7477fc40738343c62b40bc672d" + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/c565ad1e63f30e7477fc40738343c62b40bc672d", - "reference": "c565ad1e63f30e7477fc40738343c62b40bc672d", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { @@ -5157,7 +5044,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0" }, "funding": [ { @@ -5173,25 +5060,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php83", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "86fcae159633351e5fd145d1c47de6c528f8caff" + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/86fcae159633351e5fd145d1c47de6c528f8caff", - "reference": "86fcae159633351e5fd145d1c47de6c528f8caff", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", "shasum": "" }, "require": { - "php": ">=7.1", - "symfony/polyfill-php80": "^1.14" + "php": ">=7.2" }, "type": "library", "extra": { @@ -5234,7 +5120,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.31.0" }, "funding": [ { @@ -5250,20 +5136,20 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/process", - "version": "v6.4.8", + "version": "v6.4.14", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "8d92dd79149f29e89ee0f480254db595f6a6a2c5" + "reference": "25214adbb0996d18112548de20c281be9f27279f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/8d92dd79149f29e89ee0f480254db595f6a6a2c5", - "reference": "8d92dd79149f29e89ee0f480254db595f6a6a2c5", + "url": "https://api.github.com/repos/symfony/process/zipball/25214adbb0996d18112548de20c281be9f27279f", + "reference": "25214adbb0996d18112548de20c281be9f27279f", "shasum": "" }, "require": { @@ -5295,7 +5181,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.4.8" + "source": "https://github.com/symfony/process/tree/v6.4.14" }, "funding": [ { @@ -5311,20 +5197,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-11-06T09:25:01+00:00" }, { "name": "symfony/proxy-manager-bridge", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/proxy-manager-bridge.git", - "reference": "b8119e0b248ef0711c25cd09acc729102122621c" + "reference": "8932b572e147e80fb498045c580eb14215197529" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/proxy-manager-bridge/zipball/b8119e0b248ef0711c25cd09acc729102122621c", - "reference": "b8119e0b248ef0711c25cd09acc729102122621c", + "url": "https://api.github.com/repos/symfony/proxy-manager-bridge/zipball/8932b572e147e80fb498045c580eb14215197529", + "reference": "8932b572e147e80fb498045c580eb14215197529", "shasum": "" }, "require": { @@ -5362,7 +5248,7 @@ "description": "Provides integration for ProxyManager with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/proxy-manager-bridge/tree/v6.4.8" + "source": "https://github.com/symfony/proxy-manager-bridge/tree/v6.4.13" }, "funding": [ { @@ -5378,20 +5264,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/routing", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "8a40d0f9b01f0fbb80885d3ce0ad6714fb603a58" + "reference": "640a74250d13f9c30d5ca045b6aaaabcc8215278" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/8a40d0f9b01f0fbb80885d3ce0ad6714fb603a58", - "reference": "8a40d0f9b01f0fbb80885d3ce0ad6714fb603a58", + "url": "https://api.github.com/repos/symfony/routing/zipball/640a74250d13f9c30d5ca045b6aaaabcc8215278", + "reference": "640a74250d13f9c30d5ca045b6aaaabcc8215278", "shasum": "" }, "require": { @@ -5445,7 +5331,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v6.4.8" + "source": "https://github.com/symfony/routing/tree/v6.4.13" }, "funding": [ { @@ -5461,7 +5347,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-10-01T08:30:56+00:00" }, { "name": "symfony/service-contracts", @@ -5548,16 +5434,16 @@ }, { "name": "symfony/string", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "a147c0f826c4a1f3afb763ab8e009e37c877a44d" + "reference": "38371c60c71c72b3d64d8d76f6b1bb81a2cc3627" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/a147c0f826c4a1f3afb763ab8e009e37c877a44d", - "reference": "a147c0f826c4a1f3afb763ab8e009e37c877a44d", + "url": "https://api.github.com/repos/symfony/string/zipball/38371c60c71c72b3d64d8d76f6b1bb81a2cc3627", + "reference": "38371c60c71c72b3d64d8d76f6b1bb81a2cc3627", "shasum": "" }, "require": { @@ -5614,7 +5500,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.8" + "source": "https://github.com/symfony/string/tree/v6.4.13" }, "funding": [ { @@ -5630,7 +5516,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/translation-contracts", @@ -5712,16 +5598,16 @@ }, { "name": "symfony/twig-bridge", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "57de1b7d7499053a2c5beb9344751e8bfd332649" + "reference": "ec3511eef0576f378b2758da9e1c157086babd59" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/57de1b7d7499053a2c5beb9344751e8bfd332649", - "reference": "57de1b7d7499053a2c5beb9344751e8bfd332649", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/ec3511eef0576f378b2758da9e1c157086babd59", + "reference": "ec3511eef0576f378b2758da9e1c157086babd59", "shasum": "" }, "require": { @@ -5801,7 +5687,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v6.4.8" + "source": "https://github.com/symfony/twig-bridge/tree/v6.4.13" }, "funding": [ { @@ -5817,20 +5703,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-10-25T15:07:50+00:00" }, { "name": "symfony/var-dumper", - "version": "v6.4.8", + "version": "v6.4.14", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "ad23ca4312395f0a8a8633c831ef4c4ee542ed25" + "reference": "93c09246038178717a9c14b809ea8151ffcf7091" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/ad23ca4312395f0a8a8633c831ef4c4ee542ed25", - "reference": "ad23ca4312395f0a8a8633c831ef4c4ee542ed25", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/93c09246038178717a9c14b809ea8151ffcf7091", + "reference": "93c09246038178717a9c14b809ea8151ffcf7091", "shasum": "" }, "require": { @@ -5886,7 +5772,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.4.8" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.14" }, "funding": [ { @@ -5902,20 +5788,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-11-05T15:34:40+00:00" }, { "name": "symfony/var-exporter", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "792ca836f99b340f2e9ca9497c7953948c49a504" + "reference": "0f605f72a363f8743001038a176eeb2a11223b51" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/792ca836f99b340f2e9ca9497c7953948c49a504", - "reference": "792ca836f99b340f2e9ca9497c7953948c49a504", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/0f605f72a363f8743001038a176eeb2a11223b51", + "reference": "0f605f72a363f8743001038a176eeb2a11223b51", "shasum": "" }, "require": { @@ -5963,7 +5849,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.4.8" + "source": "https://github.com/symfony/var-exporter/tree/v6.4.13" }, "funding": [ { @@ -5979,20 +5865,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/yaml", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "52903de178d542850f6f341ba92995d3d63e60c9" + "reference": "e99b4e94d124b29ee4cf3140e1b537d2dad8cec9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/52903de178d542850f6f341ba92995d3d63e60c9", - "reference": "52903de178d542850f6f341ba92995d3d63e60c9", + "url": "https://api.github.com/repos/symfony/yaml/zipball/e99b4e94d124b29ee4cf3140e1b537d2dad8cec9", + "reference": "e99b4e94d124b29ee4cf3140e1b537d2dad8cec9", "shasum": "" }, "require": { @@ -6035,7 +5921,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.4.8" + "source": "https://github.com/symfony/yaml/tree/v6.4.13" }, "funding": [ { @@ -6051,34 +5937,41 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "twig/twig", - "version": "v3.8.0", + "version": "v3.14.2", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d" + "reference": "0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/9d15f0ac07f44dc4217883ec6ae02fd555c6f71d", - "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a", + "reference": "0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.0.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-mbstring": "^1.3", - "symfony/polyfill-php80": "^1.22" + "symfony/polyfill-php81": "^1.29" }, "require-dev": { "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.4.9|^6.3|^7.0" + "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" }, "type": "library", "autoload": { + "files": [ + "src/Resources/core.php", + "src/Resources/debug.php", + "src/Resources/escaper.php", + "src/Resources/string_loader.php" + ], "psr-4": { "Twig\\": "src/" } @@ -6111,7 +6004,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.8.0" + "source": "https://github.com/twigphp/Twig/tree/v3.14.2" }, "funding": [ { @@ -6123,11 +6016,11 @@ "type": "tidelift" } ], - "time": "2023-11-21T18:54:41+00:00" + "time": "2024-11-07T12:36:22+00:00" }, { "name": "web-token/jwt-key-mgmt", - "version": "3.4.3", + "version": "3.4.6", "source": { "type": "git", "url": "https://github.com/web-token/jwt-key-mgmt.git", @@ -6182,7 +6075,7 @@ "symfony" ], "support": { - "source": "https://github.com/web-token/jwt-key-mgmt/tree/3.4.3" + "source": "https://github.com/web-token/jwt-key-mgmt/tree/3.4.6" }, "funding": [ { @@ -6195,24 +6088,24 @@ }, { "name": "web-token/jwt-library", - "version": "3.4.3", + "version": "3.4.6", "source": { "type": "git", "url": "https://github.com/web-token/jwt-library.git", - "reference": "4b09510eec25c328525048cbdf6042a39a7c28d8" + "reference": "1a25c8ced3e2b3c31d32dcfad215cbd8cb812f28" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-token/jwt-library/zipball/4b09510eec25c328525048cbdf6042a39a7c28d8", - "reference": "4b09510eec25c328525048cbdf6042a39a7c28d8", + "url": "https://api.github.com/repos/web-token/jwt-library/zipball/1a25c8ced3e2b3c31d32dcfad215cbd8cb812f28", + "reference": "1a25c8ced3e2b3c31d32dcfad215cbd8cb812f28", "shasum": "" }, "require": { "brick/math": "^0.9|^0.10|^0.11|^0.12", "ext-json": "*", "ext-mbstring": "*", - "paragonie/constant_time_encoding": "^2.6", - "paragonie/sodium_compat": "^1.20", + "paragonie/constant_time_encoding": "^2.6|^3.0", + "paragonie/sodium_compat": "^1.20|^2.0", "php": ">=8.1", "psr/cache": "^3.0", "psr/clock": "^1.0", @@ -6277,7 +6170,7 @@ ], "support": { "issues": "https://github.com/web-token/jwt-library/issues", - "source": "https://github.com/web-token/jwt-library/tree/3.4.3" + "source": "https://github.com/web-token/jwt-library/tree/3.4.6" }, "funding": [ { @@ -6289,11 +6182,11 @@ "type": "patreon" } ], - "time": "2024-04-17T17:41:33+00:00" + "time": "2024-07-02T16:35:11+00:00" }, { "name": "web-token/jwt-signature", - "version": "3.4.3", + "version": "3.4.6", "source": { "type": "git", "url": "https://github.com/web-token/jwt-signature.git", @@ -6345,7 +6238,7 @@ "symfony" ], "support": { - "source": "https://github.com/web-token/jwt-signature/tree/3.4.3" + "source": "https://github.com/web-token/jwt-signature/tree/3.4.6" }, "funding": [ { @@ -6358,7 +6251,7 @@ }, { "name": "web-token/jwt-signature-algorithm-ecdsa", - "version": "3.4.3", + "version": "3.4.6", "source": { "type": "git", "url": "https://github.com/web-token/jwt-signature-algorithm-ecdsa.git", @@ -6411,7 +6304,7 @@ "symfony" ], "support": { - "source": "https://github.com/web-token/jwt-signature-algorithm-ecdsa/tree/3.4.3" + "source": "https://github.com/web-token/jwt-signature-algorithm-ecdsa/tree/3.4.6" }, "funding": [ { @@ -6424,7 +6317,7 @@ }, { "name": "web-token/jwt-util-ecc", - "version": "3.4.3", + "version": "3.4.6", "source": { "type": "git", "url": "https://github.com/web-token/jwt-util-ecc.git", @@ -6477,7 +6370,7 @@ "symfony" ], "support": { - "source": "https://github.com/web-token/jwt-util-ecc/tree/3.4.3" + "source": "https://github.com/web-token/jwt-util-ecc/tree/3.4.6" }, "funding": [ { @@ -6804,16 +6697,16 @@ }, { "name": "felixfbecker/language-server-protocol", - "version": "v1.5.2", + "version": "v1.5.3", "source": { "type": "git", "url": "https://github.com/felixfbecker/php-language-server-protocol.git", - "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842" + "reference": "a9e113dbc7d849e35b8776da39edaf4313b7b6c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/6e82196ffd7c62f7794d778ca52b69feec9f2842", - "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842", + "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/a9e113dbc7d849e35b8776da39edaf4313b7b6c9", + "reference": "a9e113dbc7d849e35b8776da39edaf4313b7b6c9", "shasum": "" }, "require": { @@ -6854,22 +6747,22 @@ ], "support": { "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues", - "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.2" + "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.3" }, - "time": "2022-03-02T22:36:06+00:00" + "time": "2024-04-30T00:40:11+00:00" }, { "name": "fidry/cpu-core-counter", - "version": "1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42" + "reference": "8520451a140d3f46ac33042715115e290cf5785f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/f92996c4d5c1a696a6a970e20f7c4216200fcc42", - "reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f", + "reference": "8520451a140d3f46ac33042715115e290cf5785f", "shasum": "" }, "require": { @@ -6909,7 +6802,7 @@ ], "support": { "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/1.1.0" + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0" }, "funding": [ { @@ -6917,7 +6810,7 @@ "type": "github" } ], - "time": "2024-02-07T09:43:46+00:00" + "time": "2024-08-06T10:04:20+00:00" }, { "name": "laravel/homestead", @@ -7097,16 +6990,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.12.0", + "version": "1.12.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" + "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845", + "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845", "shasum": "" }, "require": { @@ -7145,7 +7038,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.12.1" }, "funding": [ { @@ -7153,20 +7046,20 @@ "type": "tidelift" } ], - "time": "2024-06-12T14:39:25+00:00" + "time": "2024-11-08T17:47:46+00:00" }, { "name": "netresearch/jsonmapper", - "version": "v4.4.1", + "version": "v4.5.0", "source": { "type": "git", "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0" + "reference": "8e76efb98ee8b6afc54687045e1b8dba55ac76e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/132c75c7dd83e45353ebb9c6c9f591952995bbf0", - "reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8e76efb98ee8b6afc54687045e1b8dba55ac76e5", + "reference": "8e76efb98ee8b6afc54687045e1b8dba55ac76e5", "shasum": "" }, "require": { @@ -7202,22 +7095,22 @@ "support": { "email": "cweiske@cweiske.de", "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/v4.4.1" + "source": "https://github.com/cweiske/jsonmapper/tree/v4.5.0" }, - "time": "2024-01-31T06:18:54+00:00" + "time": "2024-09-08T10:13:13+00:00" }, { "name": "nikic/php-parser", - "version": "v4.19.1", + "version": "v4.19.4", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b" + "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4e1b88d21c69391150ace211e9eaf05810858d0b", - "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/715f4d25e225bc47b293a8b997fe6ce99bf987d2", + "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2", "shasum": "" }, "require": { @@ -7226,7 +7119,7 @@ }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "bin": [ "bin/php-parse" @@ -7258,9 +7151,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.4" }, - "time": "2024-03-17T08:10:35+00:00" + "time": "2024-09-29T15:01:53+00:00" }, { "name": "phar-io/manifest", @@ -7547,16 +7440,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.4.1", + "version": "5.5.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c" + "reference": "0c70d2c566e899666f367ab7b80986beb3581e6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", - "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/0c70d2c566e899666f367ab7b80986beb3581e6f", + "reference": "0c70d2c566e899666f367ab7b80986beb3581e6f", "shasum": "" }, "require": { @@ -7569,13 +7462,13 @@ "webmozart/assert": "^1.9.1" }, "require-dev": { - "mockery/mockery": "~1.3.5", + "mockery/mockery": "~1.3.5 || ~1.6.0", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.8", "phpstan/phpstan-mockery": "^1.1", "phpstan/phpstan-webmozart-assert": "^1.2", "phpunit/phpunit": "^9.5", - "vimeo/psalm": "^5.13" + "psalm/phar": "^5.26" }, "type": "library", "extra": { @@ -7605,29 +7498,29 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.1" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.5.1" }, - "time": "2024-05-21T05:55:05+00:00" + "time": "2024-11-06T11:58:54+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.8.2", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "153ae662783729388a584b4361f2545e4d841e3c" + "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/153ae662783729388a584b4361f2545e4d841e3c", - "reference": "153ae662783729388a584b4361f2545e4d841e3c", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a", + "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a", "shasum": "" }, "require": { "doctrine/deprecations": "^1.0", "php": "^7.3 || ^8.0", "phpdocumentor/reflection-common": "^2.0", - "phpstan/phpdoc-parser": "^1.13" + "phpstan/phpdoc-parser": "^1.18|^2.0" }, "require-dev": { "ext-tokenizer": "*", @@ -7663,22 +7556,22 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.2" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0" }, - "time": "2024-02-23T11:10:43+00:00" + "time": "2024-11-09T15:12:26+00:00" }, { "name": "phpstan/phpdoc-parser", - "version": "1.29.1", + "version": "1.33.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4" + "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fcaefacf2d5c417e928405b71b400d4ce10daaf4", - "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/82a311fd3690fb2bf7b64d5c98f912b3dd746140", + "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140", "shasum": "" }, "require": { @@ -7710,41 +7603,41 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.33.0" }, - "time": "2024-05-31T08:52:43+00:00" + "time": "2024-10-13T11:25:22+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.31", + "version": "9.2.32", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965" + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965", - "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.18 || ^5.0", + "nikic/php-parser": "^4.19.1 || ^5.1.0", "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-text-template": "^2.0.4", + "sebastian/code-unit-reverse-lookup": "^2.0.3", + "sebastian/complexity": "^2.0.3", + "sebastian/environment": "^5.1.5", + "sebastian/lines-of-code": "^1.0.4", + "sebastian/version": "^3.0.2", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.6" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -7753,7 +7646,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-main": "9.2.x-dev" } }, "autoload": { @@ -7782,7 +7675,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32" }, "funding": [ { @@ -7790,7 +7683,7 @@ "type": "github" } ], - "time": "2024-03-02T06:37:42+00:00" + "time": "2024-08-22T04:23:01+00:00" }, { "name": "phpunit/php-file-iterator", @@ -8035,45 +7928,45 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.19", + "version": "9.6.21", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8" + "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1a54a473501ef4cdeaae4e06891674114d79db8", - "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", + "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1 || ^2", + "doctrine/instantiator": "^1.5.0 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.3", - "phar-io/version": "^3.0.2", + "myclabs/deep-copy": "^1.12.0", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.28", - "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-code-coverage": "^9.2.32", + "phpunit/php-file-iterator": "^3.0.6", "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", + "phpunit/php-text-template": "^2.0.4", + "phpunit/php-timer": "^5.0.3", + "sebastian/cli-parser": "^1.0.2", + "sebastian/code-unit": "^1.0.8", "sebastian/comparator": "^4.0.8", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.5", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.2", + "sebastian/diff": "^4.0.6", + "sebastian/environment": "^5.1.5", + "sebastian/exporter": "^4.0.6", + "sebastian/global-state": "^5.0.7", + "sebastian/object-enumerator": "^4.0.4", + "sebastian/resource-operations": "^3.0.4", + "sebastian/type": "^3.2.1", "sebastian/version": "^3.0.2" }, "suggest": { @@ -8118,7 +8011,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.19" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.21" }, "funding": [ { @@ -8134,27 +8027,27 @@ "type": "tidelift" } ], - "time": "2024-04-05T04:35:58+00:00" + "time": "2024-09-19T10:50:18+00:00" }, { "name": "psalm/plugin-symfony", - "version": "v5.2.2", + "version": "v5.2.5", "source": { "type": "git", "url": "https://github.com/psalm/psalm-plugin-symfony.git", - "reference": "58e109257764e8e7eab10a43a4212bbd70435f67" + "reference": "fb801a9b3d12ace9fb619febfaa3ae0bc1dbb196" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/psalm/psalm-plugin-symfony/zipball/58e109257764e8e7eab10a43a4212bbd70435f67", - "reference": "58e109257764e8e7eab10a43a4212bbd70435f67", + "url": "https://api.github.com/repos/psalm/psalm-plugin-symfony/zipball/fb801a9b3d12ace9fb619febfaa3ae0bc1dbb196", + "reference": "fb801a9b3d12ace9fb619febfaa3ae0bc1dbb196", "shasum": "" }, "require": { "ext-simplexml": "*", "php": "^8.1", "symfony/framework-bundle": "^5.0 || ^6.0 || ^7.0", - "vimeo/psalm": "^5.24" + "vimeo/psalm": "^5.16" }, "require-dev": { "doctrine/annotations": "^1.8|^2", @@ -8197,9 +8090,9 @@ "description": "Psalm Plugin for Symfony", "support": { "issues": "https://github.com/psalm/psalm-plugin-symfony/issues", - "source": "https://github.com/psalm/psalm-plugin-symfony/tree/v5.2.2" + "source": "https://github.com/psalm/psalm-plugin-symfony/tree/v5.2.5" }, - "time": "2024-06-06T15:34:33+00:00" + "time": "2024-07-03T11:57:02+00:00" }, { "name": "sebastian/cli-parser", @@ -9234,16 +9127,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.10.1", + "version": "3.10.3", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "8f90f7a53ce271935282967f53d0894f8f1ff877" + "reference": "62d32998e820bddc40f99f8251958aed187a5c9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/8f90f7a53ce271935282967f53d0894f8f1ff877", - "reference": "8f90f7a53ce271935282967f53d0894f8f1ff877", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/62d32998e820bddc40f99f8251958aed187a5c9c", + "reference": "62d32998e820bddc40f99f8251958aed187a5c9c", "shasum": "" }, "require": { @@ -9310,20 +9203,20 @@ "type": "open_collective" } ], - "time": "2024-05-22T21:24:41+00:00" + "time": "2024-09-18T10:38:58+00:00" }, { "name": "symfony/browser-kit", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "62ab90b92066ef6cce5e79365625b4b1432464c8" + "reference": "65d4b3fd9556e4b5b41287bef93c671f8f9f86ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/62ab90b92066ef6cce5e79365625b4b1432464c8", - "reference": "62ab90b92066ef6cce5e79365625b4b1432464c8", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/65d4b3fd9556e4b5b41287bef93c671f8f9f86ab", + "reference": "65d4b3fd9556e4b5b41287bef93c671f8f9f86ab", "shasum": "" }, "require": { @@ -9362,7 +9255,7 @@ "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/browser-kit/tree/v6.4.8" + "source": "https://github.com/symfony/browser-kit/tree/v6.4.13" }, "funding": [ { @@ -9378,20 +9271,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-10-25T15:07:50+00:00" }, { "name": "symfony/cache", - "version": "v6.4.8", + "version": "v6.4.14", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "287142df5579ce223c485b3872df3efae8390984" + "reference": "36fb8aa88833708e9f29014b6f15fac051a8b613" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/287142df5579ce223c485b3872df3efae8390984", - "reference": "287142df5579ce223c485b3872df3efae8390984", + "url": "https://api.github.com/repos/symfony/cache/zipball/36fb8aa88833708e9f29014b6f15fac051a8b613", + "reference": "36fb8aa88833708e9f29014b6f15fac051a8b613", "shasum": "" }, "require": { @@ -9458,7 +9351,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.4.8" + "source": "https://github.com/symfony/cache/tree/v6.4.14" }, "funding": [ { @@ -9474,7 +9367,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-11-05T15:34:40+00:00" }, { "name": "symfony/cache-contracts", @@ -9554,16 +9447,16 @@ }, { "name": "symfony/css-selector", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "4b61b02fe15db48e3687ce1c45ea385d1780fe08" + "reference": "cb23e97813c5837a041b73a6d63a9ddff0778f5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/4b61b02fe15db48e3687ce1c45ea385d1780fe08", - "reference": "4b61b02fe15db48e3687ce1c45ea385d1780fe08", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/cb23e97813c5837a041b73a6d63a9ddff0778f5e", + "reference": "cb23e97813c5837a041b73a6d63a9ddff0778f5e", "shasum": "" }, "require": { @@ -9599,7 +9492,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v6.4.8" + "source": "https://github.com/symfony/css-selector/tree/v6.4.13" }, "funding": [ { @@ -9615,20 +9508,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/dom-crawler", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "105b56a0305d219349edeb60a800082eca864e4b" + "reference": "ae074dffb018c37a57071990d16e6152728dd972" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/105b56a0305d219349edeb60a800082eca864e4b", - "reference": "105b56a0305d219349edeb60a800082eca864e4b", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/ae074dffb018c37a57071990d16e6152728dd972", + "reference": "ae074dffb018c37a57071990d16e6152728dd972", "shasum": "" }, "require": { @@ -9666,7 +9559,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v6.4.8" + "source": "https://github.com/symfony/dom-crawler/tree/v6.4.13" }, "funding": [ { @@ -9682,20 +9575,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-10-25T15:07:50+00:00" }, { "name": "symfony/framework-bundle", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "7c7739f87f1a8be1c2f5e7d28addfe763a917acb" + "reference": "e8b0bd921f9bd35ea4d1508067c3f3f6e2036418" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/7c7739f87f1a8be1c2f5e7d28addfe763a917acb", - "reference": "7c7739f87f1a8be1c2f5e7d28addfe763a917acb", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/e8b0bd921f9bd35ea4d1508067c3f3f6e2036418", + "reference": "e8b0bd921f9bd35ea4d1508067c3f3f6e2036418", "shasum": "" }, "require": { @@ -9704,7 +9597,7 @@ "php": ">=8.1", "symfony/cache": "^5.4|^6.0|^7.0", "symfony/config": "^6.1|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4.12|^7.0", "symfony/deprecation-contracts": "^2.5|^3", "symfony/error-handler": "^6.1|^7.0", "symfony/event-dispatcher": "^5.4|^6.0|^7.0", @@ -9734,6 +9627,7 @@ "symfony/mime": "<6.4", "symfony/property-access": "<5.4", "symfony/property-info": "<5.4", + "symfony/runtime": "<5.4.45|>=6.0,<6.4.13|>=7.0,<7.1.6", "symfony/scheduler": "<6.4.4|>=7.0.0,<7.0.4", "symfony/security-core": "<5.4", "symfony/security-csrf": "<5.4", @@ -9814,7 +9708,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v6.4.8" + "source": "https://github.com/symfony/framework-bundle/tree/v6.4.13" }, "funding": [ { @@ -9830,7 +9724,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-10-25T15:07:50+00:00" }, { "name": "theseer/tokenizer", @@ -9884,16 +9778,16 @@ }, { "name": "vimeo/psalm", - "version": "5.24.0", + "version": "5.26.1", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "462c80e31c34e58cc4f750c656be3927e80e550e" + "reference": "d747f6500b38ac4f7dfc5edbcae6e4b637d7add0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/462c80e31c34e58cc4f750c656be3927e80e550e", - "reference": "462c80e31c34e58cc4f750c656be3927e80e550e", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/d747f6500b38ac4f7dfc5edbcae6e4b637d7add0", + "reference": "d747f6500b38ac4f7dfc5edbcae6e4b637d7add0", "shasum": "" }, "require": { @@ -9914,7 +9808,7 @@ "felixfbecker/language-server-protocol": "^1.5.2", "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1 || ^1.0.0", "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", - "nikic/php-parser": "^4.16", + "nikic/php-parser": "^4.17", "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", "sebastian/diff": "^4.0 || ^5.0 || ^6.0", "spatie/array-to-xml": "^2.17.0 || ^3.0", @@ -9990,7 +9884,7 @@ "issues": "https://github.com/vimeo/psalm/issues", "source": "https://github.com/vimeo/psalm" }, - "time": "2024-05-01T19:32:08+00:00" + "time": "2024-09-08T18:53:08+00:00" }, { "name": "webmozart/assert", diff --git a/phpBB/config/default/container/services.yml b/phpBB/config/default/container/services.yml index 14c0d40263..253a70342a 100644 --- a/phpBB/config/default/container/services.yml +++ b/phpBB/config/default/container/services.yml @@ -157,6 +157,15 @@ services: - '%core.php_ext%' - '%tables.log%' + manifest.controller: + class: phpbb\manifest + arguments: + - '@config' + - '@language' + - '@path_helper' + - '@event_dispatcher' + - '@user' + path_helper: class: phpbb\path_helper arguments: diff --git a/phpBB/config/default/container/services_captcha.yml b/phpBB/config/default/container/services_captcha.yml index 8e9d829b47..ea41fefe80 100644 --- a/phpBB/config/default/container/services_captcha.yml +++ b/phpBB/config/default/container/services_captcha.yml @@ -19,7 +19,11 @@ services: shared: false arguments: - '@config' + - '@dbal.conn' + - '@language' + - '@request' - '@template' + - '@user' - '%core.root_path%' - '%core.php_ext%' calls: @@ -54,3 +58,19 @@ services: - ['set_name', ['core.captcha.plugins.recaptcha_v3']] tags: - { name: captcha.plugins } + + core.captcha.plugins.turnstile: + class: phpbb\captcha\plugins\turnstile + shared: false + arguments: + - '@config' + - '@dbal.conn' + - '@language' + - '@log' + - '@request' + - '@template' + - '@user' + calls: + - ['set_name', ['core.captcha.plugins.turnstile']] + tags: + - { name: captcha.plugins } diff --git a/phpBB/config/default/container/services_console.yml b/phpBB/config/default/container/services_console.yml index 038aa360e4..6c85e22f9a 100644 --- a/phpBB/config/default/container/services_console.yml +++ b/phpBB/config/default/container/services_console.yml @@ -359,6 +359,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: diff --git a/phpBB/config/default/container/services_storage.yml b/phpBB/config/default/container/services_storage.yml index 496c30de5d..4ff6f96ae3 100644 --- a/phpBB/config/default/container/services_storage.yml +++ b/phpBB/config/default/container/services_storage.yml @@ -70,8 +70,6 @@ services: shared: false arguments: - '@filesystem' - - '@upload_imagesize' - - '@mimetype.guesser' - '%core.root_path%' tags: - { name: storage.adapter } @@ -90,6 +88,7 @@ services: - '@cache' - '@config' - '@dbal.conn' + - '@mimetype.extension_guesser' - '@storage.avatar' - '@symfony_request' @@ -102,6 +101,7 @@ services: - '@content.visibility' - '@dbal.conn' - '@event_dispatcher' + - '@mimetype.extension_guesser' - '@language' - '@request' - '@storage.attachment' diff --git a/phpBB/config/default/container/services_ucp.yml b/phpBB/config/default/container/services_ucp.yml index a950ef8e35..acd78f8440 100644 --- a/phpBB/config/default/container/services_ucp.yml +++ b/phpBB/config/default/container/services_ucp.yml @@ -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: @@ -23,8 +34,11 @@ services: - '@controller.helper' - '@dbal.conn' - '@form_helper' + - '@language' + - '@notification_manager' - '@path_helper' - '@request' + - '@user_loader' - '@user' - '@template.twig.environment' - '%tables.notification_push%' diff --git a/phpBB/config/default/routing/routing.yml b/phpBB/config/default/routing/routing.yml index 7fff9204f0..46d20e4527 100644 --- a/phpBB/config/default/routing/routing.yml +++ b/phpBB/config/default/routing/routing.yml @@ -24,6 +24,10 @@ phpbb_help_routing: resource: help.yml prefix: /help +phpbb_manifest_controller: + path: /manifest + defaults: { _controller: manifest.controller:handle } + phpbb_mention_controller: path: /mention methods: [GET, POST] diff --git a/phpBB/config/default/routing/ucp.yml b/phpBB/config/default/routing/ucp.yml index 772910bfe1..0103dbd2bb 100644 --- a/phpBB/config/default/routing/ucp.yml +++ b/phpBB/config/default/routing/ucp.yml @@ -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 } diff --git a/phpBB/docs/CHANGELOG.html b/phpBB/docs/CHANGELOG.html index 8b20e374b1..4674867ecd 100644 --- a/phpBB/docs/CHANGELOG.html +++ b/phpBB/docs/CHANGELOG.html @@ -50,6 +50,10 @@
  1. Changelog
      +
    • Changes since 3.3.14-RC1
    • +
    • Changes since 3.3.13
    • +
    • Changes since 3.3.13-RC1
    • +
    • Changes since 3.3.12
    • Changes since 3.3.12-RC1
    • Changes since 3.3.11
    • Changes since 3.3.10
    • @@ -169,6 +173,97 @@
      +

      Changes since 3.3.14-RC1

      +

      Improvement

      +
        +
      • [PHPBB-17421] - Rename section for not installed extensions to not installed
      • +
      + +

      Changes since 3.3.13

      +

      Bug

      +
        +
      • [PHPBB-17181] - If statement to highlight Reported PMS on the view message page doesn't work.
      • +
      • [PHPBB-17383] - HELO/EHLO error while using gethostbyaddr()
      • +
      • [PHPBB-17384] - Passing E_USER_ERROR to trigger_error() is deprecated in PHP 8.4
      • +
      • [PHPBB-17385] - Version check without SSL flag for CDB extensions fails
      • +
      • [PHPBB-17386] - Incorrect trace result while tracing user-based permissions
      • +
      • [PHPBB-17387] - PHP warnings in search results
      • +
      • [PHPBB-17390] - Missing buttons for approval of new messages
      • +
      • [PHPBB-17391] - PHP warnings on attempt to create user group having name already in use
      • +
      • [PHPBB-17398] - Ajax error on deleting cookies
      • +
      • [PHPBB-17405] - Function phpbb_gmgetdate() returns incorrect result for edge cases
      • +
      • [PHPBB-17410] - UCP tabs do not work when testing out another user's permissions
      • +
      +

      Improvement

      +
        +
      • [PHPBB-16852] - Addition of a new PHP event concerning bump topics
      • +
      • [PHPBB-17359] - Distinct disabled and not installed extensions in the list
      • +
      • [PHPBB-17376] - Link reference to quote post is a poor accessibility experience
      • +
      • [PHPBB-17382] - Incorrect grammar on FAQ page regarding searching for members
      • +
      • [PHPBB-17388] - Add php event to bump_topic_allowed function
      • +
      • [PHPBB-17394] - Check mergeability of PR on GitHub Actions
      • +
      • [PHPBB-17396] - Automatically handle merges of 3.3.x into master
      • +
      • [PHPBB-17397] - Add event for forum_data query in viewforum
      • +
      • [PHPBB-17402] - Add possibility to force reparsing BBCode via CLI
      • +
      • [PHPBB-17407] - Limit mergeability check to single comment
      • +
      • [PHPBB-17411] - Add core event to search.php
      • +
      + +

      Changes since 3.3.13-RC1

      +

      Bug

      +
        +
      • [PHPBB-17377] - MSSQL builds on GitHub actions broken
      • +
      + +

      Changes since 3.3.12

      +

      Bug

      +
        +
      • [PHPBB-13916] - Cancelling save draft removes previous notify setting on posting page
      • +
      • [PHPBB-14454] - Accessing ACP modules while testing user permissions returns a General Error
      • +
      • [PHPBB-15043] - Searching no longer working in 3.2.0
      • +
      • [PHPBB-15576] - PM subject truncated to shorter length than maxlength
      • +
      • [PHPBB-16213] - vendor and phpbb folders should have .htaccess files
      • +
      • [PHPBB-16907] - "phpbb" value in "hiddenSegments" blocks client requests for extensions in IIS
      • +
      • [PHPBB-17109] - Users without the "Can use signature" permission should not see checkboxes for signature
      • +
      • [PHPBB-17175] - Breadcrumbs show wrong forum and topic when using 'email topic'
      • +
      • [PHPBB-17301] - Wrong length parameter for fread in phpbb/cache/driver/file.php can lead to unusable forum
      • +
      • [PHPBB-17327] - Fix linting issue in console user add command
      • +
      • [PHPBB-17332] - New permission copied from existing permission ignores permission set options
      • +
      • [PHPBB-17337] - Transaction begin is missing from mysqli driver
      • +
      • [PHPBB-17338] - Incorrect members list sorting by user_last_visit
      • +
      • [PHPBB-17351] - phpBB2 password hashes incorrectly handled during rehash cron
      • +
      • [PHPBB-17352] - Long rank titles push other profile details below
      • +
      • [PHPBB-17353] - Gravatar avatar src is not image src
      • +
      • [PHPBB-17356] - Errors hidden by at are being displayed in PHP 8 or newer
      • +
      • [PHPBB-17358] - Redis cache never expires with the TTL of 0
      • +
      • [PHPBB-17362] - Missing declaration of property in extension manager
      • +
      • [PHPBB-17365] - Enforce the search word limit on queries containing operators without white space
      • +
      • [PHPBB-17366] - Captcha disappears on error message from registration & posting
      • +
      • [PHPBB-17369] - Permanently deleting soft-deleted topics returns incorrect forum in redirect link
      • +
      • [PHPBB-17370] - Deleting Cookies on FAQ/other pages
      • +
      • [PHPBB-17374] - ACP - Maintenance - Logs: Deleting Error / Bug
      • +
      • [PHPBB-17375] - User lastvisit gets updated too often in session garbage collection
      • +
      +

      Improvement

      +
        +
      • [PHPBB-16553] - Disapproving a reported post causes a "Module not accessible" error
      • +
      • [PHPBB-17308] - Rename tracker project key to PHPBB-
      • +
      • [PHPBB-17315] - Add new template events to group
      • +
      • [PHPBB-17316] - Add template events to ucp_groups_manage
      • +
      • [PHPBB-17317] - Update button text and make it more readable
      • +
      • [PHPBB-17325] - Show explicit message for "Re-Check version" if installed version is still up to date
      • +
      • [PHPBB-17340] - Update composer to 2.7.7
      • +
      • [PHPBB-17342] - Add PHP 8.4-dev tests to GitHub Actions
      • +
      • [PHPBB-17347] - Support deleting users by ID via console
      • +
      • [PHPBB-17350] - Add user IP address to log when installing extensions on fresh installs
      • +
      • [PHPBB-17355] - Update gravatar hash to sha256
      • +
      +

      Task

      +
        +
      • [PHPBB-13933] - Update tokens' definitions in acp_bbcodes
      • +
      • [PHPBB-16890] - Edit the config sample files and web.config to deny access to the "config" directory
      • +
      +

      Changes since 3.3.12-RC1

      Bug

        diff --git a/phpBB/docs/CREDITS.txt b/phpBB/docs/CREDITS.txt index 47621b2318..9155fc9a2b 100644 --- a/phpBB/docs/CREDITS.txt +++ b/phpBB/docs/CREDITS.txt @@ -106,5 +106,4 @@ MIT licensed: Symfony2 (c) 2004-2011 Fabien Potencier, https://symfony.com/ Cookie Consent (c) 2015 Silktide Ltd, https://cookieconsent.insites.com -Emoji by: -Twemoji (c) 2018 Twitter, Inc, https://twemoji.twitter.com/ +HiDPI smilies by rednoah: https://github.com/rednoah/phpBB-smilies diff --git a/phpBB/docs/events.md b/phpBB/docs/events.md index 07e3b83beb..cc37ede34e 100644 --- a/phpBB/docs/events.md +++ b/phpBB/docs/events.md @@ -94,6 +94,20 @@ acp_ext_list_enabled_title_after * Since: 3.1.11-RC1 * Purpose: Add text after enabled extensions section title. +acp_ext_list_not_installed_name_after +=== +* Location: adm/style/acp_ext_list.html +* Since: 3.3.14-RC1 +* Changed: 3.3.14 Renamed from acp_ext_list_available_name_after +* Purpose: Add content after the name of not installed extensions in the list + +acp_ext_list_not_installed_title_after +=== +* Location: adm/style/acp_ext_list.html +* Since: 3.3.14-RC1 +* Changed: 3.3.14 Renamed from acp_ext_list_available_title_after +* Purpose: Add text after not installed extensions section title. + acp_forums_custom_settings === * Location: adm/style/acp_forums.html diff --git a/phpBB/docs/lighttpd.sample.conf b/phpBB/docs/lighttpd.sample.conf index e783c809fc..fef922c2da 100644 --- a/phpBB/docs/lighttpd.sample.conf +++ b/phpBB/docs/lighttpd.sample.conf @@ -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 # Load moules server.modules += ( @@ -28,7 +28,7 @@ $HTTP["host"] == "www.myforums.com" { 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)" { + $HTTP["url"] =~ "^/(config|common\.php|cache|files|images/avatars/upload|includes|phpbb|store|vendor|vendor-ext)" { url.access-deny = ( "" ) } @@ -47,7 +47,8 @@ $HTTP["host"] == "www.myforums.com" { # 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" => diff --git a/phpBB/docs/nginx.sample.conf b/phpBB/docs/nginx.sample.conf index 9d2623c88b..ed1f25e023 100644 --- a/phpBB/docs/nginx.sample.conf +++ b/phpBB/docs/nginx.sample.conf @@ -55,7 +55,7 @@ server { } # Deny access to internal phpbb files. - location ~ /(config\.php|common\.php|cache|files|images/avatars/upload|includes|(? + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/phpBB/images/icons/misc/heart.svg b/phpBB/images/icons/misc/heart.svg new file mode 100644 index 0000000000..f25d0a3c64 --- /dev/null +++ b/phpBB/images/icons/misc/heart.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/phpBB/images/icons/misc/radioactive.svg b/phpBB/images/icons/misc/radioactive.svg new file mode 100644 index 0000000000..372c84e423 --- /dev/null +++ b/phpBB/images/icons/misc/radioactive.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/phpBB/images/icons/misc/star.svg b/phpBB/images/icons/misc/star.svg new file mode 100644 index 0000000000..e5e88794b9 --- /dev/null +++ b/phpBB/images/icons/misc/star.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/phpBB/images/icons/misc/thinking.svg b/phpBB/images/icons/misc/thinking.svg new file mode 100644 index 0000000000..b3fdc9fca3 --- /dev/null +++ b/phpBB/images/icons/misc/thinking.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/phpBB/images/icons/smile/alert.svg b/phpBB/images/icons/smile/alert.svg new file mode 100644 index 0000000000..173ba4d780 --- /dev/null +++ b/phpBB/images/icons/smile/alert.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/phpBB/images/icons/smile/info.svg b/phpBB/images/icons/smile/info.svg new file mode 100644 index 0000000000..f6e9ef7512 --- /dev/null +++ b/phpBB/images/icons/smile/info.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/phpBB/images/icons/smile/mrgreen.svg b/phpBB/images/icons/smile/mrgreen.svg new file mode 100644 index 0000000000..ef639a5ccd --- /dev/null +++ b/phpBB/images/icons/smile/mrgreen.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/phpBB/images/icons/smile/question.svg b/phpBB/images/icons/smile/question.svg new file mode 100644 index 0000000000..7a7bf1602a --- /dev/null +++ b/phpBB/images/icons/smile/question.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/phpBB/images/icons/smile/redface.svg b/phpBB/images/icons/smile/redface.svg new file mode 100644 index 0000000000..84fe0db5ef --- /dev/null +++ b/phpBB/images/icons/smile/redface.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_arrow.svg b/phpBB/images/smilies/icon_arrow.svg new file mode 100644 index 0000000000..4d190756ce --- /dev/null +++ b/phpBB/images/smilies/icon_arrow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_cool.svg b/phpBB/images/smilies/icon_cool.svg new file mode 100644 index 0000000000..500729316d --- /dev/null +++ b/phpBB/images/smilies/icon_cool.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_cry.svg b/phpBB/images/smilies/icon_cry.svg new file mode 100644 index 0000000000..e9312f9d7a --- /dev/null +++ b/phpBB/images/smilies/icon_cry.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_e_biggrin.svg b/phpBB/images/smilies/icon_e_biggrin.svg new file mode 100644 index 0000000000..6e3803be04 --- /dev/null +++ b/phpBB/images/smilies/icon_e_biggrin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_e_confused.svg b/phpBB/images/smilies/icon_e_confused.svg new file mode 100644 index 0000000000..b9561e3204 --- /dev/null +++ b/phpBB/images/smilies/icon_e_confused.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_e_geek.svg b/phpBB/images/smilies/icon_e_geek.svg new file mode 100644 index 0000000000..77af7d61f9 --- /dev/null +++ b/phpBB/images/smilies/icon_e_geek.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_e_sad.svg b/phpBB/images/smilies/icon_e_sad.svg new file mode 100644 index 0000000000..69a323f155 --- /dev/null +++ b/phpBB/images/smilies/icon_e_sad.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_e_smile.svg b/phpBB/images/smilies/icon_e_smile.svg new file mode 100644 index 0000000000..c273c77f1f --- /dev/null +++ b/phpBB/images/smilies/icon_e_smile.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_e_surprised.svg b/phpBB/images/smilies/icon_e_surprised.svg new file mode 100644 index 0000000000..ad5ce8bdc5 --- /dev/null +++ b/phpBB/images/smilies/icon_e_surprised.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_e_ugeek.svg b/phpBB/images/smilies/icon_e_ugeek.svg new file mode 100644 index 0000000000..0ae02fcc76 --- /dev/null +++ b/phpBB/images/smilies/icon_e_ugeek.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_e_wink.svg b/phpBB/images/smilies/icon_e_wink.svg new file mode 100644 index 0000000000..f07eaf36ac --- /dev/null +++ b/phpBB/images/smilies/icon_e_wink.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_eek.svg b/phpBB/images/smilies/icon_eek.svg new file mode 100644 index 0000000000..d3bbc31ae9 --- /dev/null +++ b/phpBB/images/smilies/icon_eek.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_evil.svg b/phpBB/images/smilies/icon_evil.svg new file mode 100644 index 0000000000..2636a078ec --- /dev/null +++ b/phpBB/images/smilies/icon_evil.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_exclaim.svg b/phpBB/images/smilies/icon_exclaim.svg new file mode 100644 index 0000000000..6d14ccd2e0 --- /dev/null +++ b/phpBB/images/smilies/icon_exclaim.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_idea.svg b/phpBB/images/smilies/icon_idea.svg new file mode 100644 index 0000000000..0f5ff849bb --- /dev/null +++ b/phpBB/images/smilies/icon_idea.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_lol.svg b/phpBB/images/smilies/icon_lol.svg new file mode 100644 index 0000000000..93d0fe7643 --- /dev/null +++ b/phpBB/images/smilies/icon_lol.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_mad.svg b/phpBB/images/smilies/icon_mad.svg new file mode 100644 index 0000000000..1575f95c14 --- /dev/null +++ b/phpBB/images/smilies/icon_mad.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_mrgreen.svg b/phpBB/images/smilies/icon_mrgreen.svg new file mode 100644 index 0000000000..a8157d4041 --- /dev/null +++ b/phpBB/images/smilies/icon_mrgreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_neutral.svg b/phpBB/images/smilies/icon_neutral.svg new file mode 100644 index 0000000000..2363cce865 --- /dev/null +++ b/phpBB/images/smilies/icon_neutral.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_question.svg b/phpBB/images/smilies/icon_question.svg new file mode 100644 index 0000000000..caa067b21c --- /dev/null +++ b/phpBB/images/smilies/icon_question.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_razz.svg b/phpBB/images/smilies/icon_razz.svg new file mode 100644 index 0000000000..a959ffc79d --- /dev/null +++ b/phpBB/images/smilies/icon_razz.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_redface.svg b/phpBB/images/smilies/icon_redface.svg new file mode 100644 index 0000000000..0b333e519a --- /dev/null +++ b/phpBB/images/smilies/icon_redface.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_rolleyes.svg b/phpBB/images/smilies/icon_rolleyes.svg new file mode 100644 index 0000000000..4d737dd4bc --- /dev/null +++ b/phpBB/images/smilies/icon_rolleyes.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/images/smilies/icon_twisted.svg b/phpBB/images/smilies/icon_twisted.svg new file mode 100644 index 0000000000..264129041a --- /dev/null +++ b/phpBB/images/smilies/icon_twisted.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/includes/acp/acp_attachments.php b/phpBB/includes/acp/acp_attachments.php index 0d66dfde4f..b0e086e65c 100644 --- a/phpBB/includes/acp/acp_attachments.php +++ b/phpBB/includes/acp/acp_attachments.php @@ -173,8 +173,6 @@ class acp_attachments 'img_max_width' => array('lang' => 'MAX_IMAGE_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false,), 'img_max_height' => array('lang' => 'MAX_IMAGE_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false,), - 'img_link_width' => array('lang' => 'IMAGE_LINK_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false,), - 'img_link_height' => array('lang' => 'IMAGE_LINK_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false,), 'allow_attachments' => array('lang' => 'ALLOW_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'allow_pm_attach' => array('lang' => 'ALLOW_PM_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), @@ -197,7 +195,6 @@ class acp_attachments 'img_max' => array('lang' => 'MAX_IMAGE_SIZE', 'validate' => 'int:0:9999', 'type' => 'dimension:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), 'img_strip_metadata' => array('lang' => 'IMAGE_STRIP_METADATA', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'img_quality' => array('lang' => 'IMAGE_QUALITY', 'validate' => 'int:50:90', 'type' => 'number:50:90', 'explain' => true, 'append' => ' %'), - 'img_link' => array('lang' => 'IMAGE_LINK_SIZE', 'validate' => 'int:0:9999', 'type' => 'dimension:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), ) ); diff --git a/phpBB/includes/acp/acp_bbcodes.php b/phpBB/includes/acp/acp_bbcodes.php index d6acf93cce..a905354040 100644 --- a/phpBB/includes/acp/acp_bbcodes.php +++ b/phpBB/includes/acp/acp_bbcodes.php @@ -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 diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index d2076ce086..6f98edeafd 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -78,6 +78,7 @@ class acp_board 'site_home_url' => array('lang' => 'SITE_HOME_URL', 'validate' => 'url', 'type' => 'url:40:255', 'explain' => true), 'site_home_text' => array('lang' => 'SITE_HOME_TEXT', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => true), 'board_index_text' => array('lang' => 'BOARD_INDEX_TEXT', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => true), + 'sitename_short' => array('lang' => 'SITE_NAME_SHORT', 'validate' => 'string', 'type' => 'text:40:12', 'explain' => true), 'board_disable' => array('lang' => 'DISABLE_BOARD', 'validate' => 'bool', 'type' => 'custom', 'method' => 'board_disable', 'explain' => true), 'board_disable_msg' => false, 'board_disable_access' => array('lang' => 'DISABLE_BOARD_ACCESS', 'validate' => 'int', 'type' => 'select', 'method' => 'board_disable_access', 'explain' => true), @@ -259,8 +260,6 @@ class acp_board 'max_sig_urls' => array('lang' => 'MAX_SIG_URLS', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), 'max_sig_font_size' => array('lang' => 'MAX_SIG_FONT_SIZE', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' %'), 'max_sig_smilies' => array('lang' => 'MAX_SIG_SMILIES', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'max_sig_img_width' => array('lang' => 'MAX_SIG_IMG_WIDTH', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - 'max_sig_img_height' => array('lang' => 'MAX_SIG_IMG_HEIGHT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), 'legend3' => 'ACP_SUBMIT_CHANGES', ) @@ -392,7 +391,7 @@ class acp_board 'title' => 'ACP_AUTH_SETTINGS', 'vars' => array( 'legend1' => 'ACP_AUTH_SETTINGS', - 'auth_method' => array('lang' => 'AUTH_METHOD', 'validate' => 'string', 'type' => 'select:1:toggable', 'method' => 'select_auth_method', 'explain' => false), + 'auth_method' => array('lang' => 'AUTH_METHOD', 'validate' => 'string', 'type' => 'select:1:toggleable', 'method' => 'select_auth_method', 'explain' => false), ) ); break; @@ -403,7 +402,7 @@ class acp_board 'vars' => array( 'legend1' => 'ACP_SERVER_SETTINGS', 'gzip_compress' => array('lang' => 'ENABLE_GZIP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'use_system_cron' => array('lang' => 'USE_SYSTEM_CRON', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'use_system_cron' => array('lang' => 'USE_SYSTEM_CRON', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true), 'legend2' => 'PATH_SETTINGS', 'enable_mod_rewrite' => array('lang' => 'MOD_REWRITE_ENABLE', 'validate' => 'bool', 'type' => 'custom', 'method' => 'enable_mod_rewrite', 'explain' => true), @@ -593,6 +592,7 @@ class acp_board // Array of emoji-enabled configurations $config_name_ary = [ 'sitename', + 'sitename_short', 'site_desc', 'site_home_text', 'board_index_text', diff --git a/phpBB/includes/acp/acp_captcha.php b/phpBB/includes/acp/acp_captcha.php index ff9f515d32..e03d2a3901 100644 --- a/phpBB/includes/acp/acp_captcha.php +++ b/phpBB/includes/acp/acp_captcha.php @@ -95,7 +95,7 @@ class acp_captcha add_form_key($form_key); $submit = $request->variable('main_submit', false); - $error = $cfg_array = array(); + $errors = $cfg_array = array(); if ($submit) { @@ -103,13 +103,13 @@ class acp_captcha { $cfg_array[$config_var] = $request->variable($config_var, $options['default']); } - validate_config_vars($config_vars, $cfg_array, $error); + validate_config_vars($config_vars, $cfg_array, $errors); if (!check_form_key($form_key)) { - $error[] = $user->lang['FORM_INVALID']; + $errors[] = $user->lang['FORM_INVALID']; } - if ($error) + if ($errors) { $submit = false; } @@ -128,11 +128,9 @@ class acp_captcha if (isset($captchas['available'][$selected])) { $old_captcha = $factory->get_instance($config['captcha_plugin']); - $old_captcha->uninstall(); + $old_captcha->garbage_collect(); $config->set('captcha_plugin', $selected); - $new_captcha = $factory->get_instance($config['captcha_plugin']); - $new_captcha->install(); $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_VISUAL'); } @@ -145,17 +143,24 @@ class acp_captcha } else { - $captcha_select = ''; + $captcha_options = []; foreach ($captchas['available'] as $value => $title) { - $current = ($selected !== false && $value == $selected) ? ' selected="selected"' : ''; - $captcha_select .= ''; + $captcha_options[] = [ + 'value' => $value, + 'label' => $user->lang($title), + 'selected' => $selected !== false && $value == $selected, + ]; } foreach ($captchas['unavailable'] as $value => $title) { - $current = ($selected !== false && $value == $selected) ? ' selected="selected"' : ''; - $captcha_select .= ''; + $captcha_options[] = [ + 'value' => $value, + 'label' => $user->lang($title), + 'selected' => $selected !== false && $value == $selected, + 'class' => 'disabled-option', + ]; } $demo_captcha = $factory->get_instance($selected); @@ -168,8 +173,12 @@ class acp_captcha $template->assign_vars(array( 'CAPTCHA_PREVIEW_TPL' => $demo_captcha->get_demo_template($id), 'S_CAPTCHA_HAS_CONFIG' => $demo_captcha->has_config(), - 'CAPTCHA_SELECT' => $captcha_select, - 'ERROR_MSG' => implode('
        ', $error), + 'CAPTCHA_SELECT' => [ + 'tag' => 'select', + 'name' => 'select_captcha', + 'options' => $captcha_options, + ], + 'ERRORS' => $errors, 'U_ACTION' => $this->u_action, )); diff --git a/phpBB/includes/acp/acp_extensions.php b/phpBB/includes/acp/acp_extensions.php index 1a30d38d61..6faeee61fd 100644 --- a/phpBB/includes/acp/acp_extensions.php +++ b/phpBB/includes/acp/acp_extensions.php @@ -972,7 +972,7 @@ class acp_extensions catch (exception_interface $e) { $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters())); - $this->template->assign_block_vars('disabled', array( + $this->template->assign_block_vars('not_installed', array( 'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $message), 'S_VERSIONCHECK' => false, )); @@ -986,9 +986,9 @@ class acp_extensions $block_vars['NAME'] = $name; $block_vars['U_DETAILS'] = $this->u_action . '&action=details&ext_name=' . urlencode($name); - $this->template->assign_block_vars('disabled', $block_vars); + $this->template->assign_block_vars('not_installed', $block_vars); - $this->output_actions('disabled', array( + $this->output_actions('not_installed', array( 'ENABLE' => $this->u_action . '&action=enable_pre&ext_name=' . urlencode($name), 'REMOVE' => $this->u_catalog_action . '&action=remove&extension=' . urlencode($block_vars['META_NAME']), )); diff --git a/phpBB/includes/acp/acp_forums.php b/phpBB/includes/acp/acp_forums.php index 6aafce12bc..920214448d 100644 --- a/phpBB/includes/acp/acp_forums.php +++ b/phpBB/includes/acp/acp_forums.php @@ -213,13 +213,7 @@ class acp_forums phpbb_cache_moderators($db, $phpbb_container->get('dbal.tools'), $cache, $auth); $copied_permissions = true; } -/* Commented out because of questionable UI workflow - re-visit for 3.0.7 - else if (!$this->parent_id && $action != 'edit' && $auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth')) - { - $this->copy_permission_page($forum_data); - return; - } -*/ + $auth->acl_clear_prefetch(); $acl_url = '&mode=setting_forum_local&forum_id[]=' . $forum_data['forum_id']; diff --git a/phpBB/includes/acp/acp_groups.php b/phpBB/includes/acp/acp_groups.php index b24014cb39..bafeafbc06 100644 --- a/phpBB/includes/acp/acp_groups.php +++ b/phpBB/includes/acp/acp_groups.php @@ -396,7 +396,7 @@ class acp_groups $allow_desc_urls = $request->variable('desc_parse_urls', false); $allow_desc_smilies = $request->variable('desc_parse_smilies', false); - $submit_ary = array( + $submit_ary = [ 'colour' => $request->variable('group_colour', ''), 'rank' => $request->variable('group_rank', 0), 'receive_pm' => isset($_REQUEST['group_receive_pm']) ? 1 : 0, @@ -406,7 +406,13 @@ class acp_groups 'max_recipients' => $request->variable('group_max_recipients', 0), 'founder_manage' => 0, 'skip_auth' => $request->variable('group_skip_auth', 0), - ); + + // Initialize avatar data + 'avatar' => $avatar_data['avatar'] ?? '', + 'avatar_type' => $avatar_data['avatar_type'] ?? '', + 'avatar_height' => $avatar_data['avatar_height'] ?? 0, + 'avatar_width' => $avatar_data['avatar_width'] ?? 0, + ]; if ($user->data['user_type'] == USER_FOUNDER) { diff --git a/phpBB/includes/acp/acp_logs.php b/phpBB/includes/acp/acp_logs.php index 1cf1246231..9913264593 100644 --- a/phpBB/includes/acp/acp_logs.php +++ b/phpBB/includes/acp/acp_logs.php @@ -50,7 +50,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)) { diff --git a/phpBB/includes/acp/acp_users.php b/phpBB/includes/acp/acp_users.php index db429e4f36..75b1cde0d8 100644 --- a/phpBB/includes/acp/acp_users.php +++ b/phpBB/includes/acp/acp_users.php @@ -1094,7 +1094,7 @@ class acp_users $s_action_options .= ''; } - $last_active = (!empty($user_row['session_time'])) ? $user_row['session_time'] : $user_row['user_last_active']; + $last_active = $user_row['user_last_active'] ?: ($user_row['session_time'] ?? 0); $inactive_reason = ''; if ($user_row['user_type'] == USER_INACTIVE) diff --git a/phpBB/includes/bbcode.php b/phpBB/includes/bbcode.php index d0ced55823..b98fe1e6b3 100644 --- a/phpBB/includes/bbcode.php +++ b/phpBB/includes/bbcode.php @@ -651,38 +651,4 @@ class bbcode return $code; } - - /** - * Function to perform custom bbcode second pass by extensions - * can be used to assign bbcode pattern replacement - * Example: '#\[list=([^\[]+):$uid\]#e' => "\$this->bbcode_second_pass_by_extension('\$1')" - * - * Accepts variable number of parameters - * - * @return bool Second pass result - * - * @deprecated 3.2.10 (To be removed 4.0.0) - */ - function bbcode_second_pass_by_extension() - { - global $phpbb_dispatcher; - - $return = false; - $params_array = func_get_args(); - - /** - * Event to perform bbcode second pass with - * the custom validating methods provided by extensions - * - * @event core.bbcode_second_pass_by_extension - * @var array params_array Array with the function parameters - * @var mixed return Second pass result to return - * - * @since 3.1.5-RC1 - */ - $vars = array('params_array', 'return'); - extract($phpbb_dispatcher->trigger_event('core.bbcode_second_pass_by_extension', compact($vars))); - - return $return; - } } diff --git a/phpBB/includes/compatibility_globals.php b/phpBB/includes/compatibility_globals.php index df152c81ab..ca0394e88f 100644 --- a/phpBB/includes/compatibility_globals.php +++ b/phpBB/includes/compatibility_globals.php @@ -49,8 +49,6 @@ function register_compatibility_globals() /* @var $request \phpbb\request\request_interface */ $request = $phpbb_container->get('request'); - // Inject request instance, so only this instance is used with request_var - request_var('', 0, false, false, $request); /* @var $user \phpbb\user */ $user = $phpbb_container->get('user'); @@ -67,8 +65,6 @@ function register_compatibility_globals() // Grab global variables, re-cache if necessary /* @var $config phpbb\config\db */ $config = $phpbb_container->get('config'); - set_config('', '', false, $config); - set_config_count('', 0, false, $config); /* @var $phpbb_log \phpbb\log\log_interface */ $phpbb_log = $phpbb_container->get('log'); diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index f560dbfbcb..825a328d39 100644 --- a/phpBB/includes/constants.php +++ b/phpBB/includes/constants.php @@ -152,9 +152,13 @@ define('FULL_FOLDER_DELETE', -2); define('FULL_FOLDER_HOLD', -1); // Confirm types +/** @deprecated 4.0.0-a1 Replaced by \phpbb\captcha\plugins\confirm_type::REGISTRATION, to be removed in 5.0.0-a1 */ define('CONFIRM_REG', 1); +/** @deprecated 4.0.0-a1 Replaced by \phpbb\captcha\plugins\confirm_type::LOGIN, to be removed in 5.0.0-a1 */ define('CONFIRM_LOGIN', 2); +/** @deprecated 4.0.0-a1 Replaced by \phpbb\captcha\plugins\confirm_type::POST, to be removed in 5.0.0-a1 */ define('CONFIRM_POST', 3); +/** @deprecated 4.0.0-a1 Replaced by \phpbb\captcha\plugins\confirm_type::REPORT, to be removed in 5.0.0-a1 */ define('CONFIRM_REPORT', 4); // Categories - Attachments @@ -174,7 +178,7 @@ define('BBCODE_UID_LEN', 8); // Number of core BBCodes define('NUM_CORE_BBCODES', 12); -define('NUM_PREDEFINED_BBCODES', 22); +define('NUM_PREDEFINED_BBCODES', 20); // BBCode IDs define('BBCODE_ID_QUOTE', 0); diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 0e52fb37d6..8741047049 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -107,9 +107,17 @@ function phpbb_gmgetdate($time = false) } // getdate() interprets timestamps in local time. - // What follows uses the fact that getdate() and - // date('Z') balance each other out. - return getdate($time - date('Z')); + // So use UTC timezone temporarily to get UTC date info array. + $current_timezone = date_default_timezone_get(); + + // Set UTC timezone and get respective date info + date_default_timezone_set('UTC'); + $date_info = getdate($time); + + // Restore timezone back + date_default_timezone_set($current_timezone); + + return $date_info; } /** @@ -2931,8 +2939,16 @@ function msg_handler($errno, $msg_text, $errfile, $errline): bool 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 true; } @@ -3847,7 +3863,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'), @@ -3855,6 +3871,7 @@ function page_header($page_title = '', $display_online_list = false, $item_id = 'UA_PRIVACY' => addslashes(append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=privacy')), 'U_RESTORE_PERMISSIONS' => ($user->data['user_perm_from'] && $auth->acl_get('a_switchperm')) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=restore_perm') : '', 'U_FEED' => $controller_helper->route('phpbb_feed_index'), + 'U_MANIFEST' => $controller_helper->route('phpbb_manifest_controller'), 'S_ALLOW_MENTIONS' => ($config['allow_mentions'] && $auth->acl_get('u_mention') && (empty($forum_id) || $auth->acl_get('f_mention', $forum_id))) ? true : false, 'S_MENTION_NAMES_LIMIT' => $config['mention_names_limit'], @@ -4023,7 +4040,9 @@ function phpbb_generate_debug_output(\phpbb\db\driver\driver_interface $db, \php if ($auth->acl_get('a_')) { - $debug_info[] = 'SQL Explain'; + $page_url = build_url(); + $page_url .= ((!str_contains($page_url, '?')) ? '?' : '&') . 'explain=1'; + $debug_info[] = 'SQL Explain'; } } diff --git a/phpBB/includes/functions_acp.php b/phpBB/includes/functions_acp.php index 646d2f34d5..a3bae23ab5 100644 --- a/phpBB/includes/functions_acp.php +++ b/phpBB/includes/functions_acp.php @@ -203,8 +203,8 @@ function adm_page_footer($copyright_html = true) */ function adm_back_link($u_action) { - global $user; - return '

        « ' . $user->lang['BACK_TO_PREV'] . ''; + global $language; + return '

        « ' . $language->lang('BACK_TO_PREV') . ''; } /** diff --git a/phpBB/includes/functions_compatibility.php b/phpBB/includes/functions_compatibility.php index 85ec1bd449..1efc8c9c2e 100644 --- a/phpBB/includes/functions_compatibility.php +++ b/phpBB/includes/functions_compatibility.php @@ -19,835 +19,6 @@ if (!defined('IN_PHPBB')) exit; } -/** -* Hash the password -* -* @deprecated 3.1.0-a2 (To be removed: 4.0.0) -* -* @param string $password Password to be hashed -* -* @return string|bool Password hash or false if something went wrong during hashing -*/ -function phpbb_hash($password) -{ - global $phpbb_container; - - /* @var $passwords_manager \phpbb\passwords\manager */ - $passwords_manager = $phpbb_container->get('passwords.manager'); - return $passwords_manager->hash($password); -} - -/** -* Check for correct password -* -* @deprecated 3.1.0-a2 (To be removed: 4.0.0) -* -* @param string $password The password in plain text -* @param string $hash The stored password hash -* -* @return bool Returns true if the password is correct, false if not. -*/ -function phpbb_check_hash($password, $hash) -{ - global $phpbb_container; - - /* @var $passwords_manager \phpbb\passwords\manager */ - $passwords_manager = $phpbb_container->get('passwords.manager'); - return $passwords_manager->check($password, $hash); -} - -/** -* Eliminates useless . and .. components from specified path. -* -* Deprecated, use storage helper class instead -* -* @param string $path Path to clean -* @return string Cleaned path -* -* @deprecated 3.1.0 (To be removed: 4.0.0) -*/ -function phpbb_clean_path($path) -{ - return \phpbb\filesystem\helper::clean_path($path); -} - -/** -* Pick a timezone -* -* @param string $default A timezone to select -* @param boolean $truncate Shall we truncate the options text -* -* @return string Returns the options for timezone selector only -* -* @deprecated 3.1.0 (To be removed: 4.0.0) -*/ -function tz_select($default = '', $truncate = false) -{ - global $user; - - return phpbb_timezone_select($user, $default, $truncate); -} - -/** -* Cache moderators. Called whenever permissions are changed -* via admin_permissions. Changes of usernames and group names -* must be carried through for the moderators table. -* -* @deprecated 3.1.0 (To be removed: 4.0.0) -* @return void -*/ -function cache_moderators() -{ - global $db, $cache, $auth, $phpbb_container; - phpbb_cache_moderators($db, $phpbb_container->get('dbal.tools'), $cache, $auth); -} - -/** -* Removes moderators and administrators from foe lists. -* -* @deprecated 3.1.0 (To be removed: 4.0.0) -* @param array|bool $group_id If an array, remove all members of this group from foe lists, or false to ignore -* @param array|bool $user_id If an array, remove this user from foe lists, or false to ignore -* @return void -*/ -function update_foes($group_id = false, $user_id = false) -{ - global $db, $auth; - return phpbb_update_foes($db, $auth, $group_id, $user_id); -} - -/** -* Get user rank title and image -* -* @param int $user_rank the current stored users rank id -* @param int $user_posts the users number of posts -* @param string &$rank_title the rank title will be stored here after execution -* @param string &$rank_img the rank image as full img tag is stored here after execution -* @param string &$rank_img_src the rank image source is stored here after execution -* -* @deprecated 3.1.0-RC5 (To be removed: 4.0.0) -* -* Note: since we do not want to break backwards-compatibility, this function will only properly assign ranks to guests if you call it for them with user_posts == false -*/ -function get_user_rank($user_rank, $user_posts, &$rank_title, &$rank_img, &$rank_img_src) -{ - global $phpbb_root_path, $phpEx; - if (!function_exists('phpbb_get_user_rank')) - { - include($phpbb_root_path . 'includes/functions_display.' . $phpEx); - } - - $rank_data = phpbb_get_user_rank(array('user_rank' => $user_rank), $user_posts); - $rank_title = $rank_data['title']; - $rank_img = $rank_data['img']; - $rank_img_src = $rank_data['img_src']; -} - -/** - * Retrieve contents from remotely stored file - * - * @deprecated 3.1.2 Use file_downloader instead - */ -function get_remote_file($host, $directory, $filename, &$errstr, &$errno, $port = 80, $timeout = 6) -{ - global $phpbb_container; - - // Get file downloader and assign $errstr and $errno - /* @var $file_downloader \phpbb\file_downloader */ - $file_downloader = $phpbb_container->get('file_downloader'); - - $file_data = $file_downloader->get($host, $directory, $filename, $port, $timeout); - $errstr = $file_downloader->get_error_string(); - $errno = $file_downloader->get_error_number(); - - return $file_data; -} - -/** - * Add log entry - * - * string $mode The mode defines which log_type is used and from which log the entry is retrieved - * int $forum_id Mode 'mod' ONLY: forum id of the related item, NOT INCLUDED otherwise - * int $topic_id Mode 'mod' ONLY: topic id of the related item, NOT INCLUDED otherwise - * int $reportee_id Mode 'user' ONLY: user id of the reportee, NOT INCLUDED otherwise - * string $log_operation Name of the operation - * array $additional_data More arguments can be added, depending on the log_type - * - * @return int|bool Returns the log_id, if the entry was added to the database, false otherwise. - * - * @deprecated 3.1.0 (To be removed: 4.0.0) - */ -function add_log() -{ - global $phpbb_log, $user; - - $args = func_get_args(); - $mode = array_shift($args); - - // This looks kind of dirty, but add_log has some additional data before the log_operation - $additional_data = array(); - switch ($mode) - { - case 'admin': - case 'critical': - break; - case 'mod': - $additional_data['forum_id'] = array_shift($args); - $additional_data['topic_id'] = array_shift($args); - break; - case 'user': - $additional_data['reportee_id'] = array_shift($args); - break; - } - - $log_operation = array_shift($args); - $additional_data = array_merge($additional_data, $args); - - $user_id = (empty($user->data)) ? ANONYMOUS : $user->data['user_id']; - $user_ip = (empty($user->ip)) ? '' : $user->ip; - - return $phpbb_log->add($mode, $user_id, $user_ip, $log_operation, time(), $additional_data); -} - -/** - * Sets a configuration option's value. - * - * Please note that this function does not update the is_dynamic value for - * an already existing config option. - * - * @param string $config_name The configuration option's name - * @param string $config_value New configuration value - * @param bool $is_dynamic Whether this variable should be cached (false) or - * if it changes too frequently (true) to be - * efficiently cached. - * - * @return void - * - * @deprecated 3.1.0 (To be removed: 4.0.0) - */ -function set_config($config_name, $config_value, $is_dynamic = false, \phpbb\config\config $set_config = null) -{ - static $config = null; - - if ($set_config !== null) - { - $config = $set_config; - - if (empty($config_name)) - { - return; - } - } - - $config->set($config_name, $config_value, !$is_dynamic); -} - -/** - * Increments an integer config value directly in the database. - * - * @param string $config_name The configuration option's name - * @param int $increment Amount to increment by - * @param bool $is_dynamic Whether this variable should be cached (false) or - * if it changes too frequently (true) to be - * efficiently cached. - * - * @return void - * - * @deprecated 3.1.0 (To be removed: 4.0.0) - */ -function set_config_count($config_name, $increment, $is_dynamic = false, \phpbb\config\config $set_config = null) -{ - static $config = null; - if ($set_config !== null) - { - $config = $set_config; - if (empty($config_name)) - { - return; - } - } - $config->increment($config_name, $increment, !$is_dynamic); -} - -/** - * Wrapper function of \phpbb\request\request::variable which exists for backwards compatability. - * See {@link \phpbb\request\request_interface::variable \phpbb\request\request_interface::variable} for - * documentation of this function's use. - * - * @deprecated 3.1.0 (To be removed: 4.0.0) - * @param mixed $var_name The form variable's name from which data shall be retrieved. - * If the value is an array this may be an array of indizes which will give - * direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a") - * then specifying array("var", 1) as the name will return "a". - * If you pass an instance of {@link \phpbb\request\request_interface phpbb_request_interface} - * as this parameter it will overwrite the current request class instance. If you do - * not do so, it will create its own instance (but leave superglobals enabled). - * @param mixed $default A default value that is returned if the variable was not set. - * This function will always return a value of the same type as the default. - * @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters - * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks - * @param bool $cookie This param is mapped to \phpbb\request\request_interface::COOKIE as the last param for - * \phpbb\request\request_interface::variable for backwards compatability reasons. - * @param \phpbb\request\request_interface|null|false $request - * If an instance of \phpbb\request\request_interface is given the instance is stored in - * a static variable and used for all further calls where this parameters is null. Until - * the function is called with an instance it automatically creates a new \phpbb\request\request - * instance on every call. By passing false this per-call instantiation can be restored - * after having passed in a \phpbb\request\request_interface instance. - * - * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the - * the same as that of $default. If the variable is not set $default is returned. - */ -function request_var($var_name, $default, $multibyte = false, $cookie = false, $request = null) -{ - // This is all just an ugly hack to add "Dependency Injection" to a function - // the only real code is the function call which maps this function to a method. - static $static_request = null; - if ($request instanceof \phpbb\request\request_interface) - { - $static_request = $request; - if (empty($var_name)) - { - return null; - } - } - else if ($request === false) - { - $static_request = null; - if (empty($var_name)) - { - return null; - } - } - $tmp_request = $static_request; - // no request class set, create a temporary one ourselves to keep backwards compatibility - if ($tmp_request === null) - { - // false param: enable super globals, so the created request class does not - // make super globals inaccessible everywhere outside this function. - $tmp_request = new \phpbb\request\request(new \phpbb\request\type_cast_helper(), false); - } - return $tmp_request->variable($var_name, $default, $multibyte, ($cookie) ? \phpbb\request\request_interface::COOKIE : \phpbb\request\request_interface::REQUEST); -} - -/** - * Get tables of a database - * - * @deprecated 3.1.0 (To be removed: 4.0.0) - */ -function get_tables($db) -{ - throw new BadFunctionCallException('function removed from phpBB core, use db_tools service instead.'); -} - -/** - * Global function for chmodding directories and files for internal use - * - * This function determines owner and group whom the file belongs to and user and group of PHP and then set safest possible file permissions. - * The function determines owner and group from common.php file and sets the same to the provided file. - * The function uses bit fields to build the permissions. - * The function sets the appropiate execute bit on directories. - * - * Supported constants representing bit fields are: - * - * CHMOD_ALL - all permissions (7) - * CHMOD_READ - read permission (4) - * CHMOD_WRITE - write permission (2) - * CHMOD_EXECUTE - execute permission (1) - * - * NOTE: The function uses POSIX extension and fileowner()/filegroup() functions. If any of them is disabled, this function tries to build proper permissions, by calling is_readable() and is_writable() functions. - * - * @param string $filename The file/directory to be chmodded - * @param int $perms Permissions to set - * - * @return bool true on success, otherwise false - * - * @deprecated 3.2.0-dev use \phpbb\filesystem\filesystem::phpbb_chmod() instead - */ -function phpbb_chmod($filename, $perms = CHMOD_READ) -{ - global $phpbb_filesystem; - - try - { - $phpbb_filesystem->phpbb_chmod($filename, $perms); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - return false; - } - - return true; -} - -/** - * Test if a file/directory is writable - * - * This function calls the native is_writable() when not running under - * Windows and it is not disabled. - * - * @param string $file Path to perform write test on - * @return bool True when the path is writable, otherwise false. - * - * @deprecated 3.2.0-dev use \phpbb\filesystem\filesystem::is_writable() instead - */ -function phpbb_is_writable($file) -{ - global $phpbb_filesystem; - - return $phpbb_filesystem->is_writable($file); -} - -/** - * Checks if a path ($path) is absolute or relative - * - * @param string $path Path to check absoluteness of - * @return boolean - * - * @deprecated 3.2.0-dev use \phpbb\filesystem\helper::is_absolute_path() instead - */ -function phpbb_is_absolute($path) -{ - return \phpbb\filesystem\helper::is_absolute_path($path); -} - -/** - * A wrapper for realpath - * - * @deprecated 3.2.0-dev use \phpbb\filesystem\helper::realpath() instead - */ -function phpbb_realpath($path) -{ - return \phpbb\filesystem\helper::realpath($path); -} - -/** - * Determine which plural form we should use. - * For some languages this is not as simple as for English. - * - * @param int $rule ID of the plural rule we want to use, see https://area51.phpbb.com/docs/dev/3.3.x/language/plurals.html - * @param int|float $number The number we want to get the plural case for. Float numbers are floored. - * @return int The plural-case we need to use for the number plural-rule combination - * - * @deprecated 3.2.0-dev (To be removed: 4.0.0) - */ -function phpbb_get_plural_form($rule, $number) -{ - global $phpbb_container; - - /** @var \phpbb\language\language $language */ - $language = $phpbb_container->get('language'); - return $language->get_plural_form($number, $rule); -} - -/** -* @return bool Always true -* @deprecated 3.2.0-dev -*/ -function phpbb_pcre_utf8_support() -{ - return true; -} - -/** - * Casts a variable to the given type. - * - * @deprecated 3.1 (To be removed 4.0.0) - */ -function set_var(&$result, $var, $type, $multibyte = false) -{ - // no need for dependency injection here, if you have the object, call the method yourself! - $type_cast_helper = new \phpbb\request\type_cast_helper(); - $type_cast_helper->set_var($result, $var, $type, $multibyte); -} - -/** - * Delete Attachments - * - * @deprecated 3.2.0-a1 (To be removed: 4.0.0) - * - * @param string $mode can be: post|message|topic|attach|user - * @param mixed $ids can be: post_ids, message_ids, topic_ids, attach_ids, user_ids - * @param bool $resync set this to false if you are deleting posts or topics - */ -function delete_attachments($mode, $ids, $resync = true) -{ - global $phpbb_container; - - /** @var \phpbb\attachment\manager $attachment_manager */ - $attachment_manager = $phpbb_container->get('attachment.manager'); - $num_deleted = $attachment_manager->delete($mode, $ids, $resync); - - unset($attachment_manager); - - return $num_deleted; -} - -/** - * Delete attached file - * - * @deprecated 3.2.0-a1 (To be removed: 4.0.0) - */ -function phpbb_unlink($filename, $mode = 'file', $entry_removed = false) -{ - global $phpbb_container; - - /** @var \phpbb\attachment\manager $attachment_manager */ - $attachment_manager = $phpbb_container->get('attachment.manager'); - $unlink = $attachment_manager->unlink($filename, $mode, $entry_removed); - unset($attachment_manager); - - return $unlink; -} - -/** - * Display reasons - * - * @deprecated 3.2.0-dev (To be removed: 4.0.0) - */ -function display_reasons($reason_id = 0) -{ - global $phpbb_container; - - $phpbb_container->get('phpbb.report.report_reason_list_provider')->display_reasons($reason_id); -} - -/** - * Upload Attachment - filedata is generated here - * Uses upload class - * - * @deprecated 3.2.0-a1 (To be removed: 4.0.0) - * - * @param string $form_name The form name of the file upload input - * @param int $forum_id The id of the forum - * @param bool $local Whether the file is local or not - * @param string $local_storage The path to the local file - * @param bool $is_message Whether it is a PM or not - * @param array $local_filedata A filespec object created for the local file - * - * @return array File data array - */ -function upload_attachment($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = false) -{ - global $phpbb_container; - - /** @var \phpbb\attachment\manager $attachment_manager */ - $attachment_manager = $phpbb_container->get('attachment.manager'); - $file = $attachment_manager->upload($form_name, $forum_id, $local, $local_storage, $is_message, $local_filedata); - unset($attachment_manager); - - return $file; -} - -/** -* Wrapper for php's checkdnsrr function. -* -* @param string $host Fully-Qualified Domain Name -* @param string $type Resource record type to lookup -* Supported types are: MX (default), A, AAAA, NS, TXT, CNAME -* Other types may work or may not work -* -* @return bool|null true if entry found, -* false if entry not found, -* null if this function is not supported by this environment -* -* Since null can also be returned, you probably want to compare the result -* with === true or === false, -* -* @deprecated 3.3.0-b2 (To be removed: 4.0.0) -*/ -function phpbb_checkdnsrr($host, $type = 'MX') -{ - return checkdnsrr($host, $type); -} - -/* - * Wrapper for inet_ntop() - * - * Converts a packed internet address to a human readable representation - * inet_ntop() is supported by PHP since 5.1.0, since 5.3.0 also on Windows. - * - * @param string $in_addr A 32bit IPv4, or 128bit IPv6 address. - * - * @return mixed false on failure, - * string otherwise - * - * @deprecated 3.3.0-b2 (To be removed: 4.0.0) - */ -function phpbb_inet_ntop($in_addr) -{ - return inet_ntop($in_addr); -} - -/** - * Wrapper for inet_pton() - * - * Converts a human readable IP address to its packed in_addr representation - * inet_pton() is supported by PHP since 5.1.0, since 5.3.0 also on Windows. - * - * @param string $address A human readable IPv4 or IPv6 address. - * - * @return false|string false if address is invalid, - * in_addr representation of the given address otherwise (string) - * - * @deprecated 3.3.0-b2 (To be removed: 4.0.0) - */ -function phpbb_inet_pton($address) -{ - return inet_pton($address); -} - -/** - * Hashes an email address to a big integer - * - * @param string $email Email address - * - * @return string Unsigned Big Integer - * - * @deprecated 3.3.0-b2 (To be removed: 4.0.0) - */ -function phpbb_email_hash($email) -{ - return sprintf('%u', crc32(strtolower($email))) . strlen($email); -} - -/** - * Load the autoloaders added by the extensions. - * - * @param string $phpbb_root_path Path to the phpbb root directory. - */ -function phpbb_load_extensions_autoloaders($phpbb_root_path) -{ - $iterator = new \phpbb\finder\recursive_path_iterator( - $phpbb_root_path . 'ext/', - \RecursiveIteratorIterator::SELF_FIRST, - \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS - ); - $iterator->setMaxDepth(2); - - foreach ($iterator as $file_info) - { - if ($file_info->getFilename() === 'vendor' && $iterator->getDepth() === 2) - { - $filename = $file_info->getRealPath() . '/autoload.php'; - if (file_exists($filename)) - { - require $filename; - } - } - } -} - -/** -* Login using http authenticate. -* -* @param array $param Parameter array, see $param_defaults array. -* -* @return void -* -* @deprecated 3.2.10 (To be removed 4.0.0) -*/ -function phpbb_http_login($param) -{ - global $auth, $user, $request; - global $config; - - $param_defaults = array( - 'auth_message' => '', - - 'autologin' => false, - 'viewonline' => true, - 'admin' => false, - ); - - // Overwrite default values with passed values - $param = array_merge($param_defaults, $param); - - // User is already logged in - // We will not overwrite his session - if (!empty($user->data['is_registered'])) - { - return; - } - - // $_SERVER keys to check - $username_keys = array( - 'PHP_AUTH_USER', - 'Authorization', - 'REMOTE_USER', 'REDIRECT_REMOTE_USER', - 'HTTP_AUTHORIZATION', 'REDIRECT_HTTP_AUTHORIZATION', - 'REMOTE_AUTHORIZATION', 'REDIRECT_REMOTE_AUTHORIZATION', - 'AUTH_USER', - ); - - $password_keys = array( - 'PHP_AUTH_PW', - 'REMOTE_PASSWORD', - 'AUTH_PASSWORD', - ); - - $username = null; - foreach ($username_keys as $k) - { - if ($request->is_set($k, \phpbb\request\request_interface::SERVER)) - { - $username = html_entity_decode($request->server($k), ENT_COMPAT); - break; - } - } - - $password = null; - foreach ($password_keys as $k) - { - if ($request->is_set($k, \phpbb\request\request_interface::SERVER)) - { - $password = html_entity_decode($request->server($k), ENT_COMPAT); - break; - } - } - - // Decode encoded information (IIS, CGI, FastCGI etc.) - if (!is_null($username) && is_null($password) && strpos($username, 'Basic ') === 0) - { - list($username, $password) = explode(':', base64_decode(substr($username, 6)), 2); - } - - if (!is_null($username) && !is_null($password)) - { - set_var($username, $username, 'string', true); - set_var($password, $password, 'string', true); - - $auth_result = $auth->login($username, $password, $param['autologin'], $param['viewonline'], $param['admin']); - - if ($auth_result['status'] == LOGIN_SUCCESS) - { - return; - } - else if ($auth_result['status'] == LOGIN_ERROR_ATTEMPTS) - { - send_status_line(401, 'Unauthorized'); - - trigger_error('NOT_AUTHORISED'); - } - } - - // Prepend sitename to auth_message - $param['auth_message'] = ($param['auth_message'] === '') ? $config['sitename'] : $config['sitename'] . ' - ' . $param['auth_message']; - - // We should probably filter out non-ASCII characters - RFC2616 - $param['auth_message'] = preg_replace('/[\x80-\xFF]/', '?', $param['auth_message']); - - header('WWW-Authenticate: Basic realm="' . $param['auth_message'] . '"'); - send_status_line(401, 'Unauthorized'); - - trigger_error('NOT_AUTHORISED'); -} - -/** -* Converts query string (GET) parameters in request into hidden fields. -* -* Useful for forwarding GET parameters when submitting forms with GET method. -* -* It is possible to omit some of the GET parameters, which is useful if -* they are specified in the form being submitted. -* -* sid is always omitted. -* -* @param \phpbb\request\request $request Request object -* @param array $exclude A list of variable names that should not be forwarded -* @return string HTML with hidden fields -* -* @deprecated 3.2.10 (To be removed 4.0.0) -*/ -function phpbb_build_hidden_fields_for_query_params($request, $exclude = null) -{ - $names = $request->variable_names(\phpbb\request\request_interface::GET); - $hidden = ''; - foreach ($names as $name) - { - // Sessions are dealt with elsewhere, omit sid always - if ($name == 'sid') - { - continue; - } - - // Omit any additional parameters requested - if (!empty($exclude) && in_array($name, $exclude)) - { - continue; - } - - $escaped_name = phpbb_quoteattr($name); - - // Note: we might retrieve the variable from POST or cookies - // here. To avoid exposing cookies, skip variables that are - // overwritten somewhere other than GET entirely. - $value = $request->variable($name, '', true); - $get_value = $request->variable($name, '', true, \phpbb\request\request_interface::GET); - if ($value === $get_value) - { - $escaped_value = phpbb_quoteattr($value); - $hidden .= ""; - } - } - return $hidden; -} - -/** -* Delete all PM(s) for a given user and delete the ones without references -* -* @param int $user_id ID of the user whose private messages we want to delete -* -* @return boolean False if there were no pms found, true otherwise. -* -* @deprecated 3.2.10 (To be removed 4.0.0) -*/ -function phpbb_delete_user_pms($user_id) -{ - $user_id = (int) $user_id; - - if (!$user_id) - { - return false; - } - - return phpbb_delete_users_pms(array($user_id)); -} - -/** -* Casts a numeric string $input to an appropriate numeric type (i.e. integer or float) -* -* @param string $input A numeric string. -* -* @return int|float Integer $input if $input fits integer, -* float $input otherwise. -* -* @deprecated 3.2.10 (To be removed 4.0.0) -*/ -function phpbb_to_numeric($input) -{ - return ($input > PHP_INT_MAX) ? (float) $input : (int) $input; -} - -/** -* Check and display the SQL report if requested. -* -* @param \phpbb\request\request_interface $request Request object -* @param \phpbb\auth\auth $auth Auth object -* @param \phpbb\db\driver\driver_interface $db Database connection -* -* @deprecated 3.3.1 (To be removed: 4.0.0-a1); use controller helper's display_sql_report() -*/ -function phpbb_check_and_display_sql_report(\phpbb\request\request_interface $request, \phpbb\auth\auth $auth, \phpbb\db\driver\driver_interface $db) -{ - global $phpbb_container; - - /** @var \phpbb\controller\helper $controller_helper */ - $controller_helper = $phpbb_container->get('controller.helper'); - - $controller_helper->display_sql_report(); -} - /** * Parse cfg file * @param string $filename @@ -909,27 +80,3 @@ function parse_cfg_file($filename, $lines = false) return $parsed_items; } - -/** -* Wraps an url into a simple html page. Used to display attachments in IE. -* this is a workaround for now; might be moved to template system later -* direct any complaints to 1 Microsoft Way, Redmond -* -* @deprecated: 3.3.0-dev (To be removed: 4.0.0) -*/ -function wrap_img_in_html($src, $title) -{ - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo '' . $title . ''; - echo ''; - echo ''; - echo '
        '; - echo '' . $title . ''; - echo '
        '; - echo ''; - echo ''; -} diff --git a/phpBB/includes/functions_content.php b/phpBB/includes/functions_content.php index 941b2eb246..1e46bf4e9b 100644 --- a/phpBB/includes/functions_content.php +++ b/phpBB/includes/functions_content.php @@ -288,7 +288,27 @@ function make_jumpbox($action, $forum_id = false, $select_all = false, $acl_list */ function bump_topic_allowed($forum_id, $topic_bumped, $last_post_time, $topic_poster, $last_topic_poster) { - global $config, $auth, $user; + global $config, $auth, $user, $phpbb_dispatcher; + + /** + * Event to run code before the topic bump checks + * + * @event core.bump_topic_allowed_before + * @var int forum_id ID of the forum + * @var int topic_bumped Flag indicating if the topic was already bumped (0/1) + * @var int last_post_time The time of the topic last post + * @var int topic_poster User ID of the topic author + * @var int last_topic_poster User ID of the topic last post author + * @since 3.3.14-RC1 + */ + $vars = [ + 'forum_id', + 'topic_bumped', + 'last_post_time', + 'topic_poster', + 'last_topic_poster', + ]; + extract($phpbb_dispatcher->trigger_event('core.bump_topic_allowed_before', compact($vars))); // Check permission and make sure the last post was not already bumped if (!$auth->acl_get('f_bump', $forum_id) || $topic_bumped) @@ -311,6 +331,28 @@ function bump_topic_allowed($forum_id, $topic_bumped, $last_post_time, $topic_po return false; } + /** + * Event to run code after the topic bump checks + * + * @event core.bump_topic_allowed_after + * @var int forum_id ID of the forum + * @var int topic_bumped Flag indicating if the topic was already bumped (0/1) + * @var int last_post_time The time of the topic last post + * @var int topic_poster User ID of the topic author + * @var int last_topic_poster User ID of the topic last post author + * @var int bump_time Bump time range + * @since 3.3.14-RC1 + */ + $vars = [ + 'forum_id', + 'topic_bumped', + 'last_post_time', + 'topic_poster', + 'last_topic_poster', + 'bump_time', + ]; + extract($phpbb_dispatcher->trigger_event('core.bump_topic_allowed_after', compact($vars))); + // A bump time of 0 will completely disable the bump feature... not intended but might be useful. return $bump_time; } @@ -324,121 +366,95 @@ 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(string $text, array $words, int $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 ", ' ')); - - // 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); - - $word_indizes = array(); - if (count($words)) + if ($length <= 0) { - $match = ''; - // find the starting indizes of all words - foreach ($words as $word) - { - 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); - } + return $text; } - if (!count($words) || !count($word_indizes)) + // We need to turn the entities back into their original form, to not cut the message in between them + $text = htmlspecialchars_decode($text); + + // Replace all spaces/invisible characters with single spaces + $text = preg_replace("/[\p{Z}\h\v]+/u", ' ', $text); + + $text_length = utf8_strlen($text); + + // Get first occurrence of each word + $word_indexes = []; + foreach ($words as $word) { - return str_replace($characters, $entities, ((utf8_strlen($text) >= $length + 3) ? utf8_substr($text, 0, $length) . '...' : $text)); + $pos = utf8_stripos($text, $word); + + if ($pos !== false) + { + $word_indexes[$pos] = $word; + } + } + if (!empty($word_indexes)) + { + 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; } - return ''; + $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('/[^\p{L}\p{N}][\p{L}\p{N}]/u', $fragment, $matches, PREG_OFFSET_CAPTURE)) + { + $fragment_start = utf8_strlen(substr($fragment, 0, (int) $matches[0][1])) + 1; + } + + // Find the last valid alphanumeric character in the fragment to don't cut words + if ($end < $text_length - 1 && preg_match_all('/[\p{L}\p{N}][^\p{L}\p{N}]/u', $fragment, $matches, PREG_OFFSET_CAPTURE)) + { + $fragment_end = utf8_strlen(substr($fragment, 0, end($matches[0])[1])); + } + + $output[] = utf8_substr($fragment, $fragment_start, $fragment_end - $fragment_start + 1); + } + + return ($fragments[0][0] !== 0 ? '... ' : '') . utf8_htmlspecialchars(implode(' ... ', $output)) . ($end < $text_length - 1 ? ' ...' : ''); } /** @@ -1260,19 +1276,7 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count_a { if ($config['img_display_inlined']) { - if ($config['img_link_width'] || $config['img_link_height']) - { - try - { - $file_info = $storage_attachment->file_info($filename); - - $display_cat = ($file_info->image_width <= $config['img_link_width'] && $file_info->image_height <= $config['img_link_height']) ? attachment_category::IMAGE : attachment_category::NONE; - } - catch (\Exception $e) - { - $display_cat = attachment_category::NONE; - } - } + $display_cat = attachment_category::IMAGE; } else { diff --git a/phpBB/includes/functions_display.php b/phpBB/includes/functions_display.php index 67affce13d..7a4e70f944 100644 --- a/phpBB/includes/functions_display.php +++ b/phpBB/includes/functions_display.php @@ -1595,7 +1595,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_last_active']; + $last_active = $data['user_last_active'] ?: ($data['session_time'] ?? 0); } else { diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php index 329a9f65dd..c94a2a5c42 100644 --- a/phpBB/includes/functions_messenger.php +++ b/phpBB/includes/functions_messenger.php @@ -1417,22 +1417,22 @@ class smtp_class global $user; // Here we try to determine the *real* hostname (reverse DNS entry preferrably) - $local_host = $user->host; - - if (function_exists('php_uname')) + if (function_exists('php_uname') && !empty($local_host = php_uname('n'))) { - $local_host = php_uname('n'); - // Able to resolve name to IP if (($addr = @gethostbyname($local_host)) !== $local_host) { // Able to resolve IP back to name - if (($name = @gethostbyaddr($addr)) !== $addr) + if (!empty($name = @gethostbyaddr($addr)) && $name !== $addr) { $local_host = $name; } } } + else + { + $local_host = $user->host; + } // If we are authenticating through pop-before-smtp, we // have to login ones before we get authenticated diff --git a/phpBB/includes/functions_module.php b/phpBB/includes/functions_module.php index ae4e77e16a..d1f35107c5 100644 --- a/phpBB/includes/functions_module.php +++ b/phpBB/includes/functions_module.php @@ -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 test permission mode + if ($this->p_class === 'acp' && $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) { diff --git a/phpBB/includes/functions_privmsgs.php b/phpBB/includes/functions_privmsgs.php index 5e7033d09c..1075a5a2bc 100644 --- a/phpBB/includes/functions_privmsgs.php +++ b/phpBB/includes/functions_privmsgs.php @@ -1691,7 +1691,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'); diff --git a/phpBB/includes/mcp/mcp_queue.php b/phpBB/includes/mcp/mcp_queue.php index 185316a705..fbde670bd0 100644 --- a/phpBB/includes/mcp/mcp_queue.php +++ b/phpBB/includes/mcp/mcp_queue.php @@ -284,6 +284,7 @@ class mcp_queue $post_data = array( 'S_MCP_QUEUE' => true, '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_DELETE_POST' => $auth->acl_get('m_delete', $post_info['forum_id']), 'S_CAN_VIEWIP' => $auth->acl_get('m_info', $post_info['forum_id']), 'S_POST_REPORTED' => $post_info['post_reported'], diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php index 337b6ccab8..9b381d22f8 100644 --- a/phpBB/includes/message_parser.php +++ b/phpBB/includes/message_parser.php @@ -1179,8 +1179,6 @@ class parse_message extends bbcode_firstpass // Set some config values $parser->set_vars(array( 'max_font_size' => $config['max_' . $this->mode . '_font_size'], - 'max_img_height' => $config['max_' . $this->mode . '_img_height'], - 'max_img_width' => $config['max_' . $this->mode . '_img_width'], 'max_smilies' => $config['max_' . $this->mode . '_smilies'], 'max_urls' => $config['max_' . $this->mode . '_urls'] )); diff --git a/phpBB/includes/questionnaire/questionnaire.php b/phpBB/includes/questionnaire/questionnaire.php index 8ab18ad8c8..74675e0e03 100644 --- a/phpBB/includes/questionnaire/questionnaire.php +++ b/phpBB/includes/questionnaire/questionnaire.php @@ -361,8 +361,6 @@ class phpbb_questionnaire_phpbb_data_provider 'hot_threshold' => true, 'img_create_thumbnail' => true, 'img_display_inlined' => true, - 'img_link_height' => true, - 'img_link_width' => true, 'img_max_height' => true, 'img_max_thumb_width' => true, 'img_max_width' => true, @@ -406,8 +404,6 @@ class phpbb_questionnaire_phpbb_data_provider 'max_reg_attempts' => true, 'max_sig_chars' => true, 'max_sig_font_size' => true, - 'max_sig_img_height' => true, - 'max_sig_img_width' => true, 'max_sig_smilies' => true, 'max_sig_urls' => true, 'min_name_chars' => true, diff --git a/phpBB/includes/ucp/ucp_register.php b/phpBB/includes/ucp/ucp_register.php index 40b14a9b54..b8d0d78b40 100644 --- a/phpBB/includes/ucp/ucp_register.php +++ b/phpBB/includes/ucp/ucp_register.php @@ -235,8 +235,10 @@ class ucp_register // The CAPTCHA kicks in here. We can't help that the information gets lost on language change. if ($config['enable_confirm']) { - $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']); - $captcha->init(CONFIRM_REG); + /** @var \phpbb\captcha\factory $captcha_factory */ + $captcha_factory = $phpbb_container->get('captcha.factory'); + $captcha = $captcha_factory->get_instance($config['captcha_plugin']); + $captcha->init(\phpbb\captcha\plugins\confirm_type::REGISTRATION); } $timezone = $config['board_timezone']; @@ -291,10 +293,9 @@ class ucp_register if ($config['enable_confirm']) { - $vc_response = $captcha->validate($data); - if ($vc_response !== false) + if ($captcha->validate() !== true) { - $error[] = $vc_response; + $error[] = $captcha->get_error(); } if ($config['max_reg_attempts'] && $captcha->get_attempt_count() > $config['max_reg_attempts']) @@ -426,7 +427,7 @@ class ucp_register } // Okay, captcha, your job is done. - if ($config['enable_confirm'] && isset($captcha)) + if ($config['enable_confirm']) { $captcha->reset(); } diff --git a/phpBB/includes/utf/utf_tools.php b/phpBB/includes/utf/utf_tools.php index b8c35a5048..ed86829b97 100644 --- a/phpBB/includes/utf/utf_tools.php +++ b/phpBB/includes/utf/utf_tools.php @@ -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 diff --git a/phpBB/install/convertors/functions_phpbb20.php b/phpBB/install/convertors/functions_phpbb20.php index 75a0b8def4..168c6be348 100644 --- a/phpBB/install/convertors/functions_phpbb20.php +++ b/phpBB/install/convertors/functions_phpbb20.php @@ -1420,9 +1420,9 @@ function phpbb_attachment_extension_group_name() $result = $db->sql_query($sql); $extension_groups_updated = array(); - while ($lang_dir = $db->sql_fetchfield('lang_dir')) + while ($row = $db->sql_fetchrow($result)) { - $lang_dir = basename($lang_dir); + $lang_dir = basename($row['lang_dir']); $lang_file = $phpbb_root_path . 'language/' . $lang_dir . '/acp/attachments.' . $phpEx; if (!file_exists($lang_file)) @@ -1676,8 +1676,6 @@ function phpbb_import_attach_config() $config->set('img_display_inlined', $attach_config['img_display_inlined']); $config->set('img_max_width', $attach_config['img_max_width']); $config->set('img_max_height', $attach_config['img_max_height']); - $config->set('img_link_width', $attach_config['img_link_width']); - $config->set('img_link_height', $attach_config['img_link_height']); $config->set('img_create_thumbnail', $attach_config['img_create_thumbnail']); $config->set('img_max_thumb_width', 400); $config->set('img_min_thumb_filesize', $attach_config['img_min_thumb_filesize']); diff --git a/phpBB/install/schemas/schema_data.sql b/phpBB/install/schemas/schema_data.sql index ba8f654a90..21b26ee9c8 100644 --- a/phpBB/install/schemas/schema_data.sql +++ b/phpBB/install/schemas/schema_data.sql @@ -77,6 +77,9 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_gd_wave', INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_gd_x_grid', '25'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_gd_y_grid', '25'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_plugin', 'core.captcha.plugins.incomplete'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_turnstile_sitekey', ''); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_turnstile_secret', ''); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_turnstile_theme', 'light'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('check_attachment_content', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('check_dnsbl', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('chg_passforce', '0'); @@ -155,8 +158,6 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('hot_threshold', '2 INSERT INTO phpbb_config (config_name, config_value) VALUES ('icons_path', 'images/icons'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('img_create_thumbnail', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('img_display_inlined', '1'); -INSERT INTO phpbb_config (config_name, config_value) VALUES ('img_link_height', '0'); -INSERT INTO phpbb_config (config_name, config_value) VALUES ('img_link_width', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('img_max_height', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('img_max_thumb_width', '400'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('img_max_width', '0'); @@ -227,8 +228,6 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_quote_depth', INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_reg_attempts', '5'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_sig_chars', '255'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_sig_font_size', '200'); -INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_sig_img_height', '0'); -INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_sig_img_width', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_sig_smilies', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_sig_urls', '5'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('mention_batch_size', '50'); @@ -284,6 +283,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('site_desc', '{L_CO INSERT INTO phpbb_config (config_name, config_value) VALUES ('site_home_text', ''); INSERT INTO phpbb_config (config_name, config_value) VALUES ('site_home_url', ''); INSERT INTO phpbb_config (config_name, config_value) VALUES ('sitename', '{L_CONFIG_SITENAME}'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('sitename_short', ''); INSERT INTO phpbb_config (config_name, config_value) VALUES ('smilies_path', 'images/smilies'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('smilies_per_page', '50'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('smtp_allow_self_signed', '0'); @@ -712,60 +712,60 @@ INSERT INTO phpbb_posts (topic_id, forum_id, poster_id, icon_id, post_time, post INSERT INTO phpbb_topics_posted (user_id, topic_id, topic_posted) VALUES (2, 1, 1); # -- Smilies -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':D', 'icon_e_biggrin.gif', '{L_SMILIES_VERY_HAPPY}', 15, 17, 1); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':-D', 'icon_e_biggrin.gif', '{L_SMILIES_VERY_HAPPY}', 15, 17, 2); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':grin:', 'icon_e_biggrin.gif', '{L_SMILIES_VERY_HAPPY}', 15, 17, 3); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':)', 'icon_e_smile.gif', '{L_SMILIES_SMILE}', 15, 17, 4); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':-)', 'icon_e_smile.gif', '{L_SMILIES_SMILE}', 15, 17, 5); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':smile:', 'icon_e_smile.gif', '{L_SMILIES_SMILE}', 15, 17, 6); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (';)', 'icon_e_wink.gif', '{L_SMILIES_WINK}', 15, 17, 7); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (';-)', 'icon_e_wink.gif', '{L_SMILIES_WINK}', 15, 17, 8); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':wink:', 'icon_e_wink.gif', '{L_SMILIES_WINK}', 15, 17, 9); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':(', 'icon_e_sad.gif', '{L_SMILIES_SAD}', 15, 17, 10); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':-(', 'icon_e_sad.gif', '{L_SMILIES_SAD}', 15, 17, 11); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':sad:', 'icon_e_sad.gif', '{L_SMILIES_SAD}', 15, 17, 12); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':o', 'icon_e_surprised.gif', '{L_SMILIES_SURPRISED}', 15, 17, 13); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':-o', 'icon_e_surprised.gif', '{L_SMILIES_SURPRISED}', 15, 17, 14); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':eek:', 'icon_e_surprised.gif', '{L_SMILIES_SURPRISED}', 15, 17, 15); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':shock:', 'icon_eek.gif', '{L_SMILIES_SHOCKED}', 15, 17, 16); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':?', 'icon_e_confused.gif', '{L_SMILIES_CONFUSED}', 15, 17, 17); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':-?', 'icon_e_confused.gif', '{L_SMILIES_CONFUSED}', 15, 17, 18); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':???:', 'icon_e_confused.gif', '{L_SMILIES_CONFUSED}', 15, 17, 19); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES ('8-)', 'icon_cool.gif', '{L_SMILIES_COOL}', 15, 17, 20); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':cool:', 'icon_cool.gif', '{L_SMILIES_COOL}', 15, 17, 21); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':lol:', 'icon_lol.gif', '{L_SMILIES_LAUGHING}', 15, 17, 22); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':x', 'icon_mad.gif', '{L_SMILIES_MAD}', 15, 17, 23); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':-x', 'icon_mad.gif', '{L_SMILIES_MAD}', 15, 17, 24); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':mad:', 'icon_mad.gif', '{L_SMILIES_MAD}', 15, 17, 25); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':P', 'icon_razz.gif', '{L_SMILIES_RAZZ}', 15, 17, 26); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':-P', 'icon_razz.gif', '{L_SMILIES_RAZZ}', 15, 17, 27); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':razz:', 'icon_razz.gif', '{L_SMILIES_RAZZ}', 15, 17, 28); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':oops:', 'icon_redface.gif', '{L_SMILIES_EMARRASSED}', 15, 17, 29); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':cry:', 'icon_cry.gif', '{L_SMILIES_CRYING}', 15, 17, 30); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':evil:', 'icon_evil.gif', '{L_SMILIES_EVIL}', 15, 17, 31); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':twisted:', 'icon_twisted.gif', '{L_SMILIES_TWISTED_EVIL}', 15, 17, 32); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':roll:', 'icon_rolleyes.gif', '{L_SMILIES_ROLLING_EYES}', 15, 17, 33); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':!:', 'icon_exclaim.gif', '{L_SMILIES_EXCLAMATION}', 15, 17, 34); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':?:', 'icon_question.gif', '{L_SMILIES_QUESTION}', 15, 17, 35); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':idea:', 'icon_idea.gif', '{L_SMILIES_IDEA}', 15, 17, 36); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':arrow:', 'icon_arrow.gif', '{L_SMILIES_ARROW}', 15, 17, 37); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':|', 'icon_neutral.gif', '{L_SMILIES_NEUTRAL}', 15, 17, 38); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':-|', 'icon_neutral.gif', '{L_SMILIES_NEUTRAL}', 15, 17, 39); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':mrgreen:', 'icon_mrgreen.gif', '{L_SMILIES_MR_GREEN}', 15, 17, 40); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':geek:', 'icon_e_geek.gif', '{L_SMILIES_GEEK}', 17, 17, 41); -INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':ugeek:', 'icon_e_ugeek.gif', '{L_SMILIES_UBER_GEEK}', 17, 18, 42); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':D', 'icon_e_biggrin.svg', '{L_SMILIES_VERY_HAPPY}', 15, 17, 1); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':-D', 'icon_e_biggrin.svg', '{L_SMILIES_VERY_HAPPY}', 15, 17, 2); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':grin:', 'icon_e_biggrin.svg', '{L_SMILIES_VERY_HAPPY}', 15, 17, 3); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':)', 'icon_e_smile.svg', '{L_SMILIES_SMILE}', 15, 17, 4); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':-)', 'icon_e_smile.svg', '{L_SMILIES_SMILE}', 15, 17, 5); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':smile:', 'icon_e_smile.svg', '{L_SMILIES_SMILE}', 15, 17, 6); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (';)', 'icon_e_wink.svg', '{L_SMILIES_WINK}', 15, 17, 7); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (';-)', 'icon_e_wink.svg', '{L_SMILIES_WINK}', 15, 17, 8); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':wink:', 'icon_e_wink.svg', '{L_SMILIES_WINK}', 15, 17, 9); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':(', 'icon_e_sad.svg', '{L_SMILIES_SAD}', 15, 17, 10); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':-(', 'icon_e_sad.svg', '{L_SMILIES_SAD}', 15, 17, 11); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':sad:', 'icon_e_sad.svg', '{L_SMILIES_SAD}', 15, 17, 12); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':o', 'icon_e_surprised.svg', '{L_SMILIES_SURPRISED}', 15, 17, 13); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':-o', 'icon_e_surprised.svg', '{L_SMILIES_SURPRISED}', 15, 17, 14); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':eek:', 'icon_e_surprised.svg', '{L_SMILIES_SURPRISED}', 15, 17, 15); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':shock:', 'icon_eek.svg', '{L_SMILIES_SHOCKED}', 15, 17, 16); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':?', 'icon_e_confused.svg', '{L_SMILIES_CONFUSED}', 15, 17, 17); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':-?', 'icon_e_confused.svg', '{L_SMILIES_CONFUSED}', 15, 17, 18); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':???:', 'icon_e_confused.svg', '{L_SMILIES_CONFUSED}', 15, 17, 19); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES ('8-)', 'icon_cool.svg', '{L_SMILIES_COOL}', 15, 17, 20); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':cool:', 'icon_cool.svg', '{L_SMILIES_COOL}', 15, 17, 21); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':lol:', 'icon_lol.svg', '{L_SMILIES_LAUGHING}', 15, 17, 22); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':x', 'icon_mad.svg', '{L_SMILIES_MAD}', 15, 17, 23); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':-x', 'icon_mad.svg', '{L_SMILIES_MAD}', 15, 17, 24); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':mad:', 'icon_mad.svg', '{L_SMILIES_MAD}', 15, 17, 25); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':P', 'icon_razz.svg', '{L_SMILIES_RAZZ}', 15, 17, 26); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':-P', 'icon_razz.svg', '{L_SMILIES_RAZZ}', 15, 17, 27); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':razz:', 'icon_razz.svg', '{L_SMILIES_RAZZ}', 15, 17, 28); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':oops:', 'icon_redface.svg', '{L_SMILIES_EMARRASSED}', 15, 17, 29); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':cry:', 'icon_cry.svg', '{L_SMILIES_CRYING}', 15, 17, 30); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':evil:', 'icon_evil.svg', '{L_SMILIES_EVIL}', 15, 17, 31); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':twisted:', 'icon_twisted.svg', '{L_SMILIES_TWISTED_EVIL}', 15, 17, 32); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':roll:', 'icon_rolleyes.svg', '{L_SMILIES_ROLLING_EYES}', 15, 17, 33); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':!:', 'icon_exclaim.svg', '{L_SMILIES_EXCLAMATION}', 15, 17, 34); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':?:', 'icon_question.svg', '{L_SMILIES_QUESTION}', 15, 17, 35); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':idea:', 'icon_idea.svg', '{L_SMILIES_IDEA}', 15, 17, 36); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':arrow:', 'icon_arrow.svg', '{L_SMILIES_ARROW}', 15, 17, 37); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':|', 'icon_neutral.svg', '{L_SMILIES_NEUTRAL}', 15, 17, 38); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':-|', 'icon_neutral.svg', '{L_SMILIES_NEUTRAL}', 15, 17, 39); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':mrgreen:', 'icon_mrgreen.svg', '{L_SMILIES_MR_GREEN}', 15, 17, 40); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':geek:', 'icon_e_geek.svg', '{L_SMILIES_GEEK}', 17, 17, 41); +INSERT INTO phpbb_smilies (code, smiley_url, emotion, smiley_width, smiley_height, smiley_order) VALUES (':ugeek:', 'icon_e_ugeek.svg', '{L_SMILIES_UBER_GEEK}', 17, 18, 42); # -- icons -INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('misc/fire.gif', 16, 16, 1, 1); -INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('smile/redface.gif', 16, 16, 9, 1); -INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('smile/mrgreen.gif', 16, 16, 10, 1); -INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('misc/heart.gif', 16, 16, 4, 1); -INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('misc/star.gif', 16, 16, 2, 1); -INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('misc/radioactive.gif', 16, 16, 3, 1); -INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('misc/thinking.gif', 16, 16, 5, 1); -INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('smile/info.gif', 16, 16, 8, 1); -INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('smile/question.gif', 16, 16, 6, 1); -INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('smile/alert.gif', 16, 16, 7, 1); +INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('misc/fire.svg', 16, 16, 1, 1); +INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('smile/redface.svg', 16, 16, 9, 1); +INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('smile/mrgreen.svg', 16, 16, 10, 1); +INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('misc/heart.svg', 16, 16, 4, 1); +INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('misc/star.svg', 16, 16, 2, 1); +INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('misc/radioactive.svg', 16, 16, 3, 1); +INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('misc/thinking.svg', 16, 16, 5, 1); +INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('smile/info.svg', 16, 16, 8, 1); +INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('smile/question.svg', 16, 16, 6, 1); +INSERT INTO phpbb_icons (icons_url, icons_width, icons_height, icons_order, display_on_posting) VALUES ('smile/alert.svg', 16, 16, 7, 1); # -- reasons INSERT INTO phpbb_reports_reasons (reason_title, reason_description, reason_order) VALUES ('warez', '{L_REPORT_WAREZ}', 1); diff --git a/phpBB/install/startup.php b/phpBB/install/startup.php index 71f5744678..b8ceb37342 100644 --- a/phpBB/install/startup.php +++ b/phpBB/install/startup.php @@ -51,7 +51,15 @@ function installer_msg_handler($errno, $msg_text, $errfile, $errline): bool { 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; } diff --git a/phpBB/language/en/acp/attachments.php b/phpBB/language/en/acp/attachments.php index 351f61dbef..630977b5ce 100644 --- a/phpBB/language/en/acp/attachments.php +++ b/phpBB/language/en/acp/attachments.php @@ -111,8 +111,6 @@ $lang = array_merge($lang, array( 'GO_TO_EXTENSIONS' => 'Go to extension management screen', 'GROUP_NAME' => 'Group name', - 'IMAGE_LINK_SIZE' => 'Image link dimensions', - 'IMAGE_LINK_SIZE_EXPLAIN' => 'Display image attachment as an inline text link if image is larger than this. To disable this behaviour, set the values to 0px by 0px.', 'IMAGE_QUALITY' => 'Quality of uploaded image attachments (JPEG only)', 'IMAGE_QUALITY_EXPLAIN' => 'Specify value between 50% (smaller file size) and 90% (higher quality). Quality higher than 90% increases filesize and is disabled. Setting only applies if maximum image dimensions are set to a value other than 0px by 0px.', 'IMAGE_STRIP_METADATA' => 'Strip image metadata (JPEG only)', diff --git a/phpBB/language/en/acp/board.php b/phpBB/language/en/acp/board.php index 3228db126b..633df91138 100644 --- a/phpBB/language/en/acp/board.php +++ b/phpBB/language/en/acp/board.php @@ -69,6 +69,8 @@ $lang = array_merge($lang, array( 'SITE_HOME_URL' => 'Main website URL', 'SITE_HOME_URL_EXPLAIN' => 'If specified, a link to this URL will be prepended to your board’s breadcrumbs and the board logo will link to this URL instead of the forum index. An absolute URL is required, e.g. http://www.phpbb.com.', 'SITE_NAME' => 'Site name', + 'SITE_NAME_SHORT' => 'Short site name', + 'SITE_NAME_SHORT_EXPLAIN' => 'Short name will be used if your site is added to a mobile device’s home screen. It can not exceed 12 characters (Emoji is supported).', 'SYSTEM_TIMEZONE' => 'Guest timezone', 'SYSTEM_TIMEZONE_EXPLAIN' => 'Timezone to use for displaying times to users who are not logged in (guests, bots). Logged in users set their timezone during registration and can change it in their user control panel.', 'WARNINGS_EXPIRE' => 'Warning duration', @@ -206,10 +208,6 @@ $lang = array_merge($lang, array( 'MAX_SIG_FONT_SIZE' => 'Maximum signature font size', 'MAX_SIG_FONT_SIZE_EXPLAIN' => 'Maximum font size allowed in user signatures. Set to 0 for unlimited size.', - 'MAX_SIG_IMG_HEIGHT' => 'Maximum signature image height', - 'MAX_SIG_IMG_HEIGHT_EXPLAIN' => 'Maximum height of an image file in user signatures. Set to 0 for unlimited height.', - 'MAX_SIG_IMG_WIDTH' => 'Maximum signature image width', - 'MAX_SIG_IMG_WIDTH_EXPLAIN' => 'Maximum width of an image file in user signatures. Set to 0 for unlimited width.', 'MAX_SIG_LENGTH' => 'Maximum signature length', 'MAX_SIG_LENGTH_EXPLAIN' => 'Maximum number of characters in user signatures.', 'MAX_SIG_SMILIES' => 'Maximum smilies per signature', @@ -472,8 +470,8 @@ $lang = array_merge($lang, array( 'SMILIES_PATH_EXPLAIN' => 'Path under your phpBB root directory, e.g. images/smilies.', 'UPLOAD_ICONS_PATH' => 'Extension group icons storage path', 'UPLOAD_ICONS_PATH_EXPLAIN' => 'Path under your phpBB root directory, e.g. images/upload_icons.', - 'USE_SYSTEM_CRON' => 'Run periodic tasks from system cron', - 'USE_SYSTEM_CRON_EXPLAIN' => 'When off, phpBB will arrange for periodic tasks to be run automatically. When on, phpBB will not schedule any periodic tasks by itself; a system administrator must arrange for bin/phpbbcli.php cron:run to be run by the system cron facility at regular intervals (e.g. every 5 minutes).', + 'USE_SYSTEM_CRON' => 'Run periodic tasks from operating system cron', + 'USE_SYSTEM_CRON_EXPLAIN' => 'When disabled, phpBB will arrange for periodic tasks to be run automatically. When enabled, phpBB will not schedule any periodic tasks by itself; a system administrator must arrange for bin/phpbbcli.php cron:run to be run by the operating system cron facility at regular intervals (e.g. every 5 minutes).', )); // Security Settings diff --git a/phpBB/language/en/acp/extensions.php b/phpBB/language/en/acp/extensions.php index c6eb147b86..5ae3735cf7 100644 --- a/phpBB/language/en/acp/extensions.php +++ b/phpBB/language/en/acp/extensions.php @@ -36,14 +36,15 @@ if (empty($lang) || !is_array($lang)) $lang = array_merge($lang, array( - 'EXTENSION_ALREADY_INSTALLED' => 'The “%s” extension has already been installed.', - 'EXTENSION_ALREADY_INSTALLED_MANUALLY' => 'The “%s” extension has already been installed manually.', - 'EXTENSION_ALREADY_MANAGED' => 'The “%s” extension is already managed.', - 'EXTENSION_CANNOT_MANAGE_FILESYSTEM_ERROR' => 'The “%s” extension cannot be managed because the existing files could not be removed from the filesystem.', - 'EXTENSION_CANNOT_MANAGE_INSTALL_ERROR' => 'The “%s” extension could not be installed. The prior installation of this extension has been restored.', - 'EXTENSION_MANAGED_WITH_CLEAN_ERROR' => 'The “%1$s” extension has been installed but an error occurred and the old files could not be removed. You might want to delete the “%2$s” files manually.', - 'EXTENSION_MANAGED_WITH_ENABLE_ERROR' => 'The “%s” extension has been installed but an error occurred while enabling it.', - 'EXTENSION_NOT_INSTALLED' => 'The “%s” extension is not installed.', + 'EXTENSIONS_ALREADY_INSTALLED' => 'The “%s” extension has already been installed.', + 'EXTENSIONS_ALREADY_INSTALLED_MANUALLY' => 'The “%s” extension has already been installed manually.', + 'EXTENSIONS_ALREADY_MANAGED' => 'The “%s” extension is already managed.', + 'EXTENSIONS_CANNOT_MANAGE_FILESYSTEM_ERROR' => 'The “%s” extension cannot be managed because the existing files could not be removed from the filesystem.', + 'EXTENSIONS_CANNOT_MANAGE_INSTALL_ERROR' => 'The “%s” extension could not be installed. The prior installation of this extension has been restored.', + 'EXTENSIONS_MANAGED_WITH_CLEAN_ERROR' => 'The “%1$s” extension has been installed but an error occurred and the old files could not be removed. You might want to delete the “%2$s” files manually.', + 'EXTENSIONS_MANAGED_WITH_ENABLE_ERROR' => 'The “%s” extension has been installed but an error occurred while enabling it.', + 'EXTENSIONS_NOT_INSTALLED' => 'The “%s” extension is not installed.', + 'EXTENSIONS_NOT_MANAGED' => 'The “%s” extension is not being managed.', 'ENABLING_EXTENSIONS' => 'Enabling extensions', 'DISABLING_EXTENSIONS' => 'Disabling extensions', @@ -62,8 +63,9 @@ $lang = array_merge($lang, array( 'DETAILS' => 'Details', - 'EXTENSIONS_DISABLED' => 'Disabled Extensions', - 'EXTENSIONS_ENABLED' => 'Enabled Extensions', + 'EXTENSIONS_NOT_INSTALLED' => 'Not installed Extensions', + 'EXTENSIONS_DISABLED' => 'Disabled Extensions', + 'EXTENSIONS_ENABLED' => 'Enabled Extensions', 'EXTENSION_DELETE_DATA' => 'Delete data', 'EXTENSION_DISABLE' => 'Disable', @@ -74,6 +76,8 @@ $lang = array_merge($lang, array( 'EXTENSION_DELETE_DATA_EXPLAIN' => 'Deleting an extension’s data removes all of its data and settings. The extension files are retained so it can be enabled again.', 'EXTENSION_DISABLE_EXPLAIN' => 'Disabling an extension retains its files, data and settings but removes any functionality added by the extension.', 'EXTENSION_ENABLE_EXPLAIN' => 'Enabling an extension allows you to use it on your board.', + 'EXTENSION_REMOVE_EXPLAIN' => 'Removing an extension removes all of its files, data and settings.', + 'EXTENSION_UPDATE_EXPLAIN' => 'Updating an extension will install the latest version compatible with your board, removing old files and replacing them with new ones, and updating the database if necessary.', 'EXTENSION_DELETE_DATA_IN_PROGRESS' => 'The extension’s data is currently being deleted. Please do not leave or refresh this page until it is completed.', 'EXTENSION_DISABLE_IN_PROGRESS' => 'The extension is currently being disabled. Please do not leave or refresh this page until it is completed.', @@ -86,25 +90,25 @@ $lang = array_merge($lang, array( 'EXTENSION_NAME' => 'Extension Name', 'EXTENSION_ACTIONS' => 'Actions', 'EXTENSION_OPTIONS' => 'Options', - 'EXTENSION_INSTALL_HEADLINE'=> 'Installing an extension', - 'EXTENSION_INSTALL_EXPLAIN' => '
          -
        1. Download an extension from phpBB’s extensions database
        2. -
        3. Unzip the extension and upload it to the ext/ directory of your phpBB board
        4. -
        5. Enable the extension, here in the Extensions manager
        6. -
        ', - 'EXTENSION_UPDATE_HEADLINE' => 'Updating an extension', - 'EXTENSION_UPDATE_EXPLAIN' => '
          -
        1. Disable the extension
        2. -
        3. Delete the extension’s files from the filesystem
        4. -
        5. Upload the new files
        6. -
        7. Enable the extension
        8. -
        ', - 'EXTENSION_REMOVE_HEADLINE' => 'Completely removing an extension from your board', - 'EXTENSION_REMOVE_EXPLAIN' => '
          -
        1. Disable the extension
        2. -
        3. Delete the extension’s data
        4. -
        5. Delete the extension’s files from the filesystem
        6. -
        ', + 'EXTENSION_INSTALLING_HEADLINE' => 'Installing an extension', + 'EXTENSION_INSTALLING_EXPLAIN' => [ + 0 => 'Download an extension from phpBB’s extensions database', + 1 => 'Unzip the extension and upload it to the ext/ directory of your phpBB board', + 2 => 'Enable the extension, here in the Extensions manager', + ], + 'EXTENSION_REMOVING_HEADLINE' => 'Deleting an extension from your board', + 'EXTENSION_REMOVING_EXPLAIN' => [ + 0 => 'Disable the extension', + 1 => 'Delete the extension’s data', + 2 => 'Delete the extension‘s files from the filesystem', + ], + 'EXTENSION_UPDATING_HEADLINE' => 'Updating an extension', + 'EXTENSION_UPDATING_EXPLAIN' => [ + 0 => 'Disable the extension', + 1 => 'Delete the extension’s files from the filesystem', + 2 => 'Upload the new files', + 3 => 'Enable the extension', + ], 'EXTENSION_DELETE_DATA_CONFIRM' => 'Are you sure that you wish to delete the data associated with “%s”?

        This removes all of its data and settings and cannot be undone!', 'EXTENSION_DISABLE_CONFIRM' => 'Are you sure that you wish to disable the “%s” extension?', diff --git a/phpBB/language/en/acp/posting.php b/phpBB/language/en/acp/posting.php index 3bff6b9185..f252864eb6 100644 --- a/phpBB/language/en/acp/posting.php +++ b/phpBB/language/en/acp/posting.php @@ -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 #FF1234 or a CSS colour keyword such as fuchsia or InactiveBorder', + 'ALNUM' => 'Characters from the latin alphabet (A-Z) and numbers.', + 'CHOICE' => 'A choice of specified values, e.g. {CHOICE=spades,hearts,diamonds,clubs}. The values are treated as case-insensitive by default and can be treated case-sensitive by specifying the caseSensitive option: {CHOICE=Spades,Hearts,Diamonds,Clubs;caseSensitive}', + 'FLOAT' => 'A decimal value, e.g. 0.5.', + 'HASHMAP' => 'Maps strings to their replacement in the form {HASHMAP=string1:replacement1,string2:replacement2}. Case-sensitive. Preserves unknown values by default.', + 'INT' => 'An integer value, e.g. 2.', + '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 {MAP=string1:replacement1,string2:replacement2}. Case-insensitive. Preserves unknown values by default.', + 'RANGE' => 'Accepts an integer in the given range, e.g. {RANGE=-10,42}.', + 'REGEXP' => 'Validates its value against a given regexp, e.g. {REGEXP=/^foo\w+bar$/}.', + 'TIMESTAMP' => 'A timestamp such as 1h30m10s which will be converted to a number of seconds. Also accepts a number.', + 'UINT' => 'An unsigned integer value. Same as {INT}, but rejects values less than 0.', ), )); diff --git a/phpBB/language/en/captcha_qa.php b/phpBB/language/en/captcha_qa.php index 637c4e035e..b883166159 100644 --- a/phpBB/language/en/captcha_qa.php +++ b/phpBB/language/en/captcha_qa.php @@ -61,4 +61,5 @@ $lang = array_merge($lang, array( 'QA_ERROR_MSG' => 'Please fill in all fields and enter at least one answer.', 'QA_LAST_QUESTION' => 'You cannot delete all questions while the plugin is active.', + 'QA_NO_QUESTIONS' => 'There are no questions yet.', )); diff --git a/phpBB/language/en/captcha_turnstile.php b/phpBB/language/en/captcha_turnstile.php new file mode 100644 index 0000000000..687ba4499d --- /dev/null +++ b/phpBB/language/en/captcha_turnstile.php @@ -0,0 +1,53 @@ + +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +/** +* DO NOT CHANGE +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +if (empty($lang) || !is_array($lang)) +{ + $lang = []; +} + +// DEVELOPERS PLEASE NOTE +// +// All language files should use UTF-8 as their encoding and the files must not contain a BOM. +// +// Placeholders can now contain order information, e.g. instead of +// 'Page %s of %s' you can (and should) write 'Page %1$s of %2$s', this allows +// translators to re-order the output of data while ensuring it remains correct +// +// You do not need this where single placeholders are used, e.g. 'Message %d' is fine +// equally where a string contains only two placeholders which are used to wrap text +// in a url you again do not need to specify an order e.g., 'Click %sHERE%s' is fine + +$lang = array_merge($lang, [ + 'CAPTCHA_TURNSTILE' => 'Turnstile', + 'CAPTCHA_TURNSTILE_INCORRECT' => 'The solution you provided was incorrect', + 'CAPTCHA_TURNSTILE_NOSCRIPT' => 'Please enable JavaScript in your browser to load the challenge.', + 'CAPTCHA_TURNSTILE_NOT_AVAILABLE' => 'In order to use Turnstile you must create a Cloudflare account.', + 'CAPTCHA_TURNSTILE_SECRET' => 'Secret key', + 'CAPTCHA_TURNSTILE_SECRET_EXPLAIN' => 'Your Turnstile secret key. The secret key can be retrieved from your Cloudflare dashboard.', + 'CAPTCHA_TURNSTILE_SITEKEY' => 'Sitekey', + 'CAPTCHA_TURNSTILE_SITEKEY_EXPLAIN' => 'Your Turnstile sitekey. The sitekey can be retrieved from your Cloudflare dashboard.', + 'CAPTCHA_TURNSTILE_THEME' => 'Widget theme', + 'CAPTCHA_TURNSTILE_THEME_EXPLAIN' => 'The theme of the CAPTCHA widget. By default, light will be used. Other possibilities are dark and auto, which respects the user’s preference.', + 'CAPTCHA_TURNSTILE_THEME_AUTO' => 'Auto', + 'CAPTCHA_TURNSTILE_THEME_DARK' => 'Dark', + 'CAPTCHA_TURNSTILE_THEME_LIGHT' => 'Light', +]); diff --git a/phpBB/language/en/cli.php b/phpBB/language/en/cli.php index 7eb71d9e6d..700bf9799d 100644 --- a/phpBB/language/en/cli.php +++ b/phpBB/language/en/cli.php @@ -75,6 +75,7 @@ $lang = array_merge($lang, array( 'CLI_DESCRIPTION_REPARSER_REPARSE' => 'Reparses stored text with the current text_formatter services.', 'CLI_DESCRIPTION_REPARSER_REPARSE_ARG_1' => 'Type of text to reparse. Leave blank to reparse everything.', 'CLI_DESCRIPTION_REPARSER_REPARSE_OPT_DRY_RUN' => 'Do not save any changes; just print what would happen', + 'CLI_DESCRIPTION_REPARSER_REPARSE_OPT_FORCE_BBCODE' => 'Re-parse all BBCodes without exception. Note that any previously disabled BBCodes will be reprocessed, enabled, and fully rendered.', 'CLI_DESCRIPTION_REPARSER_REPARSE_OPT_RANGE_MIN' => 'Lowest record ID to process', 'CLI_DESCRIPTION_REPARSER_REPARSE_OPT_RANGE_MAX' => 'Highest record ID to process', 'CLI_DESCRIPTION_REPARSER_REPARSE_OPT_RANGE_SIZE' => 'Approximate number of records to process at a time', @@ -112,6 +113,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.', @@ -171,10 +174,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.', diff --git a/phpBB/language/en/common.php b/phpBB/language/en/common.php index 5933cc8f5c..d528ef9b2b 100644 --- a/phpBB/language/en/common.php +++ b/phpBB/language/en/common.php @@ -512,7 +512,9 @@ $lang = array_merge($lang, array( ), 'NOTIFY_ADMIN' => 'Please notify the board administrator or webmaster.', 'NOTIFY_ADMIN_EMAIL' => 'Please notify the board administrator or webmaster: %1$s', - 'NOTIFY_WEB_PUSH_ENABLE' => 'Enable Web Push notifications', + 'NOTIFY_WEB_PUSH_DENIED' => 'You have denied notifications from this site. To subscribe, please allow notifications in your browser settings.', + 'NOTIFY_WEB_PUSH_DISABLED' => 'Web Push not supported', + 'NOTIFY_WEB_PUSH_ENABLE' => 'Enable web push notifications', 'NOTIFY_WEB_PUSH_SUBSCRIBE' => 'Subscribe', 'NOTIFY_WEB_PUSH_SUBSCRIBED'=> 'Subscribed', 'NO_ACCESS_ATTACHMENT' => 'You are not allowed to access this file.', diff --git a/phpBB/language/en/composer.json b/phpBB/language/en/composer.json index 7402e5efa5..cd6bcdb581 100644 --- a/phpBB/language/en/composer.json +++ b/phpBB/language/en/composer.json @@ -26,6 +26,7 @@ "direction": "ltr", "user-lang": "en-gb", "plural-rule": 1, - "recaptcha-lang": "en-GB" + "recaptcha-lang": "en-GB", + "turnstile-lang": "en" } } diff --git a/phpBB/language/en/help/faq.php b/phpBB/language/en/help/faq.php index 175f9eb164..666c0ad0b7 100644 --- a/phpBB/language/en/help/faq.php +++ b/phpBB/language/en/help/faq.php @@ -41,6 +41,7 @@ $lang = array_merge($lang, array( 'HELP_FAQ_BLOCK_POSTING' => 'Posting Issues', 'HELP_FAQ_BLOCK_SEARCH' => 'Searching the Forums', 'HELP_FAQ_BLOCK_USERSETTINGS' => 'User Preferences and settings', + 'HELP_FAQ_BLOCK_WEBPUSH' => 'Web Push Notifications for Browsers', 'HELP_FAQ_BOOKMARKS_DIFFERENCE_ANSWER' => 'In phpBB 3.0, bookmarking topics worked much like bookmarking in a web browser. You were not alerted when there was an update. As of phpBB 3.1, bookmarking is more like subscribing to a topic. You can be notified when a bookmarked topic is updated. Subscribing, however, will notify you when there is an update to a topic or forum on the board. Notification options for bookmarks and subscriptions can be configured in the User Control Panel, under “Board preferences”.', 'HELP_FAQ_BOOKMARKS_DIFFERENCE_QUESTION' => 'What is the difference between bookmarking and subscribing?', @@ -158,7 +159,7 @@ $lang = array_merge($lang, array( 'HELP_FAQ_SEARCH_BLANK_QUESTION' => 'Why does my search return a blank page!?', 'HELP_FAQ_SEARCH_FORUM_ANSWER' => 'Enter a search term in the search box located on the index, forum or topic pages. Advanced search can be accessed by clicking the “Advance Search” link which is available on all pages on the forum. How to access the search may depend on the style used.', 'HELP_FAQ_SEARCH_FORUM_QUESTION' => 'How can I search a forum or forums?', - 'HELP_FAQ_SEARCH_MEMBERS_ANSWER' => 'Visit to the “Members” page and click the “Find a member” link.', + 'HELP_FAQ_SEARCH_MEMBERS_ANSWER' => 'Visit the memberlist and click the “Find a member” link.', 'HELP_FAQ_SEARCH_MEMBERS_QUESTION' => 'How do I search for members?', 'HELP_FAQ_SEARCH_NO_RESULT_ANSWER' => 'Your search was probably too vague and included many common terms which are not indexed by phpBB. Be more specific and use the options available within Advanced search.', 'HELP_FAQ_SEARCH_NO_RESULT_QUESTION' => 'Why does my search return no results?', @@ -183,4 +184,15 @@ $lang = array_merge($lang, array( 'HELP_FAQ_USERSETTINGS_SERVERTIME_QUESTION' => 'I changed the timezone and the time is still wrong!', 'HELP_FAQ_USERSETTINGS_TIMEZONE_ANSWER' => 'It is possible the time displayed is from a timezone different from the one you are in. If this is the case, visit your User Control Panel and change your timezone to match your particular area, e.g. London, Paris, New York, Sydney, etc. Please note that changing the timezone, like most settings, can only be done by registered users. If you are not registered, this is a good time to do so.', 'HELP_FAQ_USERSETTINGS_TIMEZONE_QUESTION' => 'The times are not correct!', + + 'HELP_FAQ_WEBPUSH_GENERAL_ANSWER' => 'Make sure this forum is allowed to send notifications in your browser settings. Also, verify that your device’s system settings permit notifications from your web browser or app. Some browsers deliver notifications even when closed, whilst others only do so when the browser is open. View this table for browser support information. Finally, if you’re using an ad blocker, review its settings to make sure it’s not configured to block push notifications.', + 'HELP_FAQ_WEBPUSH_GENERAL_QUESTION' => 'What if I’m still having trouble receiving notifications?', + 'HELP_FAQ_WEBPUSH_HOW_ANSWER' => 'Navigate to “Notification options” in your UCP (User Control Panel) and click “Subscribe.” Your browser may ask for permission to send notifications — be sure to allow it. If you’re still not receiving notifications, check your device’s system settings to ensure notifications are enabled for your browser. For mobile devices such as iPhone or iPad, you may need to add the forum site to your Home Screen for push notifications to work, effectively turning it into a standalone web app. Follow your mobile device’s instructions to enable push notifications for iPhone/iPad or Android.', + 'HELP_FAQ_WEBPUSH_HOW_QUESTION' => 'How can I receive forum notification alerts on my computer or mobile device?', + 'HELP_FAQ_WEBPUSH_SESSION_ANSWER' => 'Yes, you will continue to receive notifications even if you’re logged out.', + 'HELP_FAQ_WEBPUSH_SESSION_QUESTION' => 'Will I receive notifications if I am logged out?', + 'HELP_FAQ_WEBPUSH_SUBBING_ANSWER' => 'If the “Subscribe” button is visible but cannot be clicked, your browser or device likely doesn’t support push notifications. Try using a different browser or device that supports this feature.', + 'HELP_FAQ_WEBPUSH_SUBBING_QUESTION' => 'Why is the “Subscribe” button disabled?', + 'HELP_FAQ_WEBPUSH_WHAT_ANSWER' => 'Web push notifications enhance phpBB’s notification system by allowing real-time notifications to be sent directly to your desktop or mobile device, even if you’re not actively browsing the forum. These notifications function like app alerts, providing instant updates for private messages, post interactions, moderation actions, and more.', + 'HELP_FAQ_WEBPUSH_WHAT_QUESTION' => 'What are web push notifications?', )); diff --git a/phpBB/language/en/viewtopic.php b/phpBB/language/en/viewtopic.php index e5c9be0517..9334a633d4 100644 --- a/phpBB/language/en/viewtopic.php +++ b/phpBB/language/en/viewtopic.php @@ -112,6 +112,7 @@ $lang = array_merge($lang, array( 'VIEW_INFO' => 'Post details', 'VIEW_NEXT_TOPIC' => 'Next topic', 'VIEW_PREVIOUS_TOPIC' => 'Previous topic', + 'VIEW_QUOTED_POST' => 'View quoted post', 'VIEW_RESULTS' => 'View results', 'VIEW_TOPIC_POSTS' => array( 1 => '%d post', diff --git a/phpBB/memberlist.php b/phpBB/memberlist.php index ea7fd03afe..28b1adbdee 100644 --- a/phpBB/memberlist.php +++ b/phpBB/memberlist.php @@ -815,11 +815,26 @@ switch ($mode) * Modify user's template vars before we display the profile * * @event core.memberlist_modify_view_profile_template_vars - * @var array template_ary Array with user's template vars + * @var array template_ary Array with user's template vars + * @var int user_id The user ID + * @var bool user_notes_enabled Is the mcp user notes module enabled? + * @var bool warn_user_enabled Is the mcp warnings module enabled? + * @var bool friends_enabled Is the ucp friends module enabled? + * @var bool foes_enabled Is the ucp foes module enabled? + * @var bool friend Is the user friend? + * @var bool foe Is the user foe? * @since 3.2.6-RC1 + * @changed 3.3.15-RC1 Added vars user_id, user_notes_enabled, warn_user_enabled, friend, friends_enabled, foe, foes_enabled */ $vars = array( 'template_ary', + 'user_id', + 'user_notes_enabled', + 'warn_user_enabled', + 'friend', + 'friends_enabled', + 'foe', + 'foes_enabled', ); extract($phpbb_dispatcher->trigger_event('core.memberlist_modify_view_profile_template_vars', compact($vars))); @@ -1724,7 +1739,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_last_active']; + $row['last_visit'] = $row['user_last_active'] ?: $row['session_time']; $id_cache[$row['user_id']] = $row; } diff --git a/phpBB/phpbb/.htaccess b/phpBB/phpbb/.htaccess new file mode 100644 index 0000000000..92e78ba1a7 --- /dev/null +++ b/phpBB/phpbb/.htaccess @@ -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. + + + Order Allow,Deny + Deny from All + + = 2.4> + Require all denied + + + + + Order Allow,Deny + Deny from All + + + Require all denied + + diff --git a/phpBB/phpbb/auth/auth.php b/phpBB/phpbb/auth/auth.php index 2ca2d374bd..7777796736 100644 --- a/phpBB/phpbb/auth/auth.php +++ b/phpBB/phpbb/auth/auth.php @@ -772,7 +772,7 @@ class auth $sql_group = ($group_id !== false) ? ((!is_array($group_id)) ? 'group_id = ' . (int) $group_id : $db->sql_in_set('group_id', array_map('intval', $group_id))) : ''; $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? 'AND a.forum_id = ' . (int) $forum_id : 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id))) : ''; - $sql_is_local = $forum_id !== false ? 'AND ao.is_local <> 0' : ''; + $sql_is_local = !empty($forum_id) ? 'AND ao.is_local <> 0' : ''; $sql_opts = ''; $hold_ary = $sql_ary = array(); diff --git a/phpBB/phpbb/auth/provider/db.php b/phpBB/phpbb/auth/provider/db.php index ae9d968076..5f8ebd6ac3 100644 --- a/phpBB/phpbb/auth/provider/db.php +++ b/phpBB/phpbb/auth/provider/db.php @@ -176,9 +176,8 @@ class db extends base // Every auth module is able to define what to do by itself... if ($show_captcha) { - $captcha->init(CONFIRM_LOGIN); - $vc_response = $captcha->validate($row); - if ($vc_response) + $captcha->init(\phpbb\captcha\plugins\confirm_type::LOGIN); + if ($captcha->validate() !== true) { return array( 'status' => LOGIN_ERROR_ATTEMPTS, diff --git a/phpBB/phpbb/avatar/driver/gravatar.php b/phpBB/phpbb/avatar/driver/gravatar.php index ea77497390..d72e6df604 100644 --- a/phpBB/phpbb/avatar/driver/gravatar.php +++ b/phpBB/phpbb/avatar/driver/gravatar.php @@ -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']) { diff --git a/phpBB/phpbb/cache/driver/file.php b/phpBB/phpbb/cache/driver/file.php index 0a4f0ae31e..ef62cd3d25 100644 --- a/phpBB/phpbb/cache/driver/file.php +++ b/phpBB/phpbb/cache/driver/file.php @@ -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); + } + /** * {@inheritDoc} */ @@ -368,14 +389,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; } @@ -388,9 +402,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 diff --git a/phpBB/phpbb/cache/driver/redis.php b/phpBB/phpbb/cache/driver/redis.php index c0b47dae46..6f103bf0f0 100644 --- a/phpBB/phpbb/cache/driver/redis.php +++ b/phpBB/phpbb/cache/driver/redis.php @@ -123,15 +123,17 @@ class redis extends \phpbb\cache\driver\memory } /** - * {@inheritDoc} - */ + * 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 + * + * {@inheritDoc} + */ protected function _write(string $var, $data, int $ttl = 2592000): bool { - 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]); } /** diff --git a/phpBB/phpbb/captcha/factory.php b/phpBB/phpbb/captcha/factory.php index 2e75ce8667..fc974569bb 100644 --- a/phpBB/phpbb/captcha/factory.php +++ b/phpBB/phpbb/captcha/factory.php @@ -13,6 +13,9 @@ namespace phpbb\captcha; +use phpbb\captcha\plugins\legacy_wrapper; +use phpbb\captcha\plugins\plugin_interface; + class factory { /** @@ -41,11 +44,17 @@ class factory * Return a new instance of a given plugin * * @param $name - * @return object|null + * @return plugin_interface */ - public function get_instance($name) + public function get_instance($name): plugin_interface { - return $this->container->get($name); + $captcha = $this->container->get($name); + if ($captcha instanceof plugin_interface) + { + return $captcha; + } + + return new legacy_wrapper($captcha); } /** @@ -56,7 +65,7 @@ class factory function garbage_collect($name) { $captcha = $this->get_instance($name); - $captcha->garbage_collect(0); + $captcha->garbage_collect(); } /** diff --git a/phpBB/phpbb/captcha/plugins/base.php b/phpBB/phpbb/captcha/plugins/base.php new file mode 100644 index 0000000000..a30e679731 --- /dev/null +++ b/phpBB/phpbb/captcha/plugins/base.php @@ -0,0 +1,256 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\captcha\plugins; + +use phpbb\config\config; +use phpbb\db\driver\driver_interface; +use phpbb\language\language; +use phpbb\request\request_interface; +use phpbb\user; + +abstract class base implements plugin_interface +{ + /** @var config */ + protected config $config; + + /** @var driver_interface */ + protected driver_interface $db; + + /** @var language */ + protected language $language; + + /** @var request_interface */ + protected request_interface $request; + + /** @var user */ + protected user $user; + + /** @var int Attempts at solving the CAPTCHA */ + protected int $attempts = 0; + + /** @var string Stored random CAPTCHA code */ + protected string $code = ''; + + /** @var bool Resolved state of captcha */ + protected bool $solved = false; + + /** @var string User supplied confirm code */ + protected string $confirm_code = ''; + + /** @var string Confirm id hash */ + protected string $confirm_id = ''; + + /** @var confirm_type Confirmation type */ + protected confirm_type $type = confirm_type::UNDEFINED; + + /** @var string Last error message */ + protected string $last_error = ''; + + /** + * Constructor for abstract captcha base class + * + * @param config $config + * @param driver_interface $db + * @param language $language + * @param request_interface $request + * @param user $user + */ + public function __construct(config $config, driver_interface $db, language $language, request_interface $request, user $user) + { + $this->config = $config; + $this->db = $db; + $this->language = $language; + $this->request = $request; + $this->user = $user; + } + + /** + * {@inheritDoc} + */ + public function init(confirm_type $type): void + { + $this->confirm_id = $this->request->variable('confirm_id', ''); + $this->confirm_code = $this->request->variable('confirm_code', ''); + $this->type = $type; + + if (empty($this->confirm_id) || !$this->load_confirm_data()) + { + // we have no confirm ID, better get ready to display something + $this->generate_confirm_data(); + } + } + + /** + * {@inheritDoc} + */ + public function validate(): bool + { + if ($this->confirm_id && hash_equals($this->code, $this->confirm_code)) + { + $this->solved = true; + return true; + } + + $this->increment_attempts(); + $this->last_error = $this->language->lang('CONFIRM_CODE_WRONG'); + return false; + } + + /** + * {@inheritDoc} + */ + public function reset(): void + { + $sql = 'DELETE FROM ' . CONFIRM_TABLE . " + WHERE session_id = '" . $this->db->sql_escape($this->user->session_id) . "' + AND confirm_type = " . $this->type->value; + $this->db->sql_query($sql); + + $this->generate_confirm_data(); + } + + /** + * {@inheritDoc} + */ + public function get_attempt_count(): int + { + return $this->attempts; + } + + /** + * Look up attempts from confirm table + */ + protected function load_confirm_data(): bool + { + $sql = 'SELECT code, attempts + FROM ' . CONFIRM_TABLE . " + WHERE confirm_id = '" . $this->db->sql_escape($this->confirm_id) . "' + AND session_id = '" . $this->db->sql_escape($this->user->session_id) . "' + AND confirm_type = " . $this->type->value; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + if ($row) + { + $this->attempts = $row['attempts']; + $this->code = $row['code']; + + return true; + } + + return false; + } + + /** + * Generate confirm data for tracking attempts + * + * @return void + */ + protected function generate_confirm_data(): void + { + $this->code = gen_rand_string_friendly(CAPTCHA_MAX_CHARS); + $this->confirm_id = md5(unique_id()); + $this->attempts = 0; + + $sql = 'INSERT INTO ' . CONFIRM_TABLE . ' ' . $this->db->sql_build_array('INSERT', array( + 'confirm_id' => $this->confirm_id, + 'session_id' => (string) $this->user->session_id, + 'confirm_type' => $this->type->value, + 'code' => $this->code, + )); + $this->db->sql_query($sql); + } + + /** + * Increment number of attempts for confirm ID and session + * + * @return void + */ + protected function increment_attempts(): void + { + $sql = 'UPDATE ' . CONFIRM_TABLE . " + SET attempts = attempts + 1 + WHERE confirm_id = '{$this->db->sql_escape($this->confirm_id)}' + AND session_id = '{$this->db->sql_escape($this->user->session_id)}'"; + $this->db->sql_query($sql); + + $this->attempts++; + } + + /** + * {@inheritDoc} + */ + public function get_hidden_fields(): array + { + return [ + 'confirm_id' => $this->confirm_id, + 'confirm_code' => $this->solved === true ? $this->confirm_code : '', + ]; + } + + /** + * {@inheritDoc} + */ + public function is_solved(): bool + { + return $this->solved; + } + + /** + * {@inheritDoc} + */ + public function get_error(): string + { + return $this->last_error; + } + + /** + * @inheritDoc + */ + public function garbage_collect(confirm_type $confirm_type = confirm_type::UNDEFINED): void + { + $sql = 'SELECT DISTINCT c.session_id + FROM ' . CONFIRM_TABLE . ' c + LEFT JOIN ' . SESSIONS_TABLE . ' s ON (c.session_id = s.session_id) + WHERE s.session_id IS NULL' . + ((empty($confirm_type)) ? '' : ' AND c.confirm_type = ' . $confirm_type->value); + $result = $this->db->sql_query($sql); + + if ($row = $this->db->sql_fetchrow($result)) + { + $sql_in = []; + do + { + $sql_in[] = (string) $row['session_id']; + } + while ($row = $this->db->sql_fetchrow($result)); + + if (count($sql_in)) + { + $sql = 'DELETE FROM ' . CONFIRM_TABLE . ' + WHERE ' . $this->db->sql_in_set('session_id', $sql_in); + $this->db->sql_query($sql); + } + } + $this->db->sql_freeresult($result); + } + + /** + * {@inheritDoc} + */ + public function acp_page(mixed $id, mixed $module): void + { + } +} diff --git a/phpBB/phpbb/captcha/plugins/captcha_abstract.php b/phpBB/phpbb/captcha/plugins/captcha_abstract.php index 012e28c987..c6978a1bf1 100644 --- a/phpBB/phpbb/captcha/plugins/captcha_abstract.php +++ b/phpBB/phpbb/captcha/plugins/captcha_abstract.php @@ -179,16 +179,6 @@ abstract class captcha_abstract $db->sql_freeresult($result); } - function uninstall() - { - $this->garbage_collect(0); - } - - function install() - { - return; - } - function validate() { global $user; diff --git a/phpBB/phpbb/captcha/plugins/confirm_type.php b/phpBB/phpbb/captcha/plugins/confirm_type.php new file mode 100644 index 0000000000..e3e11edf77 --- /dev/null +++ b/phpBB/phpbb/captcha/plugins/confirm_type.php @@ -0,0 +1,25 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\captcha\plugins; + +/** + * Confirmation types for CAPTCHA plugins + */ +enum confirm_type: int { + case UNDEFINED = 0; + case REGISTRATION = 1; + case LOGIN = 2; + case POST = 3; + case REPORT = 4; +} diff --git a/phpBB/phpbb/captcha/plugins/incomplete.php b/phpBB/phpbb/captcha/plugins/incomplete.php index ec3376c0a5..07998a7125 100644 --- a/phpBB/phpbb/captcha/plugins/incomplete.php +++ b/phpBB/phpbb/captcha/plugins/incomplete.php @@ -14,25 +14,34 @@ namespace phpbb\captcha\plugins; use phpbb\config\config; -use phpbb\exception\runtime_exception; +use phpbb\db\driver\driver_interface; +use phpbb\language\language; +use phpbb\request\request_interface; use phpbb\template\template; +use phpbb\user; -class incomplete extends captcha_abstract +class incomplete extends base { /** * Constructor for incomplete captcha * * @param config $config + * @param driver_interface $db + * @param language $language + * @param request_interface $request * @param template $template + * @param user $user * @param string $phpbb_root_path * @param string $phpEx */ - public function __construct(protected config $config, protected template $template, - protected string $phpbb_root_path, protected string $phpEx) - {} + public function __construct(config $config, driver_interface $db, language $language, request_interface $request, + protected template $template, user $user, protected string $phpbb_root_path, protected string $phpEx) + { + parent::__construct($config, $db, $language, $request, $user); + } /** - * @return bool True if captcha is available, false if not + * {@inheritDoc} */ public function is_available(): bool { @@ -40,70 +49,45 @@ class incomplete extends captcha_abstract } /** - * Dummy implementation, not supported by this captcha - * - * @throws runtime_exception - * @return void + * {@inheritDoc} */ - public function get_generator_class(): void + public function has_config(): bool { - throw new runtime_exception('NO_GENERATOR_CLASS'); + return false; } /** - * Get CAPTCHA name language variable - * - * @return string Language variable + * {@inheritDoc} */ - public static function get_name(): string + public function get_name(): string { return 'CAPTCHA_INCOMPLETE'; } /** - * Init CAPTCHA - * - * @param int $type CAPTCHA type - * @return void + * {@inheritDoc} */ - public function init($type) + public function set_name(string $name): void { } /** - * Execute demo - * - * @return void + * {@inheritDoc} */ - public function execute_demo() + public function init(confirm_type $type): void { } /** - * Execute CAPTCHA - * - * @return void + * {@inheritDoc} */ - public function execute() - { - } - - /** - * Get template data for demo - * - * @param int|string $id ACP module ID - * - * @return string Demo template file name - */ - public function get_demo_template($id): string + public function get_demo_template(): string { return ''; } /** - * Get template data for CAPTCHA - * - * @return string CAPTCHA template file name + * {@inheritDoc} */ public function get_template(): string { @@ -118,9 +102,7 @@ class incomplete extends captcha_abstract } /** - * Validate CAPTCHA - * - * @return false Incomplete CAPTCHA will never validate + * {@inheritDoc} */ public function validate(): bool { @@ -128,12 +110,26 @@ class incomplete extends captcha_abstract } /** - * Check whether CAPTCHA is solved - * - * @return false Incomplete CAPTCHA will never be solved + * {@inheritDoc} + */ + public function get_error(): string + { + return ''; + } + + /** + * {@inheritDoc} */ public function is_solved(): bool { return false; } + + /** + * {@inheritDoc} + */ + public function get_attempt_count(): int + { + return 0; + } } diff --git a/phpBB/phpbb/captcha/plugins/legacy_wrapper.php b/phpBB/phpbb/captcha/plugins/legacy_wrapper.php new file mode 100644 index 0000000000..aaabddb48b --- /dev/null +++ b/phpBB/phpbb/captcha/plugins/legacy_wrapper.php @@ -0,0 +1,221 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\captcha\plugins; + +class legacy_wrapper implements plugin_interface +{ + /** @var object Legacy CAPTCHA instance, should implement functionality as required in phpBB 3.3 */ + private $legacy_captcha; + + /** @var string Last error */ + private string $last_error; + + /** + * Constructor for legacy CAPTCHA wrapper + * + * @param object $legacy_captcha + */ + public function __construct(object $legacy_captcha) + { + $this->legacy_captcha = $legacy_captcha; + } + + /** + * {@inheritDoc} + */ + public function is_available(): bool + { + if (method_exists($this->legacy_captcha, 'is_available')) + { + return $this->legacy_captcha->is_available(); + } + + return false; + } + + /** + * {@inheritDoc} + */ + public function has_config(): bool + { + if (method_exists($this->legacy_captcha, 'has_config')) + { + return $this->legacy_captcha->has_config(); + } + + return false; + } + + /** + * {@inheritDoc} + */ + public function get_name(): string + { + if (method_exists($this->legacy_captcha, 'get_name')) + { + return $this->legacy_captcha->get_name(); + } + + return ''; + } + + /** + * {@inheritDoc} + */ + public function set_name(string $name): void + { + if (method_exists($this->legacy_captcha, 'set_name')) + { + $this->legacy_captcha->set_name($name); + } + } + + /** + * {@inheritDoc} + */ + public function init(confirm_type $type): void + { + if (method_exists($this->legacy_captcha, 'init')) + { + $this->legacy_captcha->init($type->value); + } + } + + /** + * {@inheritDoc} + */ + public function get_hidden_fields(): array + { + if (method_exists($this->legacy_captcha, 'get_hidden_fields')) + { + return $this->legacy_captcha->get_hidden_fields(); + } + + return []; + } + + /** + * {@inheritDoc} + */ + public function validate(): bool + { + if (method_exists($this->legacy_captcha, 'validate')) + { + $error = $this->legacy_captcha->validate(); + if ($error) + { + $this->last_error = $error; + return false; + } + + return true; + } + + return false; + } + + /** + * {@inheritDoc} + */ + public function get_error(): string + { + return $this->last_error; + } + + /** + * {@inheritDoc} + */ + public function is_solved(): bool + { + if (method_exists($this->legacy_captcha, 'is_solved')) + { + return $this->legacy_captcha->is_solved(); + } + + return false; + } + + /** + * {@inheritDoc} + */ + public function reset(): void + { + if (method_exists($this->legacy_captcha, 'reset')) + { + $this->legacy_captcha->reset(); + } + } + + /** + * {@inheritDoc} + */ + public function get_attempt_count(): int + { + if (method_exists($this->legacy_captcha, 'get_attempt_count')) + { + return $this->legacy_captcha->get_attempt_count(); + } + + // Ensure this is deemed as too many attempts + return PHP_INT_MAX; + } + + /** + * {@inheritDoc} + */ + public function get_template(): string + { + if (method_exists($this->legacy_captcha, 'get_template')) + { + return $this->legacy_captcha->get_template(); + } + + return ''; + } + + /** + * {@inheritDoc} + */ + public function get_demo_template(): string + { + if (method_exists($this->legacy_captcha, 'get_demo_template')) + { + return $this->legacy_captcha->get_demo_template(0); + } + + return ''; + } + + /** + * {@inheritDoc} + */ + public function garbage_collect(confirm_type $confirm_type = confirm_type::UNDEFINED): void + { + if (method_exists($this->legacy_captcha, 'garbage_collect')) + { + $this->legacy_captcha->garbage_collect($confirm_type->value); + } + } + + /** + * {@inheritDoc} + */ + public function acp_page(mixed $id, mixed $module): void + { + if (method_exists($this->legacy_captcha, 'acp_page')) + { + $this->legacy_captcha->acp_page($id, $module); + } + } +} diff --git a/phpBB/phpbb/captcha/plugins/plugin_interface.php b/phpBB/phpbb/captcha/plugins/plugin_interface.php new file mode 100644 index 0000000000..41483e45a5 --- /dev/null +++ b/phpBB/phpbb/captcha/plugins/plugin_interface.php @@ -0,0 +1,126 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\captcha\plugins; + +interface plugin_interface +{ + /** + * Check if the plugin is available + * + * @return bool True if the plugin is available, false if not + */ + public function is_available(): bool; + + /** + * Check if the plugin has a configuration + * + * @return bool True if the plugin has a configuration, false if not + */ + public function has_config(): bool; + + /** + * Get the name of the plugin, should be language variable + * + * @return string + */ + public function get_name(): string; + + /** + * Set the service name of the plugin + * + * @param string $name + */ + public function set_name(string $name): void; + + /** + * Display the captcha for the specified type + * + * @param confirm_type $type Type of captcha, should be one of the CONFIRMATION_* constants + * @return void + */ + public function init(confirm_type $type): void; + + /** + * Get hidden form fields for this captcha plugin + * + * @return array Hidden form fields + */ + public function get_hidden_fields(): array; + + /** + * Validate the captcha with the given request data + * + * @return bool True if request data was valid captcha reply, false if not + */ + public function validate(): bool; + + /** + * Get error string from captcha + * + * @return string Error string, empty string if there is no error + */ + public function get_error(): string; + + /** + * Return whether captcha was solved + * + * @return bool True if captcha was solved, false if not + */ + public function is_solved(): bool; + + /** + * Reset captcha state, e.g. after checking if it's valid + * + * @return void + */ + public function reset(): void; + + /** + * Get attempt count for this captcha and user + * + * @return int Number of attempts + */ + public function get_attempt_count(): int; + + /** + * Get template filename for captcha + * + * @return string Template file name + */ + public function get_template(): string; + + /** + * Get template filename for demo + * + * @return string Demo template file name + */ + public function get_demo_template(): string; + + /** + * Garbage collect captcha plugin + * + * @param confirm_type $confirm_type Confirm type to garbage collect, defaults to all (0) + * @return void + */ + public function garbage_collect(confirm_type $confirm_type = confirm_type::UNDEFINED): void; + + /** + * Display acp page + * + * @param mixed $id ACP module id + * @param mixed $module ACP module name + * @return void + */ + public function acp_page(mixed $id, mixed $module): void; +} diff --git a/phpBB/phpbb/captcha/plugins/qa.php b/phpBB/phpbb/captcha/plugins/qa.php index b9bfac33f1..6e09aaaf13 100644 --- a/phpBB/phpbb/captcha/plugins/qa.php +++ b/phpBB/phpbb/captcha/plugins/qa.php @@ -40,7 +40,7 @@ class qa protected $service_name; /** @var int Question ID */ - protected $question = -1; + private $question = -1; /** * Constructor @@ -323,71 +323,6 @@ class qa $db->sql_freeresult($result); } - /** - * API function - we don't drop the tables here, as that would cause the loss of all entered questions. - */ - function uninstall() - { - $this->garbage_collect(0); - } - - /** - * API function - set up shop - */ - function install() - { - global $phpbb_container; - - $db_tool = $phpbb_container->get('dbal.tools'); - $schemas = array( - $this->table_captcha_questions => array ( - 'COLUMNS' => array( - 'question_id' => array('UINT', null, 'auto_increment'), - 'strict' => array('BOOL', 0), - 'lang_id' => array('UINT', 0), - 'lang_iso' => array('VCHAR:30', ''), - 'question_text' => array('TEXT_UNI', ''), - ), - 'PRIMARY_KEY' => 'question_id', - 'KEYS' => array( - 'lang' => array('INDEX', 'lang_iso'), - ), - ), - $this->table_captcha_answers => array ( - 'COLUMNS' => array( - 'question_id' => array('UINT', 0), - 'answer_text' => array('STEXT_UNI', ''), - ), - 'KEYS' => array( - 'qid' => array('INDEX', 'question_id'), - ), - ), - $this->table_qa_confirm => array ( - 'COLUMNS' => array( - 'session_id' => array('CHAR:32', ''), - 'confirm_id' => array('CHAR:32', ''), - 'lang_iso' => array('VCHAR:30', ''), - 'question_id' => array('UINT', 0), - 'attempts' => array('UINT', 0), - 'confirm_type' => array('USINT', 0), - ), - 'KEYS' => array( - 'session_id' => array('INDEX', 'session_id'), - 'lookup' => array('INDEX', array('confirm_id', 'session_id', 'lang_iso')), - ), - 'PRIMARY_KEY' => 'confirm_id', - ), - ); - - foreach ($schemas as $table => $schema) - { - if (!$db_tool->sql_table_exists($table)) - { - $db_tool->sql_create_table($table, $schema); - } - } - } - /** * API function - see what has to be done to validate */ @@ -647,11 +582,6 @@ class qa $user->add_lang('acp/board'); $user->add_lang('captcha_qa'); - if (!self::is_installed()) - { - $this->install(); - } - $module->tpl_name = 'captcha_qa_acp'; $module->page_title = 'ACP_VC_SETTINGS'; $form_key = 'acp_captcha'; diff --git a/phpBB/phpbb/captcha/plugins/recaptcha.php b/phpBB/phpbb/captcha/plugins/recaptcha.php index ef30baaa9b..1c080ba67b 100644 --- a/phpBB/phpbb/captcha/plugins/recaptcha.php +++ b/phpBB/phpbb/captcha/plugins/recaptcha.php @@ -179,16 +179,6 @@ class recaptcha extends captcha_abstract return $hidden_fields; } - function uninstall() - { - $this->garbage_collect(0); - } - - function install() - { - return; - } - function validate() { if (!parent::validate()) diff --git a/phpBB/phpbb/captcha/plugins/recaptcha_v3.php b/phpBB/phpbb/captcha/plugins/recaptcha_v3.php index 67035ab1c6..e8399a5aef 100644 --- a/phpBB/phpbb/captcha/plugins/recaptcha_v3.php +++ b/phpBB/phpbb/captcha/plugins/recaptcha_v3.php @@ -361,6 +361,7 @@ class recaptcha_v3 extends captcha_abstract if ($result->isSuccess()) { $this->solved = true; + $this->confirm_code = $this->code; return false; } diff --git a/phpBB/phpbb/captcha/plugins/turnstile.php b/phpBB/phpbb/captcha/plugins/turnstile.php new file mode 100644 index 0000000000..9a235edc3b --- /dev/null +++ b/phpBB/phpbb/captcha/plugins/turnstile.php @@ -0,0 +1,287 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\captcha\plugins; + +use GuzzleHttp\Client; +use GuzzleHttp\Exception\GuzzleException; +use phpbb\config\config; +use phpbb\db\driver\driver_interface; +use phpbb\language\language; +use phpbb\log\log_interface; +use phpbb\request\request_interface; +use phpbb\template\template; +use phpbb\user; + +class turnstile extends base +{ + /** @var string URL to cloudflare turnstile API javascript */ + private const SCRIPT_URL = 'https://challenges.cloudflare.com/turnstile/v0/api.js'; + + /** @var string API endpoint for turnstile verification */ + private const VERIFY_ENDPOINT = 'https://challenges.cloudflare.com/turnstile/v0/siteverify'; + + /** @var Client */ + protected Client $client; + + /** @var language */ + protected language $language; + + /** @var log_interface */ + protected log_interface $log; + + /** @var template */ + protected template $template; + + /** @var string Service name */ + protected string $service_name = ''; + + /** @var array|string[] Supported themes for Turnstile CAPTCHA */ + protected static array $supported_themes = [ + 'light', + 'dark', + 'auto' + ]; + + /** + * Constructor for turnstile captcha plugin + * + * @param config $config + * @param driver_interface $db + * @param language $language + * @param log_interface $log + * @param request_interface $request + * @param template $template + * @param user $user + */ + public function __construct(config $config, driver_interface $db, language $language, log_interface $log, request_interface $request, template $template, user $user) + { + parent::__construct($config, $db, $language, $request, $user); + + $this->language = $language; + $this->log = $log; + $this->template = $template; + } + + /** + * {@inheritDoc} + */ + public function is_available(): bool + { + $this->init($this->type); + + return !empty($this->config->offsetGet('captcha_turnstile_sitekey')) + && !empty($this->config->offsetGet('captcha_turnstile_secret')); + } + + /** + * {@inheritDoc} + */ + public function has_config(): bool + { + return true; + } + + /** + * {@inheritDoc} + */ + public function get_name(): string + { + return 'CAPTCHA_TURNSTILE'; + } + + /** + * {@inheritDoc} + */ + public function set_name(string $name): void + { + $this->service_name = $name; + } + + /** + * {@inheritDoc} + */ + public function init(confirm_type $type): void + { + parent::init($type); + + $this->language->add_lang('captcha_turnstile'); + } + + /** + * {@inheritDoc} + */ + public function validate(): bool + { + if (parent::validate()) + { + return true; + } + + $turnstile_response = $this->request->variable('cf-turnstile-response', ''); + if (!$turnstile_response) + { + // Return without checking against server without a turnstile response + return false; + } + + // Retrieve form data for verification + $form_data = [ + 'secret' => $this->config['captcha_turnstile_secret'], + 'response' => $turnstile_response, + 'remoteip' => $this->user->ip, + ]; + + // Create guzzle client + $client = $this->get_client(); + + // Check captcha with turnstile API + try + { + $response = $client->request('POST', self::VERIFY_ENDPOINT, [ + 'form_params' => $form_data, + ]); + } + catch (GuzzleException) + { + // Something went wrong during the request to Cloudflare, assume captcha was bad + $this->solved = false; + return false; + } + + // Decode the JSON response + $result = json_decode($response->getBody(), true); + + // Check if the response indicates success + if (isset($result['success']) && $result['success'] === true) + { + $this->solved = true; + $this->confirm_code = $this->code; + return true; + } + else + { + $this->last_error = $this->language->lang('CAPTCHA_TURNSTILE_INCORRECT'); + return false; + } + } + + /** + * Get Guzzle client + * + * @return Client + */ + protected function get_client(): Client + { + if (!isset($this->client)) + { + $this->client = new Client(); + } + + return $this->client; + } + + /** + * {@inheritDoc} + */ + public function get_template(): string + { + if ($this->is_solved()) + { + return ''; + } + + $this->template->assign_vars([ + 'S_TURNSTILE_AVAILABLE' => $this->is_available(), + 'TURNSTILE_SITEKEY' => $this->config->offsetGet('captcha_turnstile_sitekey'), + 'TURNSTILE_THEME' => $this->config->offsetGet('captcha_turnstile_theme'), + 'U_TURNSTILE_SCRIPT' => self::SCRIPT_URL, + 'CONFIRM_TYPE_REGISTRATION' => $this->type->value, + ]); + + return 'captcha_turnstile.html'; + } + + /** + * {@inheritDoc} + */ + public function get_demo_template(): string + { + $this->template->assign_vars([ + 'TURNSTILE_THEME' => $this->config->offsetGet('captcha_turnstile_theme'), + 'U_TURNSTILE_SCRIPT' => self::SCRIPT_URL, + ]); + + return 'captcha_turnstile_acp_demo.html'; + } + + /** + * {@inheritDoc} + */ + public function acp_page(mixed $id, mixed $module): void + { + $captcha_vars = [ + 'captcha_turnstile_sitekey' => 'CAPTCHA_TURNSTILE_SITEKEY', + 'captcha_turnstile_secret' => 'CAPTCHA_TURNSTILE_SECRET', + ]; + + $module->tpl_name = 'captcha_turnstile_acp'; + $module->page_title = 'ACP_VC_SETTINGS'; + $form_key = 'acp_captcha'; + add_form_key($form_key); + + $submit = $this->request->is_set_post('submit'); + + if ($submit && check_form_key($form_key)) + { + $captcha_vars = array_keys($captcha_vars); + foreach ($captcha_vars as $captcha_var) + { + $value = $this->request->variable($captcha_var, ''); + if ($value) + { + $this->config->set($captcha_var, $value); + } + } + + $captcha_theme = $this->request->variable('captcha_turnstile_theme', self::$supported_themes[0]); + if (in_array($captcha_theme, self::$supported_themes)) + { + $this->config->set('captcha_turnstile_theme', $captcha_theme); + } + + $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_VISUAL'); + trigger_error($this->language->lang('CONFIG_UPDATED') . adm_back_link($module->u_action)); + } + else if ($submit) + { + trigger_error($this->language->lang('FORM_INVALID') . adm_back_link($module->u_action)); + } + else + { + foreach ($captcha_vars as $captcha_var => $template_var) + { + $var = $this->request->is_set($captcha_var) ? $this->request->variable($captcha_var, '') : $this->config->offsetGet($captcha_var); + $this->template->assign_var($template_var, $var); + } + + $this->template->assign_vars(array( + 'CAPTCHA_PREVIEW' => $this->get_demo_template(), + 'CAPTCHA_NAME' => $this->service_name, + 'CAPTCHA_TURNSTILE_THEME' => $this->config->offsetGet('captcha_turnstile_theme'), + 'CAPTCHA_TURNSTILE_THEMES' => self::$supported_themes, + 'U_ACTION' => $module->u_action, + )); + } + } +} diff --git a/phpBB/phpbb/console/command/fixup/update_hashes.php b/phpBB/phpbb/console/command/fixup/update_hashes.php index 05bef48c92..b1ffa2159b 100644 --- a/phpBB/phpbb/console/command/fixup/update_hashes.php +++ b/phpBB/phpbb/console/command/fixup/update_hashes.php @@ -101,6 +101,14 @@ class update_hashes extends \phpbb\console\command\command while ($row = $this->db->sql_fetchrow($result)) { $old_hash = preg_replace('/^\$CP\$/', '', $row['user_password']); + + // 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 . " diff --git a/phpBB/phpbb/console/command/reparser/reparse.php b/phpBB/phpbb/console/command/reparser/reparse.php index 1e66a22a73..6a197bf2d9 100644 --- a/phpBB/phpbb/console/command/reparser/reparse.php +++ b/phpBB/phpbb/console/command/reparser/reparse.php @@ -93,6 +93,12 @@ class reparse extends \phpbb\console\command\command InputOption::VALUE_NONE, $this->user->lang('CLI_DESCRIPTION_REPARSER_REPARSE_OPT_DRY_RUN') ) + ->addOption( + 'force-bbcode-reparsing', + null, + InputOption::VALUE_NONE, + $this->user->lang('CLI_DESCRIPTION_REPARSER_REPARSE_OPT_FORCE_BBCODE') + ) ->addOption( 'resume', null, @@ -223,13 +229,15 @@ class reparse extends \phpbb\console\command\command // Start from $max and decrement $current by $size until we reach $min $current = $max; + + $force_bbcode_reparsing = (bool) $this->get_option('force-bbcode-reparsing'); while ($current >= $min) { $start = max($min, $current + 1 - $size); $end = max($min, $current); $progress->setMessage($this->user->lang('CLI_REPARSER_REPARSE_REPARSING', $reparser->get_name(), $start, $end)); - $reparser->reparse_range($start, $end); + $reparser->reparse_range($start, $end, $force_bbcode_reparsing); $current = $start - 1; $progress->setProgress($max + 1 - $start); diff --git a/phpBB/phpbb/console/command/user/delete_id.php b/phpBB/phpbb/console/command/user/delete_id.php new file mode 100644 index 0000000000..07d98e7616 --- /dev/null +++ b/phpBB/phpbb/console/command/user/delete_id.php @@ -0,0 +1,232 @@ + + * @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\Helper\QuestionHelper; +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'); + if (!$helper instanceof QuestionHelper) + { + return; + } + + $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); + } + } +} diff --git a/phpBB/phpbb/cron/task/core/update_hashes.php b/phpBB/phpbb/cron/task/core/update_hashes.php index 61ed0d0501..78221bb35f 100644 --- a/phpBB/phpbb/cron/task/core/update_hashes.php +++ b/phpBB/phpbb/cron/task/core/update_hashes.php @@ -107,6 +107,14 @@ class update_hashes extends \phpbb\cron\task\base while ($row = $this->db->sql_fetchrow($result)) { $old_hash = preg_replace('/^\$CP\$/', '', $row['user_password']); + + // 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 diff --git a/phpBB/phpbb/db/driver/mysqli.php b/phpBB/phpbb/db/driver/mysqli.php index 485bb4dd74..ad5fa09343 100644 --- a/phpBB/phpbb/db/driver/mysqli.php +++ b/phpBB/phpbb/db/driver/mysqli.php @@ -154,7 +154,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; case 'commit': $result = @mysqli_commit($this->db_connect_id); diff --git a/phpBB/phpbb/db/migration/data/v33x/v3313.php b/phpBB/phpbb/db/migration/data/v33x/v3313.php new file mode 100644 index 0000000000..a133213c81 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v33x/v3313.php @@ -0,0 +1,36 @@ + + * @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 v3313 extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return version_compare($this->config['version'], '3.3.13', '>='); + } + + public static function depends_on() + { + return [ + '\phpbb\db\migration\data\v33x\v3313rc1', + ]; + } + + public function update_data() + { + return [ + ['config.update', ['version', '3.3.13']], + ]; + } +} diff --git a/phpBB/phpbb/db/migration/data/v33x/v3313rc1.php b/phpBB/phpbb/db/migration/data/v33x/v3313rc1.php new file mode 100644 index 0000000000..4481a53821 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v33x/v3313rc1.php @@ -0,0 +1,36 @@ + + * @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']], + ]; + } +} diff --git a/phpBB/phpbb/db/migration/data/v33x/v3314.php b/phpBB/phpbb/db/migration/data/v33x/v3314.php new file mode 100644 index 0000000000..ce333dbf5a --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v33x/v3314.php @@ -0,0 +1,36 @@ + + * @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 v3314 extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return version_compare($this->config['version'], '3.3.14', '>='); + } + + public static function depends_on() + { + return [ + '\phpbb\db\migration\data\v33x\v3314rc1', + ]; + } + + public function update_data() + { + return [ + ['config.update', ['version', '3.3.14']], + ]; + } +} diff --git a/phpBB/phpbb/db/migration/data/v33x/v3314rc1.php b/phpBB/phpbb/db/migration/data/v33x/v3314rc1.php new file mode 100644 index 0000000000..1632a65dda --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v33x/v3314rc1.php @@ -0,0 +1,36 @@ + + * @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 v3314rc1 extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return version_compare($this->config['version'], '3.3.14-RC1', '>='); + } + + public static function depends_on() + { + return [ + '\phpbb\db\migration\data\v33x\v3313', + ]; + } + + public function update_data() + { + return [ + ['config.update', ['version', '3.3.14-RC1']], + ]; + } +} diff --git a/phpBB/phpbb/db/migration/data/v400/add_webpush_token.php b/phpBB/phpbb/db/migration/data/v400/add_webpush_token.php new file mode 100644 index 0000000000..f87dadf9e7 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v400/add_webpush_token.php @@ -0,0 +1,53 @@ + + * @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\v400; + +use phpbb\db\migration\migration; + +class add_webpush_token extends migration +{ + public static function depends_on(): array + { + return [ + '\phpbb\db\migration\data\v400\add_webpush', + ]; + } + + public function effectively_installed(): bool + { + return $this->db_tools->sql_column_exists($this->table_prefix . 'notification_push', 'push_token'); + } + + public function update_schema(): array + { + return [ + 'add_columns' => [ + $this->table_prefix . 'notification_push' => [ + 'push_token' => ['VCHAR', ''], + ], + ], + ]; + } + + public function revert_schema(): array + { + return [ + 'drop_columns' => [ + $this->table_prefix . 'notification_push' => [ + 'push_token', + ], + ], + ]; + } +} diff --git a/phpBB/phpbb/db/migration/data/v400/hidpi_icons.php b/phpBB/phpbb/db/migration/data/v400/hidpi_icons.php new file mode 100644 index 0000000000..6e91b15ca5 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v400/hidpi_icons.php @@ -0,0 +1,75 @@ + + * @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\v400; + +use phpbb\db\migration\migration; + +class hidpi_icons extends migration +{ + private array $default_icons = [ + 'misc/fire', + 'misc/heart', + 'misc/radioactive', + 'misc/star', + 'misc/thinking', + 'smile/alert', + 'smile/info', + 'smile/mrgreen', + 'smile/question', + 'smile/redface', + ]; + + public static function depends_on(): array + { + return [ + '\phpbb\db\migration\data\v400\dev' + ]; + } + + public function update_data(): array + { + return [ + ['custom', [[$this, 'gif_to_svg_icons']]], + ]; + } + + public function revert_data(): array + { + return [ + ['custom', [[$this, 'svg_to_gif_icons']]], + ]; + } + + public function gif_to_svg_icons(): void + { + foreach ($this->default_icons as $smiley) + { + $sql = 'UPDATE ' . $this->tables['icons'] . " + SET icons_url = '" . $this->db->sql_escape($smiley) . ".svg' + WHERE icons_url = '" . $this->db->sql_escape($smiley) . ".gif'"; + $this->db->sql_query($sql); + } + } + + public function svg_to_gif_icons(): void + { + foreach ($this->default_icons as $smiley) + { + $sql = 'UPDATE ' . $this->tables['icons'] . " + SET icons_url = '" . $this->db->sql_escape($smiley) . ".gif' + WHERE icons_url = '" . $this->db->sql_escape($smiley) . ".svg'"; + $this->db->sql_query($sql); + } + } +} diff --git a/phpBB/phpbb/db/migration/data/v400/hidpi_smilies.php b/phpBB/phpbb/db/migration/data/v400/hidpi_smilies.php new file mode 100644 index 0000000000..f51810f095 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v400/hidpi_smilies.php @@ -0,0 +1,89 @@ + + * @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\v400; + +use phpbb\db\migration\migration; + +class hidpi_smilies extends migration +{ + private array $default_smilies = [ + 'icon_arrow', + 'icon_cool', + 'icon_cry', + 'icon_e_biggrin', + 'icon_e_confused', + 'icon_e_geek', + 'icon_e_sad', + 'icon_e_smile', + 'icon_e_surprised', + 'icon_e_ugeek', + 'icon_e_wink', + 'icon_eek', + 'icon_evil', + 'icon_exclaim', + 'icon_idea', + 'icon_lol', + 'icon_mad', + 'icon_mrgreen', + 'icon_neutral', + 'icon_question', + 'icon_razz', + 'icon_redface', + 'icon_rolleyes', + 'icon_twisted', + ]; + + public static function depends_on(): array + { + return [ + '\phpbb\db\migration\data\v400\dev' + ]; + } + + public function update_data(): array + { + return [ + ['custom', [[$this, 'gif_to_svg_smilies']]], + ]; + } + + public function revert_data(): array + { + return [ + ['custom', [[$this, 'svg_to_gif_smilies']]], + ]; + } + + public function gif_to_svg_smilies(): void + { + foreach ($this->default_smilies as $smiley) + { + $sql = 'UPDATE ' . $this->tables['smilies'] . " + SET smiley_url = '" . $this->db->sql_escape($smiley) . ".svg' + WHERE smiley_url = '" . $this->db->sql_escape($smiley) . ".gif'"; + $this->db->sql_query($sql); + } + } + + public function svg_to_gif_smilies(): void + { + foreach ($this->default_smilies as $smiley) + { + $sql = 'UPDATE ' . $this->tables['smilies'] . " + SET smiley_url = '" . $this->db->sql_escape($smiley) . ".gif' + WHERE smiley_url = '" . $this->db->sql_escape($smiley) . ".svg'"; + $this->db->sql_query($sql); + } + } +} diff --git a/phpBB/phpbb/db/migration/data/v400/qa_captcha.php b/phpBB/phpbb/db/migration/data/v400/qa_captcha.php new file mode 100644 index 0000000000..69cca2dc15 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v400/qa_captcha.php @@ -0,0 +1,89 @@ + + * @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\v400; + +use phpbb\db\migration\migration; + +class qa_captcha extends migration +{ + public function effectively_installed(): bool + { + return $this->db_tools->sql_table_exists($this->tables['captcha_qa_questions']) + && $this->db_tools->sql_table_exists($this->tables['captcha_qa_answers']) + && $this->db_tools->sql_table_exists($this->tables['captcha_qa_confirm']); + } + + public static function depends_on(): array + { + return [ + '\phpbb\db\migration\data\v400\dev', + ]; + } + + public function update_schema(): array + { + return [ + 'add_tables' => [ + $this->tables['captcha_qa_questions'] => [ + 'COLUMNS' => [ + 'question_id' => ['UINT', null, 'auto_increment'], + 'strict' => ['BOOL', 0], + 'lang_id' => ['UINT', 0], + 'lang_iso' => ['VCHAR:30', ''], + 'question_text' => ['TEXT_UNI', ''], + ], + 'PRIMARY_KEY' => 'question_id', + 'KEYS' => [ + 'lang' => ['INDEX', 'lang_iso'], + ], + ], + $this->tables['captcha_qa_answers'] => [ + 'COLUMNS' => [ + 'question_id' => ['UINT', 0], + 'answer_text' => ['STEXT_UNI', ''], + ], + 'KEYS' => [ + 'qid' => ['INDEX', 'question_id'], + ], + ], + $this->tables['captcha_qa_confirm'] => [ + 'COLUMNS' => [ + 'session_id' => ['CHAR:32', ''], + 'confirm_id' => ['CHAR:32', ''], + 'lang_iso' => ['VCHAR:30', ''], + 'question_id' => ['UINT', 0], + 'attempts' => ['UINT', 0], + 'confirm_type' => ['USINT', 0], + ], + 'KEYS' => [ + 'session_id' => ['INDEX', 'session_id'], + 'lookup' => ['INDEX', ['confirm_id', 'session_id', 'lang_iso']], + ], + 'PRIMARY_KEY' => 'confirm_id', + ], + ], + ]; + } + + public function revert_schema(): array + { + return [ + 'drop_tables' => [ + $this->tables['captcha_qa_questions'], + $this->tables['captcha_qa_answers'], + $this->tables['captcha_qa_confirm'] + ], + ]; + } +} diff --git a/phpBB/phpbb/db/migration/data/v400/remove_img_link.php b/phpBB/phpbb/db/migration/data/v400/remove_img_link.php new file mode 100644 index 0000000000..172bea5e1d --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v400/remove_img_link.php @@ -0,0 +1,41 @@ + + * @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\v400; + +use phpbb\db\migration\migration; + +class remove_img_link extends migration +{ + public function effectively_installed() + { + return !$this->config->offsetExists('img_link_width') + && !$this->config->offsetExists('img_link_height'); + } + + public static function depends_on() + { + return [ + '\phpbb\db\migration\data\v400\dev' + ]; + } + + public function update_data() + { + return [ + ['config.remove', ['img_link_width']], + ['config.remove', ['img_link_height']], + ]; + } +} diff --git a/phpBB/phpbb/db/migration/data/v400/remove_max_img_size.php b/phpBB/phpbb/db/migration/data/v400/remove_max_img_size.php new file mode 100644 index 0000000000..8a5338a454 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v400/remove_max_img_size.php @@ -0,0 +1,34 @@ + + * @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\v400; + +use phpbb\db\migration\migration; + +class remove_max_img_size extends migration +{ + public static function depends_on(): array + { + return [ + '\phpbb\db\migration\data\v400\dev', + ]; + } + + public function update_data(): array + { + return [ + ['config.remove', ['max_sig_img_width']], + ['config.remove', ['max_sig_img_height']], + ]; + } +} diff --git a/phpBB/phpbb/db/migration/data/v400/turnstile_captcha.php b/phpBB/phpbb/db/migration/data/v400/turnstile_captcha.php new file mode 100644 index 0000000000..77e921c090 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v400/turnstile_captcha.php @@ -0,0 +1,51 @@ + + * @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\v400; + +use phpbb\db\migration\migration; + +class turnstile_captcha extends migration +{ + public function effectively_installed(): bool + { + return $this->config->offsetExists('captcha_turnstile_sitekey') + && $this->config->offsetExists('captcha_turnstile_secret') + && $this->config->offsetExists('captcha_turnstile_theme'); + } + + public static function depends_on(): array + { + return [ + '\phpbb\db\migration\data\v400\dev', + ]; + } + + public function update_data(): array + { + return [ + ['config.add', ['captcha_turnstile_sitekey', '']], + ['config.add', ['captcha_turnstile_secret', '']], + ['config.add', ['captcha_turnstile_theme', 'light']], + ]; + } + + public function revert_data(): array + { + return [ + ['config.remove', ['captcha_turnstile_sitekey']], + ['config.remove', ['captcha_turnstile_secret']], + ['config.remove', ['captcha_turnstile_theme']], + ]; + } +} diff --git a/phpBB/phpbb/file_downloader.php b/phpBB/phpbb/file_downloader.php index 873bccc9e8..1527cfe9d4 100644 --- a/phpBB/phpbb/file_downloader.php +++ b/phpBB/phpbb/file_downloader.php @@ -13,91 +13,116 @@ namespace phpbb; +use GuzzleHttp\Client; +use GuzzleHttp\Exception\RequestException; +use phpbb\exception\runtime_exception; + class file_downloader { + const OK = 200; + const NOT_FOUND = 404; + const REQUEST_TIMEOUT = 408; + /** @var string Error string */ - protected $error_string = ''; + protected string $error_string = ''; /** @var int Error number */ - protected $error_number = 0; + protected int $error_number = 0; + + /** + * Create new guzzle client + * + * @param string $host + * @param int $port + * @param int $timeout + * + * @return Client + */ + protected function create_client(string $host, int $port = 443, int $timeout = 6): Client + { + // Only set URL scheme if not specified in URL + $url_parts = parse_url($host); + if (!isset($url_parts['scheme'])) + { + $host = (($port === 443) ? 'https://' : 'http://') . $host; + } + + // Initialize Guzzle client + return new Client([ + 'base_uri' => $host, + 'timeout' => $timeout, + ]); + } /** * Retrieve contents from remotely stored file * - * @param string $host File host - * @param string $directory Directory file is in - * @param string $filename Filename of file to retrieve - * @param int $port Port to connect to; default: 80 - * @param int $timeout Connection timeout in seconds; default: 6 + * @param string $host File host + * @param string $directory Directory file is in + * @param string $filename Filename of file to retrieve + * @param int $port Port to connect to; default: 443 + * @param int $timeout Connection timeout in seconds; default: 6 * * @return false|string File data as string if file can be read and there is no - * timeout, false if there were errors or the connection timed out + * timeout, false if there were errors or the connection timed out * - * @throws \phpbb\exception\runtime_exception If data can't be retrieved and no error - * message is returned + * @throws runtime_exception If data can't be retrieved and no error + * message is returned */ - public function get($host, $directory, $filename, $port = 80, $timeout = 6) + public function get(string $host, string $directory, string $filename, int $port = 443, int $timeout = 6): bool|string { + // Initialize Guzzle client + $client = $this->create_client($host, $port, $timeout); + // Set default values for error variables $this->error_number = 0; $this->error_string = ''; - if (function_exists('fsockopen') && - $socket = @fsockopen(($port == 443 ? 'ssl://' : '') . $host, $port, $this->error_number, $this->error_string, $timeout) - ) + try { - @fputs($socket, "GET $directory/$filename HTTP/1.0\r\n"); - @fputs($socket, "HOST: $host\r\n"); - @fputs($socket, "Connection: close\r\n\r\n"); + $response = $client->request('GET', "$directory/$filename"); - $timer_stop = time() + $timeout; - stream_set_timeout($socket, $timeout); - - $file_info = ''; - $get_info = false; - - while (!@feof($socket)) + // Check if the response status code is 200 (OK) + if ($response->getStatusCode() == self::OK) { - if ($get_info) - { - $file_info .= @fread($socket, 1024); - } - else - { - $line = @fgets($socket, 1024); - if ($line == "\r\n") - { - $get_info = true; - } - else if (stripos($line, '404 not found') !== false) - { - throw new \phpbb\exception\runtime_exception('FILE_NOT_FOUND', array($filename)); - } - } - - $stream_meta_data = stream_get_meta_data($socket); - - if ($stream_meta_data['timed_out'] || time() >= $timer_stop) - { - throw new \phpbb\exception\runtime_exception('FSOCK_TIMEOUT'); - } - } - @fclose($socket); - } - else - { - if ($this->error_string) - { - $this->error_string = utf8_convert_message($this->error_string); - return false; + return $response->getBody()->getContents(); } else { - throw new \phpbb\exception\runtime_exception('FSOCK_DISABLED'); + $this->error_number = $response->getStatusCode(); + throw new runtime_exception('FILE_NOT_FOUND', [$filename]); } } + catch (RequestException $exception) + { + if ($exception->hasResponse()) + { + $this->error_number = $exception->getResponse()->getStatusCode(); - return $file_info; + if ($this->error_number == self::NOT_FOUND) + { + throw new runtime_exception('FILE_NOT_FOUND', [$filename]); + } + } + else + { + $this->error_number = self::REQUEST_TIMEOUT; + throw new runtime_exception('FSOCK_TIMEOUT'); + } + + $this->error_string = utf8_convert_message($exception->getMessage()); + return false; + } + catch (runtime_exception $exception) + { + // Rethrow runtime_exceptions, only handle unknown cases below + throw $exception; + } + catch (\Throwable $exception) + { + $this->error_string = utf8_convert_message($exception->getMessage()); + throw new runtime_exception('FSOCK_DISABLED'); + } } /** @@ -105,7 +130,7 @@ class file_downloader * * @return string Error string */ - public function get_error_string() + public function get_error_string(): string { return $this->error_string; } @@ -115,7 +140,7 @@ class file_downloader * * @return int Error number */ - public function get_error_number() + public function get_error_number(): int { return $this->error_number; } diff --git a/phpBB/phpbb/files/filespec.php b/phpBB/phpbb/files/filespec.php index 6e4c224e39..48e9284f69 100644 --- a/phpBB/phpbb/files/filespec.php +++ b/phpBB/phpbb/files/filespec.php @@ -398,7 +398,7 @@ class filespec * @param bool $overwrite If set to true, an already existing file will be overwritten * @param bool $skip_image_check If set to true, the check for the file to be a valid image is skipped * @param string|bool $chmod Permission mask for chmodding the file after a successful move. - * The mode entered here reflects the mode defined by {@link phpbb_chmod()} + * The mode entered here reflects the mode defined by {@link \phpbb\filesystem\filesystem::phpbb_chmod()} * * @return bool True if file was moved, false if not * @access public diff --git a/phpBB/phpbb/filesystem.php b/phpBB/phpbb/filesystem.php deleted file mode 100644 index 6ac9459331..0000000000 --- a/phpBB/phpbb/filesystem.php +++ /dev/null @@ -1,21 +0,0 @@ - -* @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; - -/** - * @deprecated 3.2.0-dev (To be removed 4.0.0) use \phpbb\filesystem\filesystem instead - */ -class filesystem extends \phpbb\filesystem\filesystem -{ -} diff --git a/phpBB/phpbb/help/controller/faq.php b/phpBB/phpbb/help/controller/faq.php index 0f63be5b56..62a82a3efe 100644 --- a/phpBB/phpbb/help/controller/faq.php +++ b/phpBB/phpbb/help/controller/faq.php @@ -146,6 +146,17 @@ class faq extends controller 'HELP_FAQ_BOOKMARKS_REMOVE_QUESTION' => 'HELP_FAQ_BOOKMARKS_REMOVE_ANSWER', ) ); + $this->manager->add_block( + 'HELP_FAQ_BLOCK_WEBPUSH', + false, + array( + 'HELP_FAQ_WEBPUSH_WHAT_QUESTION' => 'HELP_FAQ_WEBPUSH_WHAT_ANSWER', + 'HELP_FAQ_WEBPUSH_HOW_QUESTION' => 'HELP_FAQ_WEBPUSH_HOW_ANSWER', + 'HELP_FAQ_WEBPUSH_SESSION_QUESTION' => 'HELP_FAQ_WEBPUSH_SESSION_ANSWER', + 'HELP_FAQ_WEBPUSH_SUBBING_QUESTION' => 'HELP_FAQ_WEBPUSH_SUBBING_ANSWER', + 'HELP_FAQ_WEBPUSH_GENERAL_QUESTION' => 'HELP_FAQ_WEBPUSH_GENERAL_ANSWER', + ) + ); $this->manager->add_block( 'HELP_FAQ_BLOCK_ATTACHMENTS', false, diff --git a/phpBB/phpbb/install/module/install_database/task/add_config_settings.php b/phpBB/phpbb/install/module/install_database/task/add_config_settings.php index bd3f0852e6..5b9a9da536 100644 --- a/phpBB/phpbb/install/module/install_database/task/add_config_settings.php +++ b/phpBB/phpbb/install/module/install_database/task/add_config_settings.php @@ -132,6 +132,7 @@ class add_config_settings extends database_task $updates = [ 'board_startdate' => (string) $current_time, + 'board_timezone' => $this->install_config->get('admin_timezone'), 'default_lang' => $this->install_config->get('default_lang'), 'server_name' => $this->install_config->get('server_name'), diff --git a/phpBB/phpbb/install/module/install_database/task/update_user_and_post_data.php b/phpBB/phpbb/install/module/install_database/task/update_user_and_post_data.php index ba178135b9..7cc5fd4f49 100644 --- a/phpBB/phpbb/install/module/install_database/task/update_user_and_post_data.php +++ b/phpBB/phpbb/install/module/install_database/task/update_user_and_post_data.php @@ -114,7 +114,8 @@ class update_user_and_post_data extends database_task . ' user_lang = :lang,' . ' user_email = :email,' . ' user_dateformat = :dateformat,' - . ' username_clean = :clean_username' + . ' username_clean = :clean_username,' + . ' user_timezone = :timezone' . ' WHERE username = \'Admin\''; $this->create_and_execute_prepared_stmt($sql, [ @@ -125,6 +126,7 @@ class update_user_and_post_data extends database_task 'email' => $this->install_config->get('board_email'), 'dateformat' => $this->language->lang('default_dateformat'), 'clean_username' => utf8_clean_string($this->install_config->get('admin_name')), + 'timezone' => $this->install_config->get('admin_timezone'), ]); $this->exec_sql('UPDATE ' . $this->user_table . ' SET user_regdate = ' . $current_time); diff --git a/phpBB/phpbb/install/module/install_finish/task/install_extensions.php b/phpBB/phpbb/install/module/install_finish/task/install_extensions.php index 019553053f..049694baba 100644 --- a/phpBB/phpbb/install/module/install_finish/task/install_extensions.php +++ b/phpBB/phpbb/install/module/install_finish/task/install_extensions.php @@ -157,7 +157,7 @@ class install_extensions extends database_task if (isset($extensions[$key]) && $extensions[$key]['ext_active']) { // Create log - $this->log->add('admin', ANONYMOUS, '', 'LOG_EXT_ENABLE', time(), array($key)); + $this->log->add('admin', ANONYMOUS, $this->user->ip, 'LOG_EXT_ENABLE', time(), array($key)); $this->iohandler->add_success_message(array('CLI_EXTENSION_ENABLE_SUCCESS', $key)); } else diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_admin_data.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_admin_data.php index 0560f2d46d..1175ab8626 100644 --- a/phpBB/phpbb/install/module/obtain_data/task/obtain_admin_data.php +++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_admin_data.php @@ -71,6 +71,7 @@ class obtain_admin_data extends \phpbb\install\task_base implements \phpbb\insta $admin_pass1 = $this->io_handler->get_input('admin_pass1', '', true); $admin_pass2 = $this->io_handler->get_input('admin_pass2', '', true); $board_email = $this->io_handler->get_input('board_email', '', true); + $admin_timezone = $this->io_handler->get_input('admin_timezone', 'UTC', true); $admin_data_valid = $this->check_admin_data($admin_name, $admin_pass1, $admin_pass2, $board_email); @@ -79,6 +80,7 @@ class obtain_admin_data extends \phpbb\install\task_base implements \phpbb\insta $this->install_config->set('admin_name', $admin_name); $this->install_config->set('admin_passwd', $admin_pass1); $this->install_config->set('board_email', $board_email); + $this->install_config->set('admin_timezone', $admin_timezone); } else { diff --git a/phpBB/phpbb/install/module/update_database/task/update_extensions.php b/phpBB/phpbb/install/module/update_database/task/update_extensions.php index e47d23d052..6ea3a517bf 100644 --- a/phpBB/phpbb/install/module/update_database/task/update_extensions.php +++ b/phpBB/phpbb/install/module/update_database/task/update_extensions.php @@ -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 diff --git a/phpBB/phpbb/language/language.php b/phpBB/phpbb/language/language.php index dee8b58486..1c51049de5 100644 --- a/phpBB/phpbb/language/language.php +++ b/phpBB/phpbb/language/language.php @@ -403,6 +403,7 @@ class language $this->lang['USER_LANG'] = $lang_values['user_lang'] ?? 'en-gb'; $this->lang['PLURAL_RULE'] = $lang_values['plural_rule'] ?? 1; $this->lang['RECAPTCHA_LANG'] = $lang_values['recaptcha_lang'] ?? 'en-GB'; + $this->lang['TURNSTILE_LANG'] = $lang_values['turnstile_lang'] ?? 'auto'; // default to auto mode } /** diff --git a/phpBB/phpbb/language/language_file_helper.php b/phpBB/phpbb/language/language_file_helper.php index 995c7b4712..83244d674f 100644 --- a/phpBB/phpbb/language/language_file_helper.php +++ b/phpBB/phpbb/language/language_file_helper.php @@ -110,16 +110,17 @@ class language_file_helper } return [ - 'iso' => $data['extra']['language-iso'], - 'name' => $data['extra']['english-name'], - 'local_name' => $data['extra']['local-name'], - 'author' => implode(', ', $authors), - 'version' => $data['version'], - 'phpbb_version' => $data['extra']['phpbb-version'], - 'direction' => $data['extra']['direction'], - 'user_lang' => $data['extra']['user-lang'], - 'plural_rule' => $data['extra']['plural-rule'], - 'recaptcha_lang'=> $data['extra']['recaptcha-lang'], + 'iso' => $data['extra']['language-iso'], + 'name' => $data['extra']['english-name'], + 'local_name' => $data['extra']['local-name'], + 'author' => implode(', ', $authors), + 'version' => $data['version'], + 'phpbb_version' => $data['extra']['phpbb-version'], + 'direction' => $data['extra']['direction'], + 'user_lang' => $data['extra']['user-lang'], + 'plural_rule' => $data['extra']['plural-rule'], + 'recaptcha_lang' => $data['extra']['recaptcha-lang'], + 'turnstile_lang' => $data['extra']['turnstile-lang'] ?? '', ]; } } diff --git a/phpBB/phpbb/manifest.php b/phpBB/phpbb/manifest.php new file mode 100644 index 0000000000..1a7d0148e5 --- /dev/null +++ b/phpBB/phpbb/manifest.php @@ -0,0 +1,95 @@ + + * @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; + +use phpbb\config\config; +use phpbb\event\dispatcher_interface; +use phpbb\exception\http_exception; +use phpbb\language\language; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Response; + +class manifest +{ + /** @var config */ + protected $config; + + /** @var language */ + protected $language; + + /** @var path_helper */ + protected $path_helper; + + /** @var dispatcher_interface */ + protected $phpbb_dispatcher; + + /** @var user */ + protected $user; + + /** + * Constructor for manifest controller + * + * @param config $config + * @param language $language + * @param path_helper $path_helper + * @param dispatcher_interface $phpbb_dispatcher + * @param user $user + */ + public function __construct(config $config, language $language, path_helper $path_helper, dispatcher_interface $phpbb_dispatcher, user $user) + { + $this->config = $config; + $this->path_helper = $path_helper; + $this->phpbb_dispatcher = $phpbb_dispatcher; + $this->language = $language; + $this->user = $user; + } + + /** + * Handle creation of a manifest json file for progressive web-app support + * + * @return JsonResponse + */ + public function handle(): JsonResponse + { + if ($this->user->data['is_bot']) + { + throw new http_exception(Response::HTTP_FORBIDDEN, 'NO_AUTH_OPERATION'); + } + + $board_path = $this->config['force_server_vars'] ? $this->config['script_path'] : $this->path_helper->get_web_root_path(); + + $manifest = [ + 'name' => $this->config['sitename'], + 'short_name' => $this->config['sitename_short'] ?: substr($this->config['sitename'], 0, 12), + 'display' => 'standalone', + 'orientation' => 'portrait', + 'dir' => $this->language->lang('DIRECTION'), + 'start_url' => $board_path, + 'scope' => $board_path, + ]; + + /** + * Event to modify manifest data before it is outputted + * + * @event core.modify_manifest + * @var array manifest Array of manifest members + * @var string board_path Path to the board root + * @since 4.0.0-a1 + */ + $vars = array('manifest', 'board_path'); + extract($this->phpbb_dispatcher->trigger_event('core.modify_manifest', compact($vars))); + + return new JsonResponse($manifest); + } +} diff --git a/phpBB/phpbb/notification/method/webpush.php b/phpBB/phpbb/notification/method/webpush.php index 4d2d18bdc6..25b22d54d8 100644 --- a/phpBB/phpbb/notification/method/webpush.php +++ b/phpBB/phpbb/notification/method/webpush.php @@ -28,7 +28,7 @@ use phpbb\user_loader; * This class handles sending push messages for notifications */ -class webpush extends messenger_base implements extended_method_interface +class webpush extends base implements extended_method_interface { /** @var config */ protected $config; @@ -39,9 +39,18 @@ class webpush extends messenger_base implements extended_method_interface /** @var log_interface */ protected $log; + /** @var user_loader */ + protected $user_loader; + /** @var user */ protected $user; + /** @var string */ + protected $phpbb_root_path; + + /** @var string */ + protected $php_ext; + /** @var string Notification Web Push table */ protected $notification_webpush_table; @@ -51,6 +60,9 @@ class webpush extends messenger_base implements extended_method_interface /** @var int Fallback size for padding if endpoint is mozilla, see https://github.com/web-push-libs/web-push-php/issues/108#issuecomment-2133477054 */ const MOZILLA_FALLBACK_PADDING = 2820; + /** @var array Map for storing push token between db insertion and sending of notifications */ + private array $push_token_map = []; + /** * Notification Method Web Push constructor * @@ -67,12 +79,13 @@ class webpush extends messenger_base implements extended_method_interface public function __construct(config $config, driver_interface $db, log_interface $log, user_loader $user_loader, user $user, string $phpbb_root_path, string $php_ext, string $notification_webpush_table, string $push_subscriptions_table) { - parent::__construct($user_loader, $phpbb_root_path, $php_ext); - $this->config = $config; $this->db = $db; $this->log = $log; + $this->user_loader = $user_loader; $this->user = $user; + $this->phpbb_root_path = $phpbb_root_path; + $this->php_ext = $php_ext; $this->notification_webpush_table = $notification_webpush_table; $this->push_subscriptions_table = $push_subscriptions_table; } @@ -90,8 +103,9 @@ class webpush extends messenger_base implements extended_method_interface */ public function is_available(type_interface $notification_type = null): bool { - return parent::is_available($notification_type) && $this->config['webpush_enable'] - && !empty($this->config['webpush_vapid_public']) && !empty($this->config['webpush_vapid_private']); + return $this->config['webpush_enable'] + && $this->config['webpush_vapid_public'] + && $this->config['webpush_vapid_private']; } /** @@ -137,17 +151,16 @@ class webpush extends messenger_base implements extended_method_interface { $data = $notification->get_insert_array(); $data += [ - 'push_data' => json_encode([ - 'heading' => $this->config['sitename'], - 'title' => strip_tags($notification->get_title()), - 'text' => strip_tags($notification->get_reference()), - 'url' => htmlspecialchars_decode($notification->get_url()), - 'avatar' => $notification->get_avatar(), - ]), + 'push_data' => json_encode(array_merge( + $data, + ['notification_type_name' => $notification->get_type()], + )), 'notification_time' => time(), + 'push_token' => hash('sha256', random_bytes(32)) ]; $data = self::clean_data($data); $insert_buffer->insert($data); + $this->push_token_map[$notification->notification_type_id][$notification->item_id] = $data['push_token']; } $insert_buffer->flush(); @@ -221,7 +234,9 @@ class webpush extends messenger_base implements extended_method_interface $data = [ 'item_id' => $notification->item_id, 'type_id' => $notification->notification_type_id, + 'user_id' => $notification->user_id, 'version' => $this->config['assets_version'], + 'token' => hash('sha256', $user['user_form_salt'] . $this->push_token_map[$notification->notification_type_id][$notification->item_id]), ]; $json_data = json_encode($data); @@ -337,12 +352,21 @@ class webpush extends messenger_base implements extended_method_interface 'item_parent_id' => null, 'user_id' => null, 'push_data' => null, + 'push_token' => null, 'notification_time' => null, ]; return array_intersect_key($data, $row); } + /** + * Get template data for the UCP + * + * @param helper $controller_helper + * @param form_helper $form_helper + * + * @return array + */ public function get_ucp_template_data(helper $controller_helper, form_helper $form_helper): array { $subscription_map = $this->get_user_subscription_map([$this->user->id()]); diff --git a/phpBB/phpbb/path_helper.php b/phpBB/phpbb/path_helper.php index aa898c7b12..6ed8e5be5a 100644 --- a/phpBB/phpbb/path_helper.php +++ b/phpBB/phpbb/path_helper.php @@ -220,13 +220,13 @@ class path_helper * * The referer must be specified as a parameter in the query. */ - if ($this->request->is_ajax() && $this->symfony_request->get('_referer')) + if ($this->request->is_ajax() && $this->request->header('Referer')) { // We need to escape $absolute_board_url because it can be partially concatenated to the result. $absolute_board_url = $this->request->escape($this->symfony_request->getSchemeAndHttpHost() . $this->symfony_request->getBasePath(), true); $referer_web_root_path = $this->get_web_root_path_from_ajax_referer( - $this->symfony_request->get('_referer'), + $this->request->header('Referer'), $absolute_board_url ); return $this->web_root_path = $referer_web_root_path; diff --git a/phpBB/phpbb/php/ini.php b/phpBB/phpbb/php/ini.php deleted file mode 100644 index 441e3ff7f6..0000000000 --- a/phpBB/phpbb/php/ini.php +++ /dev/null @@ -1,175 +0,0 @@ - -* @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\php; - -/** -* Wrapper class for ini_get function. -* -* Provides easier handling of the different interpretations of ini values. -* @deprecated 3.2.10 (To be removed 4.0.0) -*/ -class ini -{ - /** - * Simple wrapper for ini_get() - * See http://php.net/manual/en/function.ini-get.php - * - * @param string $varname The configuration option name. - * @return bool|string False if configuration option does not exist, - * the configuration option value (string) otherwise. - */ - public function get($varname) - { - return ini_get($varname); - } - - /** - * Gets the configuration option value as a trimmed string. - * - * @param string $varname The configuration option name. - * @return bool|string False if configuration option does not exist, - * the configuration option value (string) otherwise. - */ - public function get_string($varname) - { - $value = $this->get($varname); - - if ($value === false) - { - return false; - } - - return trim($value); - } - - /** - * Gets configuration option value as a boolean. - * Interprets the string value 'off' as false. - * - * @param string $varname The configuration option name. - * @return bool False if configuration option does not exist. - * False if configuration option is disabled. - * True otherwise. - */ - public function get_bool($varname) - { - $value = $this->get_string($varname); - - if (empty($value) || strtolower($value) == 'off') - { - return false; - } - - return true; - } - - /** - * Gets configuration option value as an integer. - * - * @param string $varname The configuration option name. - * @return bool|int False if configuration option does not exist, - * false if configuration option value is not numeric, - * the configuration option value (integer) otherwise. - */ - public function get_int($varname) - { - $value = $this->get_string($varname); - - if (!is_numeric($value)) - { - return false; - } - - return (int) $value; - } - - /** - * Gets configuration option value as a float. - * - * @param string $varname The configuration option name. - * @return bool|float False if configuration option does not exist, - * false if configuration option value is not numeric, - * the configuration option value (float) otherwise. - */ - public function get_float($varname) - { - $value = $this->get_string($varname); - - if (!is_numeric($value)) - { - return false; - } - - return (float) $value; - } - - /** - * Gets configuration option value in bytes. - * Converts strings like '128M' to bytes (integer or float). - * - * @param string $varname The configuration option name. - * @return bool|int|float False if configuration option does not exist, - * false if configuration option value is not well-formed, - * the configuration option value otherwise. - */ - public function get_bytes($varname) - { - $value = $this->get_string($varname); - - if ($value === false) - { - return false; - } - - if (is_numeric($value)) - { - // Already in bytes. - return phpbb_to_numeric($value); - } - else if (is_string($value)) - { - if (strlen($value) < 2) - { - // Single character. - return false; - } - else if (strlen($value) < 3 && $value[0] === '-') - { - // Two characters but the first one is a minus. - return false; - } - } - - $value_lower = strtolower($value); - $value_numeric = phpbb_to_numeric($value); - - switch ($value_lower[strlen($value_lower) - 1]) - { - case 'g': - $value_numeric *= 1024; - case 'm': - $value_numeric *= 1024; - case 'k': - $value_numeric *= 1024; - break; - - default: - // It's not already in bytes (and thus numeric) - // and does not carry a unit. - return false; - } - - return $value_numeric; - } -} diff --git a/phpBB/phpbb/plupload/plupload.php b/phpBB/phpbb/plupload/plupload.php index db5a1d6dd9..18fdfe588d 100644 --- a/phpBB/phpbb/plupload/plupload.php +++ b/phpBB/phpbb/plupload/plupload.php @@ -344,8 +344,9 @@ class plupload } $tmp_file = $this->temporary_filepath($upload['tmp_name']); + $filesystem = new \phpbb\filesystem\filesystem(); - if (!phpbb_is_writable($this->temporary_directory) || !move_uploaded_file($upload['tmp_name'], $tmp_file)) + if (!$filesystem->is_writable($this->temporary_directory) || !move_uploaded_file($upload['tmp_name'], $tmp_file)) { $this->emit_error(103, 'PLUPLOAD_ERR_MOVE_UPLOADED'); } diff --git a/phpBB/phpbb/report/controller/report.php b/phpBB/phpbb/report/controller/report.php index b8e2b04583..97dbdbd9bb 100644 --- a/phpBB/phpbb/report/controller/report.php +++ b/phpBB/phpbb/report/controller/report.php @@ -13,6 +13,8 @@ namespace phpbb\report\controller; +use phpbb\captcha\plugins\confirm_type; +use phpbb\captcha\plugins\plugin_interface; use phpbb\exception\http_exception; use phpbb\report\report_handler_interface; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -131,7 +133,7 @@ class report if ($this->config['enable_post_confirm'] && !$this->user->data['is_registered']) { $captcha = $this->captcha_factory->get_instance($this->config['captcha_plugin']); - $captcha->init(CONFIRM_REPORT); + $captcha->init(confirm_type::REPORT); } //Has the report been cancelled? @@ -140,7 +142,7 @@ class report return new RedirectResponse($redirect_url, 302); } - // Check CAPTCHA, if the form was submited + // Check CAPTCHA, if the form was submitted if (!empty($submit) && isset($captcha)) { $captcha_template_array = $this->check_captcha($captcha); @@ -298,18 +300,17 @@ class report /** * Check CAPTCHA * - * @param object $captcha A phpBB CAPTCHA object + * @param plugin_interface $captcha A phpBB CAPTCHA object * @return array template variables which ensures that CAPTCHA's work correctly */ - protected function check_captcha($captcha) + protected function check_captcha(plugin_interface $captcha) { $error = array(); $captcha_hidden_fields = ''; - $visual_confirmation_response = $captcha->validate(); - if ($visual_confirmation_response) + if ($captcha->validate() !== true) { - $error[] = $visual_confirmation_response; + $error[] = $captcha->get_error(); } if (count($error) === 0) diff --git a/phpBB/phpbb/request/request.php b/phpBB/phpbb/request/request.php index cf81dc42c6..a28b9df541 100644 --- a/phpBB/phpbb/request/request.php +++ b/phpBB/phpbb/request/request.php @@ -184,7 +184,7 @@ class request implements request_interface * @param int $super_global (\phpbb\request\request_interface::POST|GET|REQUEST|COOKIE) * Specifies which super global should be used * - * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the + * @return mixed The value of $_REQUEST[$var_name] run through {@link type_cast_helper_interface::set_var} to ensure that the type is the * the same as that of $default. If the variable is not set $default is returned. */ public function variable($var_name, $default, $multibyte = false, $super_global = request_interface::REQUEST) @@ -208,7 +208,7 @@ class request implements request_interface * @param int $super_global (\phpbb\request\request_interface::POST|GET|REQUEST|COOKIE) * Specifies which super global should be used * - * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the + * @return mixed The value of $_REQUEST[$var_name] run through {@link type_cast_helper_interface::set_var} to ensure that the type is the * the same as that of $default. If the variable is not set $default is returned. */ public function untrimmed_variable($var_name, $default, $multibyte = false, $super_global = request_interface::REQUEST) @@ -401,7 +401,7 @@ class request implements request_interface * Specifies which super global should be used * @param bool $trim Indicates whether trim() should be applied to string values. * - * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the + * @return mixed The value of $_REQUEST[$var_name] run through {@link type_cast_helper_interface::set_var} to ensure that the type is the * the same as that of $default. If the variable is not set $default is returned. */ protected function _variable($var_name, $default, $multibyte = false, $super_global = request_interface::REQUEST, $trim = true) diff --git a/phpBB/phpbb/request/request_interface.php b/phpBB/phpbb/request/request_interface.php index 9ebd4c25e3..add58736ea 100644 --- a/phpBB/phpbb/request/request_interface.php +++ b/phpBB/phpbb/request/request_interface.php @@ -59,7 +59,7 @@ interface request_interface * @param int $super_global (\phpbb\request\request_interface::POST|GET|REQUEST|COOKIE) * Specifies which super global shall be changed * - * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the + * @return mixed The value of $_REQUEST[$var_name] run through {@link type_cast_helper_interface::set_var} to ensure that the type is the * the same as that of $default. If the variable is not set $default is returned. */ public function variable($var_name, $default, $multibyte = false, $super_global = request_interface::REQUEST); @@ -81,7 +81,7 @@ interface request_interface * @param int $super_global (\phpbb\request\request_interface::POST|GET|REQUEST|COOKIE) * Specifies which super global shall be changed * - * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the + * @return mixed The value of $_REQUEST[$var_name] run through {@link type_cast_helper_interface::set_var} to ensure that the type is the * the same as that of $default. If the variable is not set $default is returned. */ public function raw_variable($var_name, $default, $super_global = request_interface::REQUEST); diff --git a/phpBB/phpbb/search/backend/base.php b/phpBB/phpbb/search/backend/base.php index e195e0f4c0..9663c15f65 100644 --- a/phpBB/phpbb/search/backend/base.php +++ b/phpBB/phpbb/search/backend/base.php @@ -112,17 +112,10 @@ abstract class base implements search_backend_interface } } - // change the start to the actual end of the current request if the sort direction differs - // from the direction in the cache and reverse the ids later + // If the sort direction differs from the direction in the cache, then reverse the ids array if ($reverse_ids) { - $start = $result_count - $start - $per_page; - - // the user requested a page past the last index - if ($start < 0) - { - return self::SEARCH_RESULT_NOT_IN_CACHE; - } + $stored_ids = array_reverse($stored_ids); } for ($i = $start, $n = $start + $per_page; ($i < $n) && ($i < $result_count); $i++) @@ -138,11 +131,6 @@ abstract class base implements search_backend_interface } unset($stored_ids); - if ($reverse_ids) - { - $id_ary = array_reverse($id_ary); - } - if (!$complete) { return self::SEARCH_RESULT_INCOMPLETE; diff --git a/phpBB/phpbb/search/backend/fulltext_native.php b/phpBB/phpbb/search/backend/fulltext_native.php index ca71ae8bae..ffdcbff3db 100644 --- a/phpBB/phpbb/search/backend/fulltext_native.php +++ b/phpBB/phpbb/search/backend/fulltext_native.php @@ -308,7 +308,11 @@ class fulltext_native extends base implements search_backend_interface ); $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('/(?config['max_num_search_keywords'] && $num_keywords > $this->config['max_num_search_keywords']) diff --git a/phpBB/phpbb/session.php b/phpBB/phpbb/session.php index 5cfe3d91f3..cc86f6f3ce 100644 --- a/phpBB/phpbb/session.php +++ b/phpBB/phpbb/session.php @@ -451,7 +451,7 @@ class session $this->check_ban_for_current_session($config); // Update user last active time accordingly, but in a minute or so - if ((int) $this->data['session_time'] - (int) $this->data['user_last_active'] > 60) + if ($this->time_now - (int) $this->data['user_last_active'] > 60) { $this->update_last_active_time(); } @@ -832,7 +832,7 @@ class session // Update the form key $sql = 'UPDATE ' . USERS_TABLE . ' SET user_form_salt = \'' . $db->sql_escape($this->data['user_form_salt']) . '\', - user_last_active = ' . (int) $this->data['session_time'] . ' + user_last_active = ' . (int) $this->time_now . ' WHERE user_id = ' . (int) $this->data['user_id']; $db->sql_query($sql); } @@ -980,8 +980,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 @@ -989,7 +989,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 @@ -1718,7 +1719,7 @@ class session { $sql = 'UPDATE ' . USERS_TABLE . ' SET user_lastvisit = ' . (int) $this->data['session_time'] . ', - user_last_active = ' . (int) $this->data['session_time'] . ' + user_last_active = ' . $this->time_now . ' WHERE user_id = ' . (int) $this->data['user_id']; $db->sql_query($sql); } @@ -1733,10 +1734,10 @@ class session { global $db; - if (isset($this->data['session_time'], $this->data['user_id'])) + if (isset($this->time_now, $this->data['user_id'])) { $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_last_active = ' . (int) $this->data['session_time'] . ' + SET user_last_active = ' . $this->time_now . ' WHERE user_id = ' . (int) $this->data['user_id']; $db->sql_query($sql); } diff --git a/phpBB/phpbb/storage/adapter/adapter_interface.php b/phpBB/phpbb/storage/adapter/adapter_interface.php index 725b954c2d..d7fcd77bcb 100644 --- a/phpBB/phpbb/storage/adapter/adapter_interface.php +++ b/phpBB/phpbb/storage/adapter/adapter_interface.php @@ -20,7 +20,7 @@ interface adapter_interface /** * Set adapter parameters * - * @param array options Storage-specific options. + * @param array $options options Storage-specific options. */ public function configure(array $options): void; @@ -82,13 +82,15 @@ interface adapter_interface public function copy(string $path_orig, string $path_dest): void; /** - * Get direct link + * Get file size in bytes * * @param string $path The file * - * @return string Returns link. + * @return int Size in bytes. + * + * @throws storage_exception When unable to retrieve file size */ - public function get_link(string $path): string; + public function file_size(string $path): int; /** * Get space available in bytes diff --git a/phpBB/phpbb/storage/adapter/local.php b/phpBB/phpbb/storage/adapter/local.php index 48722cf5b2..72d92096d5 100644 --- a/phpBB/phpbb/storage/adapter/local.php +++ b/phpBB/phpbb/storage/adapter/local.php @@ -18,8 +18,6 @@ use phpbb\storage\exception\storage_exception; use phpbb\filesystem\exception\filesystem_exception; use phpbb\filesystem\filesystem; use phpbb\filesystem\helper as filesystem_helper; -use phpbb\mimetype\guesser; -use FastImageSize\FastImageSize; /** * Experimental @@ -33,20 +31,6 @@ class local implements adapter_interface, stream_interface */ protected $filesystem; - /** - * FastImageSize - * - * @var FastImageSize - */ - protected $imagesize; - - /** - * Mimetype Guesser component - * - * @var guesser - */ - protected $mimetype_guesser; - /** * @var string path */ @@ -77,15 +61,11 @@ class local implements adapter_interface, stream_interface * Constructor * * @param filesystem $filesystem - * @param FastImageSize $imagesize - * @param guesser $mimetype_guesser * @param string $phpbb_root_path */ - public function __construct(filesystem $filesystem, FastImageSize $imagesize, guesser $mimetype_guesser, string $phpbb_root_path) + public function __construct(filesystem $filesystem, string $phpbb_root_path) { $this->filesystem = $filesystem; - $this->imagesize = $imagesize; - $this->mimetype_guesser = $mimetype_guesser; $this->phpbb_root_path = $phpbb_root_path; } @@ -294,15 +274,9 @@ class local implements adapter_interface, stream_interface } /** - * Get file size - * - * @param string $path The file - * - * @return array Properties - * - * @throws storage_exception When cannot get size + * {@inheritdoc} */ - public function file_size(string $path): array + public function file_size(string $path): int { $size = @filesize($this->root_path . $this->get_path($path) . $this->get_filename($path)); @@ -311,72 +285,7 @@ class local implements adapter_interface, stream_interface throw new storage_exception('STORAGE_CANNOT_GET_FILESIZE'); } - return ['size' => $size]; - } - - /** - * Get file mimetype - * - * @param string $path The file - * - * @return array Properties - */ - public function file_mimetype(string $path): array - { - return ['mimetype' => $this->mimetype_guesser->guess($this->root_path . $this->get_path($path) . $this->get_filename($path))]; - } - - /** - * Get image dimensions - * - * @param string $path The file - * - * @return array Properties - */ - protected function image_dimensions(string $path): array - { - $size = $this->imagesize->getImageSize($this->root_path . $this->get_path($path) . $this->get_filename($path)); - - // For not supported types like swf - if ($size === false) - { - $imsize = getimagesize($this->root_path . $this->get_path($path) . $this->get_filename($path)); - $size = ['width' => $imsize[0], 'height' => $imsize[1]]; - } - - return ['image_width' => $size['width'], 'image_height' => $size['height']]; - } - - /** - * Get image width - * - * @param string $path The file - * - * @return array Properties - */ - public function file_image_width(string $path): array - { - return $this->image_dimensions($path); - } - - /** - * Get image height - * - * @param string $path The file - * - * @return array Properties - */ - public function file_image_height(string $path): array - { - return $this->image_dimensions($path); - } - - /** - * {@inheritdoc} - */ - public function get_link(string $path): string - { - return generate_board_url() . '/' . $this->path . $path; + return $size; } /** diff --git a/phpBB/phpbb/storage/controller/attachment.php b/phpBB/phpbb/storage/controller/attachment.php index d9e108e098..9d84fceb45 100644 --- a/phpBB/phpbb/storage/controller/attachment.php +++ b/phpBB/phpbb/storage/controller/attachment.php @@ -22,6 +22,7 @@ use phpbb\db\driver\driver_interface; use phpbb\event\dispatcher_interface; use phpbb\exception\http_exception; use phpbb\language\language; +use phpbb\mimetype\extension_guesser; use phpbb\request\request; use phpbb\storage\storage; use phpbb\user; @@ -66,15 +67,16 @@ class attachment extends controller * @param content_visibility $content_visibility * @param driver_interface $db * @param dispatcher_interface $dispatcher + * @param extension_guesser $extension_guesser * @param language $language * @param request $request * @param storage $storage * @param symfony_request $symfony_request * @param user $user */ - public function __construct(auth $auth, service $cache, config $config, content_visibility $content_visibility, driver_interface $db, dispatcher_interface $dispatcher, language $language, request $request, storage $storage, symfony_request $symfony_request, user $user) + public function __construct(auth $auth, service $cache, config $config, content_visibility $content_visibility, driver_interface $db, dispatcher_interface $dispatcher, extension_guesser $extension_guesser, language $language, request $request, storage $storage, symfony_request $symfony_request, user $user) { - parent::__construct($cache, $db, $storage, $symfony_request); + parent::__construct($cache, $db, $extension_guesser, $storage, $symfony_request); $this->auth = $auth; $this->config = $config; diff --git a/phpBB/phpbb/storage/controller/avatar.php b/phpBB/phpbb/storage/controller/avatar.php index 7055961230..720745e2cc 100644 --- a/phpBB/phpbb/storage/controller/avatar.php +++ b/phpBB/phpbb/storage/controller/avatar.php @@ -16,6 +16,7 @@ namespace phpbb\storage\controller; use phpbb\cache\service; use phpbb\config\config; use phpbb\db\driver\driver_interface; +use phpbb\mimetype\extension_guesser; use phpbb\storage\storage; use Symfony\Component\HttpFoundation\Request as symfony_request; use Symfony\Component\HttpFoundation\Response; @@ -39,12 +40,13 @@ class avatar extends controller * @param service $cache * @param config $config * @param driver_interface $db + * @param extension_guesser $extension_guesser * @param storage $storage * @param symfony_request $symfony_request */ - public function __construct(service $cache, config $config, driver_interface $db, storage $storage, symfony_request $symfony_request) + public function __construct(service $cache, config $config, driver_interface $db, extension_guesser $extension_guesser, storage $storage, symfony_request $symfony_request) { - parent::__construct($cache, $db, $storage, $symfony_request); + parent::__construct($cache, $db , $extension_guesser, $storage, $symfony_request); $this->config = $config; } diff --git a/phpBB/phpbb/storage/controller/controller.php b/phpBB/phpbb/storage/controller/controller.php index d1ea9f29f7..94af901eed 100644 --- a/phpBB/phpbb/storage/controller/controller.php +++ b/phpBB/phpbb/storage/controller/controller.php @@ -16,6 +16,7 @@ namespace phpbb\storage\controller; use phpbb\cache\service; use phpbb\db\driver\driver_interface; use phpbb\exception\http_exception; +use phpbb\mimetype\extension_guesser; use phpbb\storage\exception\storage_exception; use phpbb\storage\storage; use Symfony\Component\HttpFoundation\Request as symfony_request; @@ -33,6 +34,9 @@ class controller /** @var driver_interface */ protected $db; + /** @var extension_guesser */ + protected $extension_guesser; + /** @var storage */ protected $storage; @@ -47,10 +51,11 @@ class controller * @param storage $storage * @param symfony_request $symfony_request */ - public function __construct(service $cache, driver_interface $db, storage $storage, symfony_request $symfony_request) + public function __construct(service $cache, driver_interface $db, extension_guesser $extension_guesser, storage $storage, symfony_request $symfony_request) { $this->cache = $cache; $this->db = $db; + $this->extension_guesser = $extension_guesser; $this->storage = $storage; $this->symfony_request = $symfony_request; } @@ -124,14 +129,12 @@ class controller */ protected function prepare(StreamedResponse $response, string $file): void { - $file_info = $this->storage->file_info($file); - // Add Content-Type header if (!$response->headers->has('Content-Type')) { try { - $content_type = $file_info->get('mimetype'); + $content_type = $this->extension_guesser->guess($file); } catch (storage_exception $e) { @@ -146,7 +149,7 @@ class controller { try { - $response->headers->set('Content-Length', $file_info->get('size')); + $response->headers->set('Content-Length', $this->storage->file_size($file)); } catch (storage_exception $e) { diff --git a/phpBB/phpbb/storage/file_info.php b/phpBB/phpbb/storage/file_info.php deleted file mode 100644 index 3bb6b28131..0000000000 --- a/phpBB/phpbb/storage/file_info.php +++ /dev/null @@ -1,85 +0,0 @@ - - * @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\storage; - -use phpbb\storage\exception\storage_exception; -use phpbb\storage\adapter\adapter_interface; - -class file_info -{ - /** - * @var adapter_interface - */ - protected $adapter; - - /** - * Path of the file - * - * @var string - */ - protected $path; - - /** - * Stores the properties of $path file, so dont have to be consulted multiple times. - * For example, when you need the width of an image, using getimagesize() you get - * both dimensions, so you store both here, and when you get the height, you dont have - * to call getimagesize() again - * - * @var array - */ - protected $properties; - - /** - * Constructor - * - * @param adapter_interface $adapter - * @param string $path - */ - public function __construct(adapter_interface $adapter, $path) - { - $this->adapter = $adapter; - $this->path = $path; - $this->properties = []; - } - - /** - * Load propertys lazily - * - * @param string $name The property name. - * - * @return string Returns the property value - */ - public function get($name) - { - if (!isset($this->properties[$name])) - { - if (!method_exists($this->adapter, 'file_' . $name)) - { - throw new storage_exception('STORAGE_METHOD_NOT_IMPLEMENTED'); - } - - $this->properties = array_merge($this->properties, call_user_func([$this->adapter, 'file_' . $name], $this->path)); - } - - return $this->properties[$name]; - } - - /** - * Alias of \phpbb\storage\file_info->get() - */ - public function __get($name) - { - return $this->get($name); - } -} diff --git a/phpBB/phpbb/storage/storage.php b/phpBB/phpbb/storage/storage.php index a4c652f40a..fa1ca0d204 100644 --- a/phpBB/phpbb/storage/storage.php +++ b/phpBB/phpbb/storage/storage.php @@ -59,11 +59,11 @@ class storage * * @param db $db * @param cache $cache - * @param adapter_factory $factory + * @param adapter_factory $factory * @param string $storage_name * @param string $storage_table */ - public function __construct(db $db, cache $cache, adapter_factory $factory, $storage_name, $storage_table) + public function __construct(db $db, cache $cache, adapter_factory $factory, string $storage_name, string $storage_table) { $this->db = $db; $this->cache = $cache; @@ -77,7 +77,7 @@ class storage * * @return string */ - public function get_name() + public function get_name(): string { return $this->storage_name; } @@ -87,7 +87,7 @@ class storage * * @return adapter_interface */ - protected function get_adapter() + protected function get_adapter(): mixed { if ($this->adapter === null) { @@ -106,7 +106,7 @@ class storage * @throws storage_exception When the file already exists * When the file cannot be written */ - public function put_contents($path, $content) + public function put_contents(string $path, string $content): void { if ($this->exists($path)) { @@ -128,7 +128,7 @@ class storage * When cannot read file contents * */ - public function get_contents($path) + public function get_contents(string $path): string { if (!$this->exists($path)) { @@ -146,7 +146,7 @@ class storage * * @return bool Returns true if the file/directory exist, false otherwise */ - public function exists($path, $full_check = false) + public function exists(string $path, bool $full_check = false): bool { return ($this->is_tracked($path) && (!$full_check || $this->get_adapter()->exists($path))); } @@ -154,12 +154,12 @@ class storage /** * Removes files or directories * - * @param string $path file/directory to remove + * @param string $path file/directory to remove * * @throws storage_exception When removal fails * When the file doesn't exist */ - public function delete($path) + public function delete(string $path): void { if (!$this->exists($path)) { @@ -173,14 +173,14 @@ class storage /** * Rename a file or a directory * - * @param string $path_orig The original file/direcotry - * @param string $path_dest The target file/directory + * @param string $path_orig The original file/direcotry + * @param string $path_dest The target file/directory * * @throws storage_exception When the file doesn't exist * When target exists * When file/directory cannot be renamed */ - public function rename($path_orig, $path_dest) + public function rename(string $path_orig, string $path_dest): void { if (!$this->exists($path_orig)) { @@ -199,14 +199,14 @@ class storage /** * Copies a file * - * @param string $path_orig The original filename - * @param string $path_dest The target filename + * @param string $path_orig The original filename + * @param string $path_dest The target filename * * @throws storage_exception When the file doesn't exist * When target exists * When the file cannot be copied */ - public function copy($path_orig, $path_dest) + public function copy(string $path_orig, string $path_dest): void { if (!$this->exists($path_orig)) { @@ -225,14 +225,14 @@ class storage /** * Reads a file as a stream * - * @param string $path File to read + * @param string $path File to read * * @return resource Returns a file pointer * @throws storage_exception When the file doesn't exist * When unable to open file * */ - public function read_stream($path) + public function read_stream(string $path) { if (!$this->exists($path)) { @@ -260,13 +260,13 @@ class storage /** * Writes a new file using a stream * - * @param string $path The target file + * @param string $path The target file * @param resource $resource The resource * * @throws storage_exception When the file exist * When target file cannot be created */ - public function write_stream($path, $resource) + public function write_stream(string $path, $resource): void { if ($this->exists($path)) { @@ -295,10 +295,10 @@ class storage /** * Track file in database * - * @param string $path The target file - * @param bool $update Update file size when already tracked + * @param string $path The target file + * @param bool $update Update file size when already tracked */ - public function track_file($path, $update = false) + public function track_file(string $path, bool $update = false): void { if (!$this->get_adapter()->exists($path)) { @@ -319,20 +319,15 @@ class storage if (!$row) { - // Don't call the file_info method, because it check's if the file is tracked - // and is not (for now). This method check if the file exists using the adapter - // at the beginning. - $file = new file_info($this->get_adapter(), $path); - $sql_ary['filesize'] = $file->size; + $sql_ary['filesize'] = $this->get_adapter()->file_size($path); $sql = 'INSERT INTO ' . $this->storage_table . $this->db->sql_build_array('INSERT', $sql_ary); $this->db->sql_query($sql); } else if ($update) { - $file = $this->file_info($path); $sql = 'UPDATE ' . $this->storage_table . ' - SET filesize = ' . $file->size . ' + SET filesize = ' . $this->get_adapter()->file_size($path) . ' WHERE ' . $this->db->sql_build_array('SELECT', $sql_ary); $this->db->sql_query($sql); } @@ -364,11 +359,11 @@ class storage /** * Check if a file is tracked * - * @param string $path The file + * @param string $path The file * * @return bool True if file is tracked */ - public function is_tracked($path) + public function is_tracked(string $path): bool { $sql_ary = array( 'file_path' => $path, @@ -381,16 +376,16 @@ class storage $row = $this->db->sql_fetchrow($result); $this->db->sql_freeresult($result); - return ($row) ? true : false; + return $row !== false; } /** * Rename tracked file * - * @param string $path_orig The original file/direcotry - * @param string $path_dest The target file/directory + * @param string $path_orig The original file/direcotry + * @param string $path_dest The target file/directory */ - protected function track_rename($path_orig, $path_dest) + protected function track_rename(string $path_orig, string $path_dest): void { $sql = 'UPDATE ' . $this->storage_table . " SET file_path = '" . $this->db->sql_escape($path_dest) . "' @@ -400,36 +395,28 @@ class storage } /** - * Get file info + * Get file size in bytes * - * @param string $path The file + * @param string $path The file * - * @return \phpbb\storage\file_info Returns file_info object - * @throws storage_exception When the adapter doesn't implement the method - * When the file doesn't exist + * @return int Size in bytes. * + * @throws storage_exception When unable to retrieve file size */ - public function file_info($path) + public function file_size(string $path): int { - if (!$this->exists($path)) - { - throw new storage_exception('STORAGE_FILE_NO_EXIST', $path); - } + $sql_ary = array( + 'file_path' => $path, + 'storage' => $this->get_name(), + ); - return new file_info($this->get_adapter(), $path); - } + $sql = 'SELECT filesize FROM ' . $this->storage_table . ' + WHERE ' . $this->db->sql_build_array('SELECT', $sql_ary); + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); - /** - * Get direct link - * - * @param string $path The file - * - * @return string Returns link. - * - */ - public function get_link($path) - { - return $this->get_adapter()->get_link($path); + return $row !== false && !empty($row['filesize']) ? $row['filesize'] : $this->get_adapter()->file_size($path); } /** @@ -437,7 +424,7 @@ class storage * * @return int Size in bytes */ - public function get_size() + public function get_size(): int { $total_size = $this->cache->get('_storage_' . $this->get_name() . '_totalsize'); @@ -462,7 +449,7 @@ class storage * * @return int Number of files */ - public function get_num_files() + public function get_num_files(): int { $number_files = $this->cache->get('_storage_' . $this->get_name() . '_numfiles'); @@ -493,4 +480,5 @@ class storage { return $this->get_adapter()->free_space(); } + } diff --git a/phpBB/phpbb/template/twig/extension.php b/phpBB/phpbb/template/twig/extension.php index 2e920dbe4b..7fde9e2cac 100644 --- a/phpBB/phpbb/template/twig/extension.php +++ b/phpBB/phpbb/template/twig/extension.php @@ -93,6 +93,7 @@ class extension extends \Twig\Extension\AbstractExtension new \Twig\TwigFunction('lang', array($this, 'lang')), new \Twig\TwigFunction('lang_defined', array($this, 'lang_defined')), new \Twig\TwigFunction('lang_js', [$this, 'lang_js']), + new \Twig\TwigFunction('lang_raw', [$this, 'lang_raw']), new \Twig\TwigFunction('get_class', 'get_class'), ); } @@ -214,4 +215,16 @@ class extension extends \Twig\Extension\AbstractExtension return twig_escape_filter($this->environment, call_user_func_array([$this, 'lang'], $args), 'js'); } + + /** + * Get raw value associated with lang key + * + * @param string $key + * + * @return array|string Raw value associated with lang key + */ + public function lang_raw(string $key): array|string + { + return call_user_func_array(array($this->language, 'lang_raw'), [$key]); + } } diff --git a/phpBB/phpbb/template/twig/extension/forms.php b/phpBB/phpbb/template/twig/extension/forms.php index 5a3d9420db..b146aacfb9 100644 --- a/phpBB/phpbb/template/twig/extension/forms.php +++ b/phpBB/phpbb/template/twig/extension/forms.php @@ -183,6 +183,7 @@ class forms extends AbstractExtension 'GROUP_ONLY' => (bool) ($form_data['group_only'] ?? false), 'SIZE' => (int) ($form_data['size'] ?? 0), 'MULTIPLE' => (bool) ($form_data['multiple'] ?? false), + 'ONCHANGE' => (string) ($form_data['onchange'] ?? ''), ]); } catch (\Twig\Error\Error $e) diff --git a/phpBB/phpbb/textformatter/parser_interface.php b/phpBB/phpbb/textformatter/parser_interface.php index ad611fb5b4..1430bfd5d3 100644 --- a/phpBB/phpbb/textformatter/parser_interface.php +++ b/phpBB/phpbb/textformatter/parser_interface.php @@ -91,8 +91,6 @@ interface parser_interface * Set a variable to be used by the parser * * - max_font_size - * - max_img_height - * - max_img_width * - max_smilies * - max_urls * diff --git a/phpBB/phpbb/textformatter/s9e/factory.php b/phpBB/phpbb/textformatter/s9e/factory.php index 7195f95915..78f8cbe6c6 100644 --- a/phpBB/phpbb/textformatter/s9e/factory.php +++ b/phpBB/phpbb/textformatter/s9e/factory.php @@ -355,20 +355,10 @@ class factory implements \phpbb\textformatter\cache_interface // Register some vars with a default value. Those should be set at runtime by whatever calls // the parser $configurator->registeredVars['max_font_size'] = 0; - $configurator->registeredVars['max_img_height'] = 0; - $configurator->registeredVars['max_img_width'] = 0; // Load the Emoji plugin and modify its tag's template to obey viewsmilies $tag = $configurator->Emoji->getTag(); - $tag->template = ' - - {.} - - - {.} - - '; - $tag->template = '' . str_replace('class="emoji"', 'class="emoji smilies"', $tag->template) . ''; + $tag->template = ''; /** * Modify the s9e\TextFormatter configurator after the default settings are set diff --git a/phpBB/phpbb/textreparser/base.php b/phpBB/phpbb/textreparser/base.php index 84209a4127..1c26563f05 100644 --- a/phpBB/phpbb/textreparser/base.php +++ b/phpBB/phpbb/textreparser/base.php @@ -219,11 +219,11 @@ abstract class base implements reparser_interface /** * {@inheritdoc} */ - public function reparse_range($min_id, $max_id) + public function reparse_range($min_id, $max_id, bool $force_bbcode_reparsing = false) { foreach ($this->get_records_by_range($min_id, $max_id) as $record) { - $this->reparse_record($record); + $this->reparse_record($record, $force_bbcode_reparsing); } } @@ -231,16 +231,17 @@ abstract class base implements reparser_interface * Reparse given record * * @param array $record Associative array containing the record's data + * @param bool $force_bbcode_reparsing Flag indicating if BBCode should be reparsed unconditionally */ - protected function reparse_record(array $record) + protected function reparse_record(array $record, bool $force_bbcode_reparsing = false) { // Guess magic URL state based on actual record content before adding fields $record['enable_magic_url'] = $this->guess_magic_url($record); $record = $this->add_missing_fields($record); - $flags = ($record['enable_bbcode']) ? OPTION_FLAG_BBCODE : 0; - $flags |= ($record['enable_smilies']) ? OPTION_FLAG_SMILIES : 0; - $flags |= ($record['enable_magic_url']) ? OPTION_FLAG_LINKS : 0; + $flags = ($record['enable_bbcode'] || $force_bbcode_reparsing) ? OPTION_FLAG_BBCODE : 0; + $flags |= ($record['enable_smilies'] || $force_bbcode_reparsing) ? OPTION_FLAG_SMILIES : 0; + $flags |= ($record['enable_magic_url'] || $force_bbcode_reparsing) ? OPTION_FLAG_LINKS : 0; $unparsed = array_merge( $record, generate_text_for_edit($record['text'], $record['bbcode_uid'], $flags) @@ -256,12 +257,12 @@ abstract class base implements reparser_interface $unparsed['bbcode_uid'], $bitfield, $flags, - $unparsed['enable_bbcode'], - $unparsed['enable_magic_url'], - $unparsed['enable_smilies'], - $unparsed['enable_img_bbcode'], - $unparsed['enable_quote_bbcode'], - $unparsed['enable_url_bbcode'], + $unparsed['enable_bbcode'] || $force_bbcode_reparsing, + $unparsed['enable_magic_url'] || $force_bbcode_reparsing, + $unparsed['enable_smilies'] || $force_bbcode_reparsing, + $unparsed['enable_img_bbcode'] || $force_bbcode_reparsing, + $unparsed['enable_quote_bbcode'] || $force_bbcode_reparsing, + $unparsed['enable_url_bbcode'] || $force_bbcode_reparsing, 'text_reparser.' . $this->get_name() ); diff --git a/phpBB/phpbb/textreparser/reparser_interface.php b/phpBB/phpbb/textreparser/reparser_interface.php index 912de10058..99e1c26778 100644 --- a/phpBB/phpbb/textreparser/reparser_interface.php +++ b/phpBB/phpbb/textreparser/reparser_interface.php @@ -41,6 +41,7 @@ interface reparser_interface * * @param integer $min_id Lower bound * @param integer $max_id Upper bound + * @param bool $force_bbcode_reparsing Flag indicating if BBCode should be reparsed unconditionally */ - public function reparse_range($min_id, $max_id); + public function reparse_range($min_id, $max_id, bool $force_bbcode_reparsing = false); } diff --git a/phpBB/phpbb/ucp/controller/delete_cookies.php b/phpBB/phpbb/ucp/controller/delete_cookies.php new file mode 100644 index 0000000000..869227abea --- /dev/null +++ b/phpBB/phpbb/ucp/controller/delete_cookies.php @@ -0,0 +1,134 @@ + + * @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') . '

        ' . $this->language->lang('RETURN_INDEX', 'phpbb_root_path}index.$this->php_ext") . '">', ''); + trigger_error($message); + } + else + { + confirm_box(false, 'DELETE_COOKIES', ''); + } + + redirect(append_sid("{$this->phpbb_root_path}index.$this->php_ext")); + } +} diff --git a/phpBB/phpbb/ucp/controller/webpush.php b/phpBB/phpbb/ucp/controller/webpush.php index b60fa437b3..313965db63 100644 --- a/phpBB/phpbb/ucp/controller/webpush.php +++ b/phpBB/phpbb/ucp/controller/webpush.php @@ -19,10 +19,13 @@ use phpbb\db\driver\driver_interface; use phpbb\exception\http_exception; use phpbb\form\form_helper; use phpbb\json\sanitizer as json_sanitizer; +use phpbb\language\language; +use phpbb\notification\manager; use phpbb\path_helper; use phpbb\request\request_interface; use phpbb\symfony_request; use phpbb\user; +use phpbb\user_loader; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; use Twig\Environment; @@ -47,12 +50,21 @@ class webpush /** @var form_helper */ protected $form_helper; + /** @var language */ + protected $language; + + /** @var manager */ + protected $notification_manager; + /** @var path_helper */ protected $path_helper; /** @var request_interface */ protected $request; + /** @var user_loader */ + protected $user_loader; + /** @var user */ protected $user; @@ -72,22 +84,28 @@ class webpush * @param controller_helper $controller_helper * @param driver_interface $db * @param form_helper $form_helper + * @param language $language + * @param manager $notification_manager * @param path_helper $path_helper * @param request_interface $request + * @param user_loader $user_loader * @param user $user * @param Environment $template * @param string $notification_webpush_table * @param string $push_subscriptions_table */ - public function __construct(config $config, controller_helper $controller_helper, driver_interface $db, form_helper $form_helper, path_helper $path_helper, - request_interface $request, user $user, Environment $template, string $notification_webpush_table, string $push_subscriptions_table) + public function __construct(config $config, controller_helper $controller_helper, driver_interface $db, form_helper $form_helper, language $language, manager $notification_manager, + path_helper $path_helper, request_interface $request, user_loader $user_loader, user $user, Environment $template, string $notification_webpush_table, string $push_subscriptions_table) { $this->config = $config; $this->controller_helper = $controller_helper; $this->db = $db; $this->form_helper = $form_helper; + $this->language = $language; + $this->notification_manager = $notification_manager; $this->path_helper = $path_helper; $this->request = $request; + $this->user_loader = $user_loader; $this->user = $user; $this->template = $template; $this->notification_webpush_table = $notification_webpush_table; @@ -101,11 +119,38 @@ class webpush */ public function notification(): JsonResponse { - // Subscribe should only be available for logged-in "normal" users - if (!$this->request->is_ajax() || $this->user->id() == ANONYMOUS || $this->user->data['is_bot'] - || $this->user->data['user_type'] == USER_IGNORE || $this->user->data['user_type'] == USER_INACTIVE) + if (!$this->request->is_ajax() || $this->user->data['is_bot'] || $this->user->data['user_type'] == USER_INACTIVE) { - throw new http_exception(Response::HTTP_FORBIDDEN, 'Forbidden'); + throw new http_exception(Response::HTTP_FORBIDDEN, 'NO_AUTH_OPERATION'); + } + + if ($this->user->id() !== ANONYMOUS) + { + $notification_data = $this->get_user_notifications(); + } + else + { + $notification_data = $this->get_anonymous_notifications(); + } + + // Decode and return data if everything is fine + $data = json_decode($notification_data, true); + $data['url'] = isset($data['url']) ? $this->path_helper->update_web_root_path($data['url']) : ''; + + return new JsonResponse($data); + } + + /** + * Get notification data for logged in user + * + * @return string Notification data + */ + private function get_user_notifications(): string + { + // Subscribe should only be available for logged-in "normal" users + if ($this->user->data['user_type'] == USER_IGNORE) + { + throw new http_exception(Response::HTTP_FORBIDDEN, 'NO_AUTH_OPERATION'); } $item_id = $this->request->variable('item_id', 0); @@ -119,10 +164,92 @@ class webpush $result = $this->db->sql_query($sql); $notification_data = $this->db->sql_fetchfield('push_data'); $this->db->sql_freeresult($result); - $data = json_decode($notification_data, true); - $data['url'] = isset($data['url']) ? $this->path_helper->update_web_root_path($data['url']) : ''; - return new JsonResponse($data); + return $this->get_notification_data($notification_data); + } + + /** + * Get notification data for not logged in user via token + * + * @return string + */ + private function get_anonymous_notifications(): string + { + $token = $this->request->variable('token', ''); + + if ($token) + { + $item_id = $this->request->variable('item_id', 0); + $type_id = $this->request->variable('type_id', 0); + $user_id = $this->request->variable('user_id', 0); + + $sql = 'SELECT push_data, push_token + FROM ' . $this->notification_webpush_table . ' + WHERE user_id = ' . (int) $user_id . ' + AND notification_type_id = ' . (int) $type_id . ' + AND item_id = ' . (int) $item_id; + $result = $this->db->sql_query($sql); + $notification_row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $notification_data = $notification_row['push_data']; + $push_token = $notification_row['push_token']; + + // Check if passed push token is valid + $sql = 'SELECT user_form_salt, user_lang + FROM ' . USERS_TABLE . ' + WHERE user_id = ' . (int) $user_id; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $user_form_token = $row['user_form_salt']; + $user_lang = $row['user_lang']; + + $expected_push_token = hash('sha256', $user_form_token . $push_token); + if ($expected_push_token === $token) + { + if ($user_lang !== $this->language->get_used_language()) + { + $this->language->set_user_language($user_lang, true); + } + return $this->get_notification_data($notification_data); + } + } + + throw new http_exception(Response::HTTP_FORBIDDEN, 'NO_AUTH_OPERATION'); + } + + /** + * Get notification data for output from json encoded data stored in database + * + * @param string $notification_data Encoded data stored in database + * + * @return string Data for notification output with javascript + */ + private function get_notification_data(string $notification_data): string + { + $row_data = json_decode($notification_data, true); + + // Old notification data is pre-parsed and just needs to be returned + if (isset($row_data['heading'])) + { + return $notification_data; + } + + // Get notification from row_data + $notification = $this->notification_manager->get_item_type_class($row_data['notification_type_name'], $row_data); + + // Load users for notification + $this->user_loader->load_users($notification->users_to_query()); + + return json_encode([ + 'heading' => $this->config['sitename'], + 'title' => strip_tags(html_entity_decode($notification->get_title(), ENT_NOQUOTES, 'UTF-8')), + 'text' => strip_tags(html_entity_decode($notification->get_reference(), ENT_NOQUOTES, 'UTF-8')), + 'url' => htmlspecialchars_decode($notification->get_url()), + 'avatar' => $notification->get_avatar(), + ]); } /** @@ -135,7 +262,6 @@ class webpush */ public function worker(): Response { - // @todo: only work for logged in users, no anonymous & bot $content = $this->template->render('push_worker.js.twig', [ 'U_WEBPUSH_GET_NOTIFICATION' => $this->controller_helper->route('phpbb_ucp_push_get_notification_controller'), 'ASSETS_VERSION' => $this->config['assets_version'], @@ -153,20 +279,6 @@ class webpush return $response; } - /** - * Get template variables for subscribe type pages - * - * @return array - */ - protected function get_subscribe_vars(): array - { - return [ - 'U_WEBPUSH_SUBSCRIBE' => $this->controller_helper->route('phpbb_ucp_push_subscribe_controller'), - 'U_WEBPUSH_UNSUBSCRIBE' => $this->controller_helper->route('phpbb_ucp_push_unsubscribe_controller'), - 'FORM_TOKENS' => $this->form_helper->get_form_tokens(self::FORM_TOKEN_UCP), - ]; - } - /** * Check (un)subscribe form for valid link hash * @@ -181,7 +293,7 @@ class webpush } // Subscribe should only be available for logged-in "normal" users - if (!$this->request->is_ajax() || $this->user->id() == ANONYMOUS || $this->user->data['is_bot'] + if (!$this->request->is_ajax() || $this->user->id() === ANONYMOUS || $this->user->data['is_bot'] || $this->user->data['user_type'] == USER_IGNORE || $this->user->data['user_type'] == USER_INACTIVE) { throw new http_exception(Response::HTTP_FORBIDDEN, 'NO_AUTH_OPERATION'); diff --git a/phpBB/posting.php b/phpBB/posting.php index 0f9ad87988..9f8cce0ead 100644 --- a/phpBB/posting.php +++ b/phpBB/posting.php @@ -455,8 +455,10 @@ if (!$is_authed || !empty($error)) if ($config['enable_post_confirm'] && !$user->data['is_registered']) { - $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']); - $captcha->init(CONFIRM_POST); + /** @var \phpbb\captcha\factory $captcha_factory */ + $captcha_factory = $phpbb_container->get('captcha.factory'); + $captcha = $captcha_factory->get_instance($config['captcha_plugin']); + $captcha->init(\phpbb\captcha\plugins\confirm_type::POST); } // Is the user able to post within this forum? @@ -846,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, @@ -1207,15 +1210,9 @@ if ($submit || $preview || $refresh) if ($config['enable_post_confirm'] && !$user->data['is_registered'] && in_array($mode, array('quote', 'post', 'reply'))) { - $captcha_data = array( - 'message' => $request->variable('message', '', true), - 'subject' => $request->variable('subject', '', true), - 'username' => $request->variable('username', '', true), - ); - $vc_response = $captcha->validate($captcha_data); - if ($vc_response) + if ($captcha->validate() !== true) { - $error[] = $vc_response; + $error[] = $captcha->get_error(); } } @@ -1599,7 +1596,7 @@ if ($submit || $preview || $refresh) ); extract($phpbb_dispatcher->trigger_event('core.posting_modify_submit_post_after', compact($vars))); - if ($config['enable_post_confirm'] && !$user->data['is_registered'] && (isset($captcha) && $captcha->is_solved() === true) && ($mode == 'post' || $mode == 'reply' || $mode == 'quote')) + if ($config['enable_post_confirm'] && !$user->data['is_registered'] && $captcha->is_solved() === true && ($mode == 'post' || $mode == 'reply' || $mode == 'quote')) { $captcha->reset(); } diff --git a/phpBB/search.php b/phpBB/search.php index 0d5ee35d66..bec4cb96e2 100644 --- a/phpBB/search.php +++ b/phpBB/search.php @@ -90,8 +90,21 @@ switch ($search_id) break; } +$search_auth_check_override = false; +/** +* This event allows you to override search auth checks +* +* @event core.search_auth_check_override +* @var bool search_auth_check_override Whether or not the search auth check overridden +* @since 3.3.14-RC1 +*/ +$vars = [ + 'search_auth_check_override', +]; +extract($phpbb_dispatcher->trigger_event('core.search_auth_check_override', compact($vars))); + // Is user able to search? Has search been disabled? -if (!$auth->acl_get('u_search') || !$auth->acl_getf_global('f_search') || !$config['load_search']) +if (!$search_auth_check_override && (!$auth->acl_get('u_search') || !$auth->acl_getf_global('f_search') || !$config['load_search'])) { $template->assign_var('S_NO_SEARCH', true); trigger_error('NO_SEARCH'); diff --git a/phpBB/styles/all/js/push_worker.js.twig b/phpBB/styles/all/js/push_worker.js.twig index f2807cb43a..cf0ca568ac 100644 --- a/phpBB/styles/all/js/push_worker.js.twig +++ b/phpBB/styles/all/js/push_worker.js.twig @@ -23,12 +23,16 @@ self.addEventListener('push', event => { let itemId = 0; let typeId = 0; - let notificationVersion = 5; + let userId = 0; + let notificationVersion = 0; + let pushToken = ''; try { const notificationData = event.data.json(); itemId = notificationData.item_id; typeId = notificationData.type_id; + userId = notificationData.user_id; notificationVersion = parseInt(notificationData.version, 10); + pushToken = notificationData.token; } catch { self.registration.showNotification(event.data.text()); return; @@ -45,6 +49,8 @@ self.addEventListener('push', event => { const formData = new FormData(); formData.append('item_id', itemId.toString(10)); formData.append('type_id', typeId.toString(10)); + formData.append('user_id', userId.toString(10)); + formData.append('token', pushToken); fetch(getNotificationUrl, { method: 'POST', diff --git a/phpBB/styles/all/template/macros/forms/select.twig b/phpBB/styles/all/template/macros/forms/select.twig index 827ccb1121..1ada063e57 100644 --- a/phpBB/styles/all/template/macros/forms/select.twig +++ b/phpBB/styles/all/template/macros/forms/select.twig @@ -8,6 +8,7 @@ name="{{ NAME }}" {% if TOGGLEABLE %}data-togglable-settings="true"{% endif %} {% if MULTIPLE %}multiple="multiple"{% endif %} + {% if ONCHANGE %}onchange="{{ ONCHANGE }}"{% endif %} {% if SIZE %}size="{{ SIZE }}"{% endif %}> {% for element in OPTIONS %} {% if not GROUP_ONLY and element.options %} diff --git a/phpBB/styles/prosilver/imgs/svg/toggle-off.svg b/phpBB/styles/prosilver/imgs/svg/toggle-off.svg new file mode 100644 index 0000000000..9bd31a7bf5 --- /dev/null +++ b/phpBB/styles/prosilver/imgs/svg/toggle-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/styles/prosilver/imgs/svg/toggle-on.svg b/phpBB/styles/prosilver/imgs/svg/toggle-on.svg new file mode 100644 index 0000000000..83d2e59c0c --- /dev/null +++ b/phpBB/styles/prosilver/imgs/svg/toggle-on.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/phpBB/styles/prosilver/template/ajax.js b/phpBB/styles/prosilver/template/ajax.js index 421c43f767..3fb6a88a87 100644 --- a/phpBB/styles/prosilver/template/ajax.js +++ b/phpBB/styles/prosilver/template/ajax.js @@ -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 diff --git a/phpBB/styles/prosilver/template/bbcode.html b/phpBB/styles/prosilver/template/bbcode.html index 583b764b2c..dc051eef3e 100644 --- a/phpBB/styles/prosilver/template/bbcode.html +++ b/phpBB/styles/prosilver/template/bbcode.html @@ -38,11 +38,11 @@ - + - + diff --git a/phpBB/styles/prosilver/template/captcha_turnstile.html b/phpBB/styles/prosilver/template/captcha_turnstile.html new file mode 100644 index 0000000000..1cf4f4c792 --- /dev/null +++ b/phpBB/styles/prosilver/template/captcha_turnstile.html @@ -0,0 +1,23 @@ +{% if CONFIRM_TYPE_REGISTRATION %} +
        +
        +

        {{ lang('CONFIRMATION') }}

        +
        +{% endif %} +{% if S_TURNSTILE_AVAILABLE %} + + + + + {# The cf-turnstile class is used in JavaScript #} +
        +{% else %} + {{ lang('CAPTCHA_TURNSTILE_NOT_AVAILABLE') }} +{% endif %} +{% if CONFIRM_TYPE_REGISTRATION %} +
        +
        +
        +{% endif %} diff --git a/phpBB/styles/prosilver/template/memberlist_view.html b/phpBB/styles/prosilver/template/memberlist_view.html index 6914778623..2a69cb08be 100644 --- a/phpBB/styles/prosilver/template/memberlist_view.html +++ b/phpBB/styles/prosilver/template/memberlist_view.html @@ -9,7 +9,7 @@
        -
        +
        {AVATAR_HTML}
        {RANK_TITLE}
        diff --git a/phpBB/styles/prosilver/template/navbar_header.html b/phpBB/styles/prosilver/template/navbar_header.html index ef6da4ab91..8269f27fa6 100644 --- a/phpBB/styles/prosilver/template/navbar_header.html +++ b/phpBB/styles/prosilver/template/navbar_header.html @@ -69,7 +69,6 @@ {% endif %} {% endif %} -
      • {% EVENT navbar_header_quick_links_after %} diff --git a/phpBB/styles/prosilver/template/notification_dropdown.html b/phpBB/styles/prosilver/template/notification_dropdown.html index ff52543d0a..715f04e1a2 100644 --- a/phpBB/styles/prosilver/template/notification_dropdown.html +++ b/phpBB/styles/prosilver/template/notification_dropdown.html @@ -45,10 +45,10 @@ {L_SEE_ALL}
        {% if NOTIFICATIONS_WEBPUSH_ENABLE and notification_types is not defined %} -