Merge branch 'master' into feat(announcer)-Check-for-frozen-torrents

This commit is contained in:
Roman Kelesidis 2025-05-06 12:25:28 +03:00 committed by GitHub
commit 36b7c055d4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
114 changed files with 1963 additions and 3473 deletions

7
.cliffignore Normal file
View file

@ -0,0 +1,7 @@
9766c534bddad8e82e6d19f9bad5cf70b9887f9a
92ce77ec0ec703c08a659419087a373f76e711f7
2d53efc945c7747be1755d0b66557a86bdc12cbd
602137b65129b817811b80975a369ebde3270c6d
4eb26ae37e1f4c82a45961517ffeb54c20200408
e59adce848a9e10ee5775254045cbbd915236b8b
9e0a64108d62236ab07b3f8d10e8c78269b8e1d1

View file

@ -1,10 +1,11 @@
# Common params # Common params
TP_HOST=example.com
TP_PORT=80
APP_ENV=production APP_ENV=production
APP_CRON_ENABLED=true APP_CRON_ENABLED=true
APP_DEMO_MODE=false APP_DEMO_MODE=false
# Database credentials # Database credentials
DB_CONNECTION=mysql
DB_HOST=localhost DB_HOST=localhost
DB_PORT=3306 DB_PORT=3306
DB_DATABASE=torrentpier DB_DATABASE=torrentpier

View file

@ -1,35 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

62
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View file

@ -0,0 +1,62 @@
name: Bug Report
description: File a bug report
title: "[Bug]"
labels: Bug
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
The more detailed this bug report is, the faster it can be reviewed and fixed.
- type: input
id: version-torrentpier
attributes:
label: TorrentPier Version
description: TorrentPier version your using?
placeholder: 2.4.0
validations:
required: true
- type: input
id: version-php-os
attributes:
label: PHP & Platform
description: Exact PHP and Platform (OS) versions your using.
placeholder: 8.1.2 - Ubuntu 22.04 x64
validations:
required: true
- type: checkboxes
id: requirements
attributes:
label: Have you done this?
options:
- label: I am willing to share my stack trace and logs
required: true
- label: I can suggest a fix as a Pull Request
required: false
- type: textarea
id: expectation
attributes:
label: Expectation
description: Write what you expect to (correctly) happen.
placeholder: When I do this, I expect to this to happen.
validations:
required: true
- type: textarea
id: description
attributes:
label: Description
description: Write what (incorrectly) happens instead.
placeholder: Instead, when I do this, I receive that.
validations:
required: true
- type: textarea
id: logs
attributes:
label: Stack trace & logs
description: |
If you have a stack trace, you can copy it here. You may hide sensitive information.
Including a stack trace when reporting an error 500 is required.
placeholder: This is automatically formatted into code, no need for backticks.
render: shell
validations:
required: false

View file

@ -0,0 +1,7 @@
---
name: Feature / Enhancement request
about: Suggest an idea for TorrentPier
title: "[Feature]"
labels: Feature, Enhancement
assignees: ''
---

View file

@ -1,17 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View file

@ -1,41 +0,0 @@
name: TorrentPier nightly builder
on:
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
- name: Install Composer dependencies
run: composer install --no-progress --prefer-dist --optimize-autoloader
- name: Get commit hash
id: get_commit_hash
run: |
COMMIT_HASH=$(git rev-parse --short HEAD)
echo "COMMIT_HASH=$COMMIT_HASH" >> $GITHUB_OUTPUT
- name: Create archive
id: create_zip
run: |
ZIP_NAME="torrentpier-${{ steps.get_commit_hash.outputs.COMMIT_HASH }}.zip"
zip -r "$ZIP_NAME" . -x ".git/*" ".github/*"
echo "ZIP_NAME=$ZIP_NAME" >> $GITHUB_OUTPUT
- name: Upload Archive
uses: actions/upload-artifact@v4
with:
name: TorrentPier
path: ${{ steps.create_zip.outputs.ZIP_NAME }}

83
.github/workflows/cd.yml vendored Normal file
View file

@ -0,0 +1,83 @@
name: Continuous Deployment
on:
push:
tags:
- "v*.*.*"
jobs:
generate-changelog:
name: Generate changelog
runs-on: ubuntu-22.04
outputs:
release_body: ${{ steps.git-cliff.outputs.content }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate a changelog
uses: orhun/git-cliff-action@v4
id: git-cliff
with:
config: cliff-releases.toml
args: -vv --latest --no-exec --github-repo ${{ github.repository }}
- name: Print the changelog
run: cat "${{ steps.git-cliff.outputs.changelog }}"
release:
name: Create release
needs: [ generate-changelog ]
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Set the release version
shell: bash
run: echo "RELEASE_VERSION=${GITHUB_REF:11}" >> $GITHUB_ENV
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
- name: Update composer.lock file
run: composer update --no-install
- name: Install Composer dependencies
run: composer install --no-progress --prefer-dist --optimize-autoloader
- name: Cleanup
run: php _cleanup.php && rm _cleanup.php
- name: Create archive
id: create-zip
run: |
ZIP_NAME="torrentpier-v${{ env.RELEASE_VERSION }}.zip"
zip -r "$ZIP_NAME" . -x ".git/*"
echo "ZIP_NAME=$ZIP_NAME" >> $GITHUB_OUTPUT
- name: Publish to GitHub
if: ${{ !contains(github.ref, '-') }}
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ${{ steps.create-zip.outputs.ZIP_NAME }}
overwrite: true
tag: ${{ github.ref }}
release_name: "v${{ env.RELEASE_VERSION }}"
body: "${{ needs.generate-changelog.outputs.release_body }}"
- name: Publish to GitHub (pre-release)
if: ${{ contains(github.ref, '-') }}
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ${{ steps.create-zip.outputs.ZIP_NAME }}
overwrite: true
tag: ${{ github.ref }}
release_name: "v${{ env.RELEASE_VERSION }}"
body: "${{ needs.generate-changelog.outputs.release_body }}"
prerelease: true

80
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,80 @@
name: Continuous Integration
on:
push:
branches:
- master
jobs:
nightly:
name: Nightly builds 📦
runs-on: ubuntu-22.04
steps:
- name: Checkout code 🗳
uses: actions/checkout@v4
- name: Setup PHP 🔩
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
- name: Update composer.lock file
run: composer update --no-install
- name: Install Composer dependencies 🪚
run: composer install --no-progress --prefer-dist --optimize-autoloader
- name: Get commit hash 🔗
id: get-commit-hash
run: |
COMMIT_HASH=$(git rev-parse --short HEAD)
echo "COMMIT_HASH=$COMMIT_HASH" >> $GITHUB_OUTPUT
- name: Cleanup
run: php _cleanup.php && rm _cleanup.php
- name: Create archive 🗞
id: create-zip
run: |
ZIP_NAME="torrentpier-${{ steps.get-commit-hash.outputs.COMMIT_HASH }}.zip"
zip -r "$ZIP_NAME" . -x ".git/*"
echo "ZIP_NAME=$ZIP_NAME" >> $GITHUB_OUTPUT
- name: Upload Archive 📤
uses: actions/upload-artifact@v4
with:
name: TorrentPier-master
path: ${{ steps.create-zip.outputs.ZIP_NAME }}
deploy:
name: 🎉 Deploy
runs-on: ubuntu-22.04
steps:
- name: 🚚 Get latest code
uses: actions/checkout@v4
- name: 🔩 Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
- name: Update composer.lock file
run: composer update --no-install
- name: 🖇 Install Composer dependencies
run: composer install --no-progress --prefer-dist --optimize-autoloader
- name: 📂 Sync files
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
with:
server: ${{ secrets.FTP_SERVER }}
username: ${{ secrets.FTP_USERNAME }}
password: ${{ secrets.FTP_PASSWORD }}
server-dir: ${{ secrets.FTP_DIR }}
protocol: ${{ secrets.FTP_PROTOCOL }}
port: ${{ secrets.FTP_PORT }}
exclude: |
**/.git*
**/.git*/**
.env

View file

@ -1,13 +1,14 @@
name: Changelog generation name: Changelog generation
on: on:
push: schedule:
branches: - cron: '0 0 * * *'
- master workflow_dispatch:
jobs: jobs:
changelog: changelog:
runs-on: ubuntu-latest name: Changelog generation
runs-on: ubuntu-22.04
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -32,8 +33,8 @@ jobs:
- name: Commit changelog - name: Commit changelog
run: | run: |
git checkout master git checkout master
git config user.name 'belomaxorka' git config --local user.name 'belomaxorka'
git config user.email 'roman25052006.kelesh@gmail.com' git config --local user.email 'roman25052006.kelesh@gmail.com'
set +e set +e
git add CHANGELOG.md git add CHANGELOG.md
git commit -m "Update CHANGELOG.md 📖" git commit -m "Update CHANGELOG.md 📖"

2
.gitignore vendored
View file

@ -4,8 +4,6 @@
### TorrentPier ### ### TorrentPier ###
*.log *.log
/*.txt
*.integrity
install.php_* install.php_*
composer-setup.php composer-setup.php
.env .env

View file

@ -6,6 +6,150 @@
### 🚀 Features ### 🚀 Features
- *(admin_smilies)* Added confirmation on smilie deleting ([#1895](https://github.com/torrentpier/torrentpier/pull/1895)) - ([b51820e](https://github.com/torrentpier/torrentpier/commit/b51820e1861044143321fcde5239c22abc3de984))
- *(freeipapi)* Added ability to use own API token ([#1901](https://github.com/torrentpier/torrentpier/pull/1901)) - ([513e306](https://github.com/torrentpier/torrentpier/commit/513e3065d34409931c4198c03b080f232f1d809b))
- Added ability to hide peer country in peer list ([#1891](https://github.com/torrentpier/torrentpier/pull/1891)) - ([2555ebc](https://github.com/torrentpier/torrentpier/commit/2555ebce4717f871922495e48cbca9e22da78bd5))
- Added ability to hide BitTorrent client in peers list ([#1890](https://github.com/torrentpier/torrentpier/pull/1890)) - ([f5d65b8](https://github.com/torrentpier/torrentpier/commit/f5d65b8911c5e864f000348a6d1aefbb4c09c2b4))
### 🐛 Bug Fixes
- Incorrect rounding in execution time counter ([#1899](https://github.com/torrentpier/torrentpier/pull/1899)) - ([781b724](https://github.com/torrentpier/torrentpier/commit/781b7240c41ddd141cfb057480c10d9cee30e6d7))
- `Undefined array key "smile"` when are no smilies ([#1896](https://github.com/torrentpier/torrentpier/pull/1896)) - ([36d3992](https://github.com/torrentpier/torrentpier/commit/36d399220e2c16a582e1e400df0002c164f5ec3b))
- Peer country flag not shown in peers list ([#1894](https://github.com/torrentpier/torrentpier/pull/1894)) - ([8edba72](https://github.com/torrentpier/torrentpier/commit/8edba72f09f037225ede058cf09c830b1a01e78f))
### 📦 Dependencies
- *(deps)* Bump symfony/polyfill from 1.31.0 to 1.32.0 ([#1900](https://github.com/torrentpier/torrentpier/pull/1900)) - ([a4793f6](https://github.com/torrentpier/torrentpier/commit/a4793f6ce103f22941d72793e2bf8cdf9f78d494))
### ⚙️ Miscellaneous
- Minor improvements ([#1898](https://github.com/torrentpier/torrentpier/pull/1898)) - ([2f02692](https://github.com/torrentpier/torrentpier/commit/2f026921ee331226900b3cd4f1bb238f6562b48d))
- Minor improvements ([#1897](https://github.com/torrentpier/torrentpier/pull/1897)) - ([14086a0](https://github.com/torrentpier/torrentpier/commit/14086a0ed6181a0ff4496ee2e56f4fb70bfe18d5))
- Minor improvements ([#1893](https://github.com/torrentpier/torrentpier/pull/1893)) - ([90ece5c](https://github.com/torrentpier/torrentpier/commit/90ece5c7621789f170246b2898841b347e264674))
- Minor improvements ([#1892](https://github.com/torrentpier/torrentpier/pull/1892)) - ([1e5b93d](https://github.com/torrentpier/torrentpier/commit/1e5b93d2c072c5c35feef7567b3fcdb4b3597935))
## [v2.4.5-rc.5](https://github.com/torrentpier/torrentpier/compare/v2.4.5-rc.4..v2.4.5-rc.5) (2025-05-03)
### 🚀 Features
- *(admin_ranks)* Added confirmation on rank deleting ([#1888](https://github.com/torrentpier/torrentpier/pull/1888)) - ([e510ebc](https://github.com/torrentpier/torrentpier/commit/e510ebc3ba30be7bf99769b1e5540353bd53c333))
- *(atom)* Hide topics from private forums ([#1889](https://github.com/torrentpier/torrentpier/pull/1889)) - ([75e9d5e](https://github.com/torrentpier/torrentpier/commit/75e9d5e4a8c5ec20f438e7b24a5469d219959a8c))
- *(avatar upload)* Added `accept="image/*"` attribute ([#1841](https://github.com/torrentpier/torrentpier/pull/1841)) - ([56d531a](https://github.com/torrentpier/torrentpier/commit/56d531aa5ddb778d08a2796fa9fb865e5b3040ce))
- *(emailer)* Added ability to configure `sendmail` - ([5ad4a70](https://github.com/torrentpier/torrentpier/commit/5ad4a7019d996d468650ab608ab53d6cf3ebb4f5))
- *(magnet)* Added `xl` (eXact Length) parametr ([#1883](https://github.com/torrentpier/torrentpier/pull/1883)) - ([c0cdcff](https://github.com/torrentpier/torrentpier/commit/c0cdcff48825ce5fb0c89c0ec44eb95686aee74c))
- *(playback_m3u.php)* Added checking auth to download ([#1848](https://github.com/torrentpier/torrentpier/pull/1848)) - ([0b8d8a5](https://github.com/torrentpier/torrentpier/commit/0b8d8a5210ee761dddaa57fc48bb48b0ede1ec3c))
### 🐛 Bug Fixes
- *(cache)* Implicitly marking parameter `$name` as nullable is deprecated ([#1877](https://github.com/torrentpier/torrentpier/pull/1877)) - ([c3b4000](https://github.com/torrentpier/torrentpier/commit/c3b40003b778a725e958cebee6446bcfd6a68b10))
- Displaying `Network news` and `Latest news` for guests when foums are private ([#1879](https://github.com/torrentpier/torrentpier/pull/1879)) - ([9f96090](https://github.com/torrentpier/torrentpier/commit/9f96090cc419f828e54e69a91a906a3f3d92c255))
- Pagination issue in `Report on action` page ([#1872](https://github.com/torrentpier/torrentpier/pull/1872)) - ([8358aa0](https://github.com/torrentpier/torrentpier/commit/8358aa00de2ec9efd4c51b8bef11bd700a56c19c))
- `tablesorting` issues & incorrect `user_role` for pending users ([#1871](https://github.com/torrentpier/torrentpier/pull/1871)) - ([595adbe](https://github.com/torrentpier/torrentpier/commit/595adbe4da5296b0f3ebde6628e58e878c0fb7d5))
- Fixed TorrentPier build-in emojis showing in ACP ([#1870](https://github.com/torrentpier/torrentpier/pull/1870)) - ([12792e7](https://github.com/torrentpier/torrentpier/commit/12792e74f71a57448277dda46471563a7fea71db))
### 📦 Dependencies
- *(deps)* Bump vlucas/phpdotenv from 5.6.1 to 5.6.2 ([#1887](https://github.com/torrentpier/torrentpier/pull/1887)) - ([7a14464](https://github.com/torrentpier/torrentpier/commit/7a14464d20fe8d2f8b980a82647c6b9ec081f621))
- *(deps)* Bump php-curl-class/php-curl-class from 11.1.0 to 12.0.0 ([#1868](https://github.com/torrentpier/torrentpier/pull/1868)) - ([bd5aa2a](https://github.com/torrentpier/torrentpier/commit/bd5aa2a5e71560409bc630ea2334e33c77458ab3))
- *(deps)* Bump monolog/monolog from 3.8.1 to 3.9.0 ([#1865](https://github.com/torrentpier/torrentpier/pull/1865)) - ([6440162](https://github.com/torrentpier/torrentpier/commit/64401621879af0cc445c38687c571d2fec184410))
- *(deps)* Bump php-curl-class/php-curl-class from 11.0.5 to 11.1.0 ([#1864](https://github.com/torrentpier/torrentpier/pull/1864)) - ([de2fcea](https://github.com/torrentpier/torrentpier/commit/de2fceabedefd07441ba6801417157a9828e0e2a))
- *(deps)* Bump egulias/email-validator from 4.0.3 to 4.0.4 ([#1858](https://github.com/torrentpier/torrentpier/pull/1858)) - ([3ced460](https://github.com/torrentpier/torrentpier/commit/3ced460640e4bfe27a91acd0408e73c3c49e1534))
- *(deps)* Bump filp/whoops from 2.17.0 to 2.18.0 ([#1853](https://github.com/torrentpier/torrentpier/pull/1853)) - ([7ca0582](https://github.com/torrentpier/torrentpier/commit/7ca058256186b7b690003308d660a3a6271e84d2))
- *(deps)* Bump php-curl-class/php-curl-class from 11.0.4 to 11.0.5 ([#1849](https://github.com/torrentpier/torrentpier/pull/1849)) - ([37ad07a](https://github.com/torrentpier/torrentpier/commit/37ad07a40c1adf29f712f469d2850753d32a5eb9))
- *(deps)* Bump belomaxorka/captcha from 1.2.3 to 1.2.4 - ([4641b0a](https://github.com/torrentpier/torrentpier/commit/4641b0a0d0e055d684ec36d41bfaf22b4d4b2ee1))
- *(deps)* Bump belomaxorka/captcha from 1.2.2 to 1.2.3 ([#1842](https://github.com/torrentpier/torrentpier/pull/1842)) - ([be65f7c](https://github.com/torrentpier/torrentpier/commit/be65f7c55cbf81d889d5083c9344ccef400e8e19))
### 🚜 Refactor
- Password generation ([#1847](https://github.com/torrentpier/torrentpier/pull/1847)) - ([af2403f](https://github.com/torrentpier/torrentpier/commit/af2403f1918845e8af3d9fa7708623eef6aa427e))
- Moved `Select` class into `Legacy\Common` ([#1846](https://github.com/torrentpier/torrentpier/pull/1846)) - ([bd0ef06](https://github.com/torrentpier/torrentpier/commit/bd0ef063fac328ed16537aacbc12e287a8d8206b))
### ⚙️ Miscellaneous
- *(.cliffignore)* Added one more commit ([#1860](https://github.com/torrentpier/torrentpier/pull/1860)) - ([974d359](https://github.com/torrentpier/torrentpier/commit/974d3590c1fb11c6314da4a4b8115a2229e32bbd))
- *(README)* Removed `Build actions` badge ([#1861](https://github.com/torrentpier/torrentpier/pull/1861)) - ([e9920ab](https://github.com/torrentpier/torrentpier/commit/e9920ab59803552e3a1a00b603962208a62efe4e))
- *(cliff)* Added `.cliffignore` file to ignore reverted commits ([#1859](https://github.com/torrentpier/torrentpier/pull/1859)) - ([2eab551](https://github.com/torrentpier/torrentpier/commit/2eab551bd75e7acfd6f4dabe13b2a30ac09db880))
- *(nightly builds)* Added cleanup step ([#1851](https://github.com/torrentpier/torrentpier/pull/1851)) - ([299d9a1](https://github.com/torrentpier/torrentpier/commit/299d9a1f6c4f244e435803212e763c252e5bd396))
- *(password_hash)* Changed `cost` to `12` by default ([#1886](https://github.com/torrentpier/torrentpier/pull/1886)) - ([1663e19](https://github.com/torrentpier/torrentpier/commit/1663e19c3f80ae15792d6ffe4ce64e40129b14db))
- *(render_flag)* Hide names for specified (`$nameIgnoreList`) flags ([#1862](https://github.com/torrentpier/torrentpier/pull/1862)) - ([83e42bc](https://github.com/torrentpier/torrentpier/commit/83e42bc5db086f60a6038b3fffca5982ceeced51))
- *(text captcha)* Disabled scatter effect by default - ([3af5202](https://github.com/torrentpier/torrentpier/commit/3af5202f7b2a4ea5d14bbc4808b7a380de2e0dc0))
- Updated nightly builds link ([#1885](https://github.com/torrentpier/torrentpier/pull/1885)) - ([6bd000b](https://github.com/torrentpier/torrentpier/commit/6bd000bc0d6176dbe1f0a573f081c9daefd3718b))
- Composer dependencies are installed according to the minimum supported PHP version ([#1884](https://github.com/torrentpier/torrentpier/pull/1884)) - ([5fe7700](https://github.com/torrentpier/torrentpier/commit/5fe770070e1cd71ea50ea3ad3825a322774f0baf))
- Corrected `php` version in `composer.json` ([#1882](https://github.com/torrentpier/torrentpier/pull/1882)) - ([bc1713a](https://github.com/torrentpier/torrentpier/commit/bc1713abdd28d04e8e1da3c3eabeb5170a35a460))
- Composer dependencies are installed according to the minimum supported PHP version ([#1881](https://github.com/torrentpier/torrentpier/pull/1881)) - ([5c4972e](https://github.com/torrentpier/torrentpier/commit/5c4972ec12340cbffb8ac941d390ee6c2c89b635))
- Minor improvements ([#1880](https://github.com/torrentpier/torrentpier/pull/1880)) - ([de8f192](https://github.com/torrentpier/torrentpier/commit/de8f1925bae3b38db18b86eb4a10337853638ad7))
- Minor improvements ([#1876](https://github.com/torrentpier/torrentpier/pull/1876)) - ([eeb391d](https://github.com/torrentpier/torrentpier/commit/eeb391da6a16440492a3b803f63be301ba3d02d3))
- Minor improvements ([#1875](https://github.com/torrentpier/torrentpier/pull/1875)) - ([41a78dd](https://github.com/torrentpier/torrentpier/commit/41a78ddbcbc628f0592c59879df0170bf48664aa))
- Minor improvements ([#1874](https://github.com/torrentpier/torrentpier/pull/1874)) - ([0f1a69e](https://github.com/torrentpier/torrentpier/commit/0f1a69e32d8d5eb5053b021844845911c619d8cd))
- Fetch only necessary sitemap parameters in `admin_sitemap.php` ([#1873](https://github.com/torrentpier/torrentpier/pull/1873)) - ([f9c8160](https://github.com/torrentpier/torrentpier/commit/f9c8160f8e897950a038a74ad7ee30b116f7b2b8))
- Changed placeholder IP address from `7f000001` to `0` ([#1869](https://github.com/torrentpier/torrentpier/pull/1869)) - ([84e2392](https://github.com/torrentpier/torrentpier/commit/84e23928968f943826bdc4390c52365357d56f32))
- Minor improvements ([#1866](https://github.com/torrentpier/torrentpier/pull/1866)) - ([7237653](https://github.com/torrentpier/torrentpier/commit/72376532b32395eda04dc032c07ca08b27346c6b))
- Some minor improvements ([#1855](https://github.com/torrentpier/torrentpier/pull/1855)) - ([3cc880e](https://github.com/torrentpier/torrentpier/commit/3cc880eeb8be41596d5e8eaf19297046500afcf7))
### ◀️ Revert
- Added `TorrentPier instance hash` generation - ([eabf851](https://github.com/torrentpier/torrentpier/commit/eabf851ee60d29835d1979f46dcf2b9d82576c1b))
- Added `IndexNow` protocol support 🤖 - ([1b288a9](https://github.com/torrentpier/torrentpier/commit/1b288a96e443e06c4f4e9ea374037d3b0af8a639))
## [v2.4.5-rc.4](https://github.com/torrentpier/torrentpier/compare/v2.4.5-rc.3..v2.4.5-rc.4) (2025-03-09)
### 🚀 Features
- *(captcha)* Added `Text Captcha` provider ([#1839](https://github.com/torrentpier/torrentpier/pull/1839)) - ([74ea157](https://github.com/torrentpier/torrentpier/commit/74ea1573b298be5a935caaca0b3cc57cb1e9264a))
- *(show post bbcode)* Added `'only_for_first_post'` param ([#1830](https://github.com/torrentpier/torrentpier/pull/1830)) - ([4dcd1fb](https://github.com/torrentpier/torrentpier/commit/4dcd1fb16e4e84acd1231ad821a2f05658b849ad))
- *(sitemap)* Update `lastmod` when a new reply in topic ([#1737](https://github.com/torrentpier/torrentpier/pull/1737)) - ([bc95e14](https://github.com/torrentpier/torrentpier/commit/bc95e14be328303bb37e31299661b03045e37d07))
- Added `$bb_cfg['auto_language_detection']` parametr ([#1835](https://github.com/torrentpier/torrentpier/pull/1835)) - ([b550fa5](https://github.com/torrentpier/torrentpier/commit/b550fa59f9ee96ca89e5b6db880147bc72841e93))
- Easter egg for the 20th anniversary of the TorrentPier! ([#1831](https://github.com/torrentpier/torrentpier/pull/1831)) - ([f2e513d](https://github.com/torrentpier/torrentpier/commit/f2e513dd8b0f82f4f02474db4b83d83904a93f29))
- Added configuration files for `nginx` & `caddy` ([#1787](https://github.com/torrentpier/torrentpier/pull/1787)) - ([f7d3946](https://github.com/torrentpier/torrentpier/commit/f7d394607e4ea5bb9b7f2b33692204a226a4d78b))
### 🐛 Bug Fixes
- *(info.php)* Undefined array key "show" ([#1836](https://github.com/torrentpier/torrentpier/pull/1836)) - ([f8c4e8f](https://github.com/torrentpier/torrentpier/commit/f8c4e8fb14090bc7403f24e363603bad9e231351))
- *(tr_seed_bonus.php)* Incorrect `GROUP BY` ([#1820](https://github.com/torrentpier/torrentpier/pull/1820)) - ([dfd4e5e](https://github.com/torrentpier/torrentpier/commit/dfd4e5ebc9df916868210a7844f2a6f35e7b8aca))
### 📦 Dependencies
- *(deps)* Bump bugsnag/bugsnag from 3.29.2 to 3.29.3 ([#1837](https://github.com/torrentpier/torrentpier/pull/1837)) - ([b954815](https://github.com/torrentpier/torrentpier/commit/b954815f5d0dce9520f65679e834d8bd49e571e0))
- *(deps)* Bump php-curl-class/php-curl-class from 11.0.3 to 11.0.4 ([#1823](https://github.com/torrentpier/torrentpier/pull/1823)) - ([1c323a4](https://github.com/torrentpier/torrentpier/commit/1c323a45d777b033155da9a2becec506215bd94c))
- *(deps)* Bump php-curl-class/php-curl-class from 11.0.1 to 11.0.3 ([#1821](https://github.com/torrentpier/torrentpier/pull/1821)) - ([dedf35b](https://github.com/torrentpier/torrentpier/commit/dedf35b794196034eb27d4125dff0798aed5f315))
### 🗑️ Removed
- *(posting.php)* Unused `'U_VIEWTOPIC` variable ([#1818](https://github.com/torrentpier/torrentpier/pull/1818)) - ([03ebbda](https://github.com/torrentpier/torrentpier/commit/03ebbda6be567d82d2a49fefe02356544fbd07cb))
- Integrity checker 🥺🪦 ([#1827](https://github.com/torrentpier/torrentpier/pull/1827)) - ([ba3ce88](https://github.com/torrentpier/torrentpier/commit/ba3ce885c8d84ae939a0ce9c79b97877d3aaab41))
- Redundant `.htaccess` files ([#1826](https://github.com/torrentpier/torrentpier/pull/1826)) - ([912b080](https://github.com/torrentpier/torrentpier/commit/912b080b16438b09f82fbc72a363589cc2f6209e))
### ⚙️ Miscellaneous
- *(Caddyfile)* Some minor fixes ([#1822](https://github.com/torrentpier/torrentpier/pull/1822)) - ([6f641aa](https://github.com/torrentpier/torrentpier/commit/6f641aa9d8d7afb30920c054a43347393ea05cc4))
- *(README)* Fixed all grammatical errors, sentence structure and readibility ([#1812](https://github.com/torrentpier/torrentpier/pull/1812)) - ([bea3b0b](https://github.com/torrentpier/torrentpier/commit/bea3b0bccf335970ea5826543d8fa223329ef077))
- *(_cleanup.php)* Added CLI mode check ([#1834](https://github.com/torrentpier/torrentpier/pull/1834)) - ([5dc9a54](https://github.com/torrentpier/torrentpier/commit/5dc9a5475c051911c579ea732ef52d7feb78e8ac))
- *(announcer)* Some minor improvements ([#1819](https://github.com/torrentpier/torrentpier/pull/1819)) - ([bdefed4](https://github.com/torrentpier/torrentpier/commit/bdefed4dab3cc65330fcb9cb9750cc8e84beda1d))
- *(cliff)* Removed TorrentPier logo ([#1817](https://github.com/torrentpier/torrentpier/pull/1817)) - ([7794242](https://github.com/torrentpier/torrentpier/commit/7794242750b44183312a2a45c9f54c6afde12f0e))
- *(cliff)* Synced `cliff-releases.toml` with `cliff.toml` changes ([#1815](https://github.com/torrentpier/torrentpier/pull/1815)) - ([f2aea92](https://github.com/torrentpier/torrentpier/commit/f2aea92b3d79d72254e696fde31ad9b4bec5dcd0))
- *(cliff)* Added missing line breaks after `body` ([#1814](https://github.com/torrentpier/torrentpier/pull/1814)) - ([2593f09](https://github.com/torrentpier/torrentpier/commit/2593f093a389a9c450725290862b99d911fbef5d))
- *(installer)* Added cleanup step (for master builds) ([#1838](https://github.com/torrentpier/torrentpier/pull/1838)) - ([dd72136](https://github.com/torrentpier/torrentpier/commit/dd721367c7dc9956861fcd33af7f9f822cf80011))
- *(installer)* Some minor improvements ([#1825](https://github.com/torrentpier/torrentpier/pull/1825)) - ([4f89685](https://github.com/torrentpier/torrentpier/commit/4f896854d3bb67300027f7542704f41c4869837f))
- *(installer)* Some minor improvements ([#1824](https://github.com/torrentpier/torrentpier/pull/1824)) - ([f3714f0](https://github.com/torrentpier/torrentpier/commit/f3714f02f2c8fbfaccfdafb8f25a269664c48950))
- *(workflow)* Short `release_name` ([#1816](https://github.com/torrentpier/torrentpier/pull/1816)) - ([c57db21](https://github.com/torrentpier/torrentpier/commit/c57db2104d7b8363d0b8ce8872ce90fc7410c724))
- *(workflow)* Added `workflow_dispatch` for `schedule.yml` ([#1813](https://github.com/torrentpier/torrentpier/pull/1813)) - ([d54c07b](https://github.com/torrentpier/torrentpier/commit/d54c07b3da00fc8bcba5413cd4ae3f3c9f6007bb))
- *(workflow)* Some improvements ([#1811](https://github.com/torrentpier/torrentpier/pull/1811)) - ([3a9dd6a](https://github.com/torrentpier/torrentpier/commit/3a9dd6a3c931cfbd682257c283a3296c4914548f))
- *(workflow)* Some improvements ([#1810](https://github.com/torrentpier/torrentpier/pull/1810)) - ([c168c39](https://github.com/torrentpier/torrentpier/commit/c168c3956cf77886c14133ac10ec33aa0ae5bc4e))
- Replaced `gregwar/captcha` with my own fork ([#1840](https://github.com/torrentpier/torrentpier/pull/1840)) - ([8585560](https://github.com/torrentpier/torrentpier/commit/858556043d3e45218ea8e803786d6b6de6d485d0))
- Created cleanup script (for releases preparation) ([#1833](https://github.com/torrentpier/torrentpier/pull/1833)) - ([68bf26d](https://github.com/torrentpier/torrentpier/commit/68bf26d0f4ab33f5394d26f425e53817f3464ac8))
- Bring back missing `cache` & `log` directories ([#1832](https://github.com/torrentpier/torrentpier/pull/1832)) - ([249c988](https://github.com/torrentpier/torrentpier/commit/249c9889890291d56317dd703414bdb57ecaa41f))
- Some minor improvements ([#1829](https://github.com/torrentpier/torrentpier/pull/1829)) - ([3b8ee4c](https://github.com/torrentpier/torrentpier/commit/3b8ee4c4d3ab4631425fbe44f197b6a9bd7d158c))
## New Contributors ❤️
* @xeddmc made their first contribution in [#1812](https://github.com/torrentpier/torrentpier/pull/1812)
## [v2.4.5-rc.3](https://github.com/torrentpier/torrentpier/compare/v2.4.5-rc.2..v2.4.5-rc.3) (2025-02-06)
### 🚀 Features
- *(announcer)* Added some disallowed ports by default ([#1767](https://github.com/torrentpier/torrentpier/pull/1767)) - ([46288ec](https://github.com/torrentpier/torrentpier/commit/46288ec19830c84aedb156e1f30d7ec8a0803e0d)) - *(announcer)* Added some disallowed ports by default ([#1767](https://github.com/torrentpier/torrentpier/pull/1767)) - ([46288ec](https://github.com/torrentpier/torrentpier/commit/46288ec19830c84aedb156e1f30d7ec8a0803e0d))
- *(announcer)* Added `is_numeric()` checking for some fields ([#1766](https://github.com/torrentpier/torrentpier/pull/1766)) - ([096bb51](https://github.com/torrentpier/torrentpier/commit/096bb5124fa27d27c3e60031edc432d877f1c507)) - *(announcer)* Added `is_numeric()` checking for some fields ([#1766](https://github.com/torrentpier/torrentpier/pull/1766)) - ([096bb51](https://github.com/torrentpier/torrentpier/commit/096bb5124fa27d27c3e60031edc432d877f1c507))
- *(announcer)* Added `event` verifying ([#1765](https://github.com/torrentpier/torrentpier/pull/1765)) - ([6a19323](https://github.com/torrentpier/torrentpier/commit/6a1932313801e55fbcfb047fdcef87266f472c33)) - *(announcer)* Added `event` verifying ([#1765](https://github.com/torrentpier/torrentpier/pull/1765)) - ([6a19323](https://github.com/torrentpier/torrentpier/commit/6a1932313801e55fbcfb047fdcef87266f472c33))
@ -13,27 +157,36 @@
- *(announcer)* Block `User-Agent` strings that are too long ([#1763](https://github.com/torrentpier/torrentpier/pull/1763)) - ([a98f8f1](https://github.com/torrentpier/torrentpier/commit/a98f8f102a8253b0b22c80ef444fed1ec29177f3)) - *(announcer)* Block `User-Agent` strings that are too long ([#1763](https://github.com/torrentpier/torrentpier/pull/1763)) - ([a98f8f1](https://github.com/torrentpier/torrentpier/commit/a98f8f102a8253b0b22c80ef444fed1ec29177f3))
- *(announcer)* Blocking all ports lower then `1024` ([#1762](https://github.com/torrentpier/torrentpier/pull/1762)) - ([1bc7e09](https://github.com/torrentpier/torrentpier/commit/1bc7e09ddbeaf680b86095eed9a80b8ebf6169b3)) - *(announcer)* Blocking all ports lower then `1024` ([#1762](https://github.com/torrentpier/torrentpier/pull/1762)) - ([1bc7e09](https://github.com/torrentpier/torrentpier/commit/1bc7e09ddbeaf680b86095eed9a80b8ebf6169b3))
- *(cache)* Checking if extensions are installed ([#1759](https://github.com/torrentpier/torrentpier/pull/1759)) - ([7f31022](https://github.com/torrentpier/torrentpier/commit/7f31022cfca2acb28a5cba06961eeaf8d2c9de51)) - *(cache)* Checking if extensions are installed ([#1759](https://github.com/torrentpier/torrentpier/pull/1759)) - ([7f31022](https://github.com/torrentpier/torrentpier/commit/7f31022cfca2acb28a5cba06961eeaf8d2c9de51))
- *(captcha)* Added some new services 🤖 ([#1771](https://github.com/torrentpier/torrentpier/pull/1771)) - ([d413c71](https://github.com/torrentpier/torrentpier/commit/d413c717188c9bd906f715e7137955dc9a42a003))
- *(environment)* Make configurable `TP_HOST` and `TP_PORT` ([#1780](https://github.com/torrentpier/torrentpier/pull/1780)) - ([e51e091](https://github.com/torrentpier/torrentpier/commit/e51e09159333382a77b809b5f1da5e152a713143))
- *(installer)* Fully show non-installed extensions ([#1761](https://github.com/torrentpier/torrentpier/pull/1761)) - ([8fcc62d](https://github.com/torrentpier/torrentpier/commit/8fcc62d2a2fd41927b2f5dae215fe5bbf95f2c96)) - *(installer)* Fully show non-installed extensions ([#1761](https://github.com/torrentpier/torrentpier/pull/1761)) - ([8fcc62d](https://github.com/torrentpier/torrentpier/commit/8fcc62d2a2fd41927b2f5dae215fe5bbf95f2c96))
- *(installer)* More explanations ([#1758](https://github.com/torrentpier/torrentpier/pull/1758)) - ([48ab52a](https://github.com/torrentpier/torrentpier/commit/48ab52ac8674afcb607c8e49134316a3e117236a)) - *(installer)* More explanations ([#1758](https://github.com/torrentpier/torrentpier/pull/1758)) - ([48ab52a](https://github.com/torrentpier/torrentpier/commit/48ab52ac8674afcb607c8e49134316a3e117236a))
- *(installer)* Check `Composer` dependencies after installing ([#1756](https://github.com/torrentpier/torrentpier/pull/1756)) - ([262b887](https://github.com/torrentpier/torrentpier/commit/262b8872a5b14068eb73d745adea6203c557e192)) - *(installer)* Check `Composer` dependencies after installing ([#1756](https://github.com/torrentpier/torrentpier/pull/1756)) - ([262b887](https://github.com/torrentpier/torrentpier/commit/262b8872a5b14068eb73d745adea6203c557e192))
- *(installer)* More explanations ([#1754](https://github.com/torrentpier/torrentpier/pull/1754)) - ([fd6f1f8](https://github.com/torrentpier/torrentpier/commit/fd6f1f86a5e9216469cd648601ecb9ba875f9eb6)) - *(installer)* More explanations ([#1754](https://github.com/torrentpier/torrentpier/pull/1754)) - ([fd6f1f8](https://github.com/torrentpier/torrentpier/commit/fd6f1f86a5e9216469cd648601ecb9ba875f9eb6))
- *(installer)* Create `config.local.php` on local environment ([#1745](https://github.com/torrentpier/torrentpier/pull/1745)) - ([0d93b2c](https://github.com/torrentpier/torrentpier/commit/0d93b2c768c2965c12ac62e2f3b2886dc1ef31c2)) - *(installer)* Create `config.local.php` on local environment ([#1745](https://github.com/torrentpier/torrentpier/pull/1745)) - ([0d93b2c](https://github.com/torrentpier/torrentpier/commit/0d93b2c768c2965c12ac62e2f3b2886dc1ef31c2))
- *(torrent)* Bring back old torrent file naming ([#1783](https://github.com/torrentpier/torrentpier/pull/1783)) - ([314c592](https://github.com/torrentpier/torrentpier/commit/314c592affbef4b8db48d562b9633aad27059a76))
- *(workflow)* Automated deploy actual changes to `TorrentPier Demo` ([#1788](https://github.com/torrentpier/torrentpier/pull/1788)) - ([4333d6a](https://github.com/torrentpier/torrentpier/commit/4333d6aca4aeb8584ff8a8ef0bf76c537a3f371a))
- Used `TORRENT_MIMETYPE` constant instead of hardcoded string ([#1757](https://github.com/torrentpier/torrentpier/pull/1757)) - ([4b0d270](https://github.com/torrentpier/torrentpier/commit/4b0d270c89ec06abed590504f6a0cb70076a9e59)) - Used `TORRENT_MIMETYPE` constant instead of hardcoded string ([#1757](https://github.com/torrentpier/torrentpier/pull/1757)) - ([4b0d270](https://github.com/torrentpier/torrentpier/commit/4b0d270c89ec06abed590504f6a0cb70076a9e59))
### 🐛 Bug Fixes ### 🐛 Bug Fixes
- *(announcer)* Null `event` exception ([#1784](https://github.com/torrentpier/torrentpier/pull/1784)) - ([b06e327](https://github.com/torrentpier/torrentpier/commit/b06e327cbb285a676814699eb5fb1fbc0e1f22e8))
- *(bb_die)* HTML characters converting ([#1744](https://github.com/torrentpier/torrentpier/pull/1744)) - ([4f1c7e4](https://github.com/torrentpier/torrentpier/commit/4f1c7e40d82e52f81eba44ead501e1f01058cc4f)) - *(bb_die)* HTML characters converting ([#1744](https://github.com/torrentpier/torrentpier/pull/1744)) - ([4f1c7e4](https://github.com/torrentpier/torrentpier/commit/4f1c7e40d82e52f81eba44ead501e1f01058cc4f))
- *(debug)* Disabled `Bugsnag` reporting on local environment ([#1751](https://github.com/torrentpier/torrentpier/pull/1751)) - ([1f3b629](https://github.com/torrentpier/torrentpier/commit/1f3b629e9cea4d11fbf3cf29f575ba730bad898d)) - *(debug)* Disabled `Bugsnag` reporting on local environment ([#1751](https://github.com/torrentpier/torrentpier/pull/1751)) - ([1f3b629](https://github.com/torrentpier/torrentpier/commit/1f3b629e9cea4d11fbf3cf29f575ba730bad898d))
- *(installer)* Missing `gd` extension ([#1749](https://github.com/torrentpier/torrentpier/pull/1749)) - ([a1c519d](https://github.com/torrentpier/torrentpier/commit/a1c519d938b848edffcbf7fbbe6a3fdb9a5394f1)) - *(installer)* Missing `gd` extension ([#1749](https://github.com/torrentpier/torrentpier/pull/1749)) - ([a1c519d](https://github.com/torrentpier/torrentpier/commit/a1c519d938b848edffcbf7fbbe6a3fdb9a5394f1))
- *(youtube player)* Mixed content issue ([#1795](https://github.com/torrentpier/torrentpier/pull/1795)) - ([3c0a1d5](https://github.com/torrentpier/torrentpier/commit/3c0a1d5d0018daa87ad3914ea04078a9a6d05fc2))
- Incorrect peer country flag ([#1768](https://github.com/torrentpier/torrentpier/pull/1768)) - ([0f091eb](https://github.com/torrentpier/torrentpier/commit/0f091eb546e34923d9d1ab34be5faf92080ec198)) - Incorrect peer country flag ([#1768](https://github.com/torrentpier/torrentpier/pull/1768)) - ([0f091eb](https://github.com/torrentpier/torrentpier/commit/0f091eb546e34923d9d1ab34be5faf92080ec198))
### 📦 Dependencies ### 📦 Dependencies
- *(deps)* Bump jacklul/monolog-telegram from 3.1.0 to 3.2.0 ([#1776](https://github.com/torrentpier/torrentpier/pull/1776)) - ([420c92c](https://github.com/torrentpier/torrentpier/commit/420c92c0addf4dee91f3ae872517cb3224827a1f))
- *(deps)* Bump filp/whoops from 2.16.0 to 2.17.0 ([#1777](https://github.com/torrentpier/torrentpier/pull/1777)) - ([a71609b](https://github.com/torrentpier/torrentpier/commit/a71609ba67a89480fabb7b62de450d9be09373fa))
- *(deps)* Bump php-curl-class/php-curl-class from 11.0.0 to 11.0.1 ([#1753](https://github.com/torrentpier/torrentpier/pull/1753)) - ([ce32031](https://github.com/torrentpier/torrentpier/commit/ce32031a0fb14cdf6c3f4ba379b530cbb52b0fea)) - *(deps)* Bump php-curl-class/php-curl-class from 11.0.0 to 11.0.1 ([#1753](https://github.com/torrentpier/torrentpier/pull/1753)) - ([ce32031](https://github.com/torrentpier/torrentpier/commit/ce32031a0fb14cdf6c3f4ba379b530cbb52b0fea))
- *(deps)* Bump bugsnag/bugsnag from 3.29.1 to 3.29.2 ([#1752](https://github.com/torrentpier/torrentpier/pull/1752)) - ([f63d15c](https://github.com/torrentpier/torrentpier/commit/f63d15c49e3992837413b2c7a0160d599b44f2ef)) - *(deps)* Bump bugsnag/bugsnag from 3.29.1 to 3.29.2 ([#1752](https://github.com/torrentpier/torrentpier/pull/1752)) - ([f63d15c](https://github.com/torrentpier/torrentpier/commit/f63d15c49e3992837413b2c7a0160d599b44f2ef))
### 🗑️ Removed ### 🗑️ Removed
- *(environment)* Extra `DB_CONNECTION` variable ([#1775](https://github.com/torrentpier/torrentpier/pull/1775)) - ([cd2786b](https://github.com/torrentpier/torrentpier/commit/cd2786bb69c74cec88a447f66750d014fc4d3612))
- Some unused tracker config variables ([#1769](https://github.com/torrentpier/torrentpier/pull/1769)) - ([7f9df35](https://github.com/torrentpier/torrentpier/commit/7f9df35d3bd0e9d23284b8bd9c36a0f52158f5d7)) - Some unused tracker config variables ([#1769](https://github.com/torrentpier/torrentpier/pull/1769)) - ([7f9df35](https://github.com/torrentpier/torrentpier/commit/7f9df35d3bd0e9d23284b8bd9c36a0f52158f5d7))
### 📚 Documentation ### 📚 Documentation
@ -42,12 +195,38 @@
### ⚙️ Miscellaneous ### ⚙️ Miscellaneous
- *(cd workflow)* Fixed release body creation ([#1809](https://github.com/torrentpier/torrentpier/pull/1809)) - ([7378cb3](https://github.com/torrentpier/torrentpier/commit/7378cb3af5cc56343c667a9d920038b05327e97b))
- *(cd workflow)* Fixed release body creation ([#1807](https://github.com/torrentpier/torrentpier/pull/1807)) - ([cc679a8](https://github.com/torrentpier/torrentpier/commit/cc679a80246f3ff65136653025d826bf1458db3a))
- *(changelog workflow)* Minor improvements ([#1802](https://github.com/torrentpier/torrentpier/pull/1802)) - ([15ca21f](https://github.com/torrentpier/torrentpier/commit/15ca21f03840281f7d4402959aa8bfb7d407b45b))
- *(checksum workflow)* Fixed incorrect file path ([#1799](https://github.com/torrentpier/torrentpier/pull/1799)) - ([4eb5a9a](https://github.com/torrentpier/torrentpier/commit/4eb5a9adc61c4e116feb09208091efb914275da2))
- *(cliff)* Changed emoji for dependencies ([#1755](https://github.com/torrentpier/torrentpier/pull/1755)) - ([55d4670](https://github.com/torrentpier/torrentpier/commit/55d467048370b51cd592982c8026702dca8813d5)) - *(cliff)* Changed emoji for dependencies ([#1755](https://github.com/torrentpier/torrentpier/pull/1755)) - ([55d4670](https://github.com/torrentpier/torrentpier/commit/55d467048370b51cd592982c8026702dca8813d5))
- *(cliff)* Use blockquote for notice ([#1748](https://github.com/torrentpier/torrentpier/pull/1748)) - ([61e5592](https://github.com/torrentpier/torrentpier/commit/61e55925f312417bdb63c88a7c8939c3b2eb2ac5)) - *(cliff)* Use blockquote for notice ([#1748](https://github.com/torrentpier/torrentpier/pull/1748)) - ([61e5592](https://github.com/torrentpier/torrentpier/commit/61e55925f312417bdb63c88a7c8939c3b2eb2ac5))
- *(cliff)* Fixed typo ([#1747](https://github.com/torrentpier/torrentpier/pull/1747)) - ([4936af7](https://github.com/torrentpier/torrentpier/commit/4936af7d3d10f553d8586a14de249c32e50f3494)) - *(cliff)* Fixed typo ([#1747](https://github.com/torrentpier/torrentpier/pull/1747)) - ([4936af7](https://github.com/torrentpier/torrentpier/commit/4936af7d3d10f553d8586a14de249c32e50f3494))
- *(cliff)* Notice about previous changelog file ([#1746](https://github.com/torrentpier/torrentpier/pull/1746)) - ([85395be](https://github.com/torrentpier/torrentpier/commit/85395be5e7c6a891c79ec72cf215894af097f819)) - *(cliff)* Notice about previous changelog file ([#1746](https://github.com/torrentpier/torrentpier/pull/1746)) - ([85395be](https://github.com/torrentpier/torrentpier/commit/85395be5e7c6a891c79ec72cf215894af097f819))
- *(copyright)* Updated copyright year ([#1760](https://github.com/torrentpier/torrentpier/pull/1760)) - ([6697410](https://github.com/torrentpier/torrentpier/commit/6697410c1df6c8d9d7f511b1e984ae90d888ae0e)) - *(copyright)* Updated copyright year ([#1760](https://github.com/torrentpier/torrentpier/pull/1760)) - ([6697410](https://github.com/torrentpier/torrentpier/commit/6697410c1df6c8d9d7f511b1e984ae90d888ae0e))
- *(database)* Use `DEFAULT ''` for `privmsgs_subject` ([#1786](https://github.com/torrentpier/torrentpier/pull/1786)) - ([387a258](https://github.com/torrentpier/torrentpier/commit/387a25870abd37b641b55ffd98e13f4aaecb73b1))
- *(deploy action)* Specify some missing params ([#1789](https://github.com/torrentpier/torrentpier/pull/1789)) - ([6115900](https://github.com/torrentpier/torrentpier/commit/6115900b765752209a6ed1dfb83e4f0cbee2ae77))
- *(emailer)* Use constants for email types ([#1794](https://github.com/torrentpier/torrentpier/pull/1794)) - ([c95d414](https://github.com/torrentpier/torrentpier/commit/c95d414ef63ca37118f1f660880cd58b4480c414))
- *(integrity checker)* Disabled by default in `Demo mode` ([#1804](https://github.com/torrentpier/torrentpier/pull/1804)) - ([44be40c](https://github.com/torrentpier/torrentpier/commit/44be40c2e849c60eb4f10ca7e0bae0463791355e))
- *(integrity checker)* Some enhancements ([#1797](https://github.com/torrentpier/torrentpier/pull/1797)) - ([09cafc2](https://github.com/torrentpier/torrentpier/commit/09cafc2285dd171cb2213ece9549993a3321527c))
- *(issue template)* Improved `Feature request` template ([#1774](https://github.com/torrentpier/torrentpier/pull/1774)) - ([268f79d](https://github.com/torrentpier/torrentpier/commit/268f79d7259de67aa8877fcf7130ff0069469ab2))
- *(issue template)* Improved `Bug report` template ([#1773](https://github.com/torrentpier/torrentpier/pull/1773)) - ([53ebfef](https://github.com/torrentpier/torrentpier/commit/53ebfef32c0e9016257e03b96ef96349e22d3e9b))
- *(notify)* Hide notify checkbox in topic for guests ([#1793](https://github.com/torrentpier/torrentpier/pull/1793)) - ([8e4cd97](https://github.com/torrentpier/torrentpier/commit/8e4cd97734fc46f33459c4b00a0fe38b0597f92b))
- *(readme)* Improved installation guide ([#1781](https://github.com/torrentpier/torrentpier/pull/1781)) - ([e579b81](https://github.com/torrentpier/torrentpier/commit/e579b816b4dc346b3242cb3d9db292ad05596c1f))
- *(readme)* Minor improvements ([#1779](https://github.com/torrentpier/torrentpier/pull/1779)) - ([5b0ed02](https://github.com/torrentpier/torrentpier/commit/5b0ed020890a8f938df912f9215cccbda42b0317))
- *(readme)* Added Caddy webserver ([#1778](https://github.com/torrentpier/torrentpier/pull/1778)) - ([970a028](https://github.com/torrentpier/torrentpier/commit/970a0282e3631c403029c959ffd46b21c5cad0cd))
- *(workflow)* Refactored all workflows ([#1803](https://github.com/torrentpier/torrentpier/pull/1803)) - ([a29d57b](https://github.com/torrentpier/torrentpier/commit/a29d57b2f8673733bbfbea3fb96eebe841078d49))
- *(workflow)* Trying combine `changelog workflow` with `checksums workflow` ([#1800](https://github.com/torrentpier/torrentpier/pull/1800)) - ([60c6057](https://github.com/torrentpier/torrentpier/commit/60c605778412335ce97d41489c3b6ee9c051454b))
- Automated releases generation ([#1808](https://github.com/torrentpier/torrentpier/pull/1808)) - ([6c9372c](https://github.com/torrentpier/torrentpier/commit/6c9372c407327c9bb443b2ecf16eff64c0245c4b))
- Automated releases generation ([#1806](https://github.com/torrentpier/torrentpier/pull/1806)) - ([bc74550](https://github.com/torrentpier/torrentpier/commit/bc745502940207f3f24c83057cd680fe69355961))
- Automated releases generation ([#1805](https://github.com/torrentpier/torrentpier/pull/1805)) - ([425e2e8](https://github.com/torrentpier/torrentpier/commit/425e2e87d5a7f097b961b1a14fbafcdabb9d1666))
- Minor improvements ([#1796](https://github.com/torrentpier/torrentpier/pull/1796)) - ([8650ad3](https://github.com/torrentpier/torrentpier/commit/8650ad30f429ab14a03f44b26d7be7701f1985f1))
- Update `cliff.toml` - ([254dca2](https://github.com/torrentpier/torrentpier/commit/254dca2b27c2d92421d3e639c80b0adf1172202f)) - Update `cliff.toml` - ([254dca2](https://github.com/torrentpier/torrentpier/commit/254dca2b27c2d92421d3e639c80b0adf1172202f))
- Minor improvements ([#1743](https://github.com/torrentpier/torrentpier/pull/1743)) - ([e73d650](https://github.com/torrentpier/torrentpier/commit/e73d65011fff0a8b8e1368eef61bbfb67e87eab8)) - Minor improvements ([#1743](https://github.com/torrentpier/torrentpier/pull/1743)) - ([e73d650](https://github.com/torrentpier/torrentpier/commit/e73d65011fff0a8b8e1368eef61bbfb67e87eab8))
- Enabled `$bb_cfg['integrity_check']` by defaul ([#1742](https://github.com/torrentpier/torrentpier/pull/1742)) - ([7e3601e](https://github.com/torrentpier/torrentpier/commit/7e3601e63aff73be1428969ca37dda3da2537d9b)) - Enabled `$bb_cfg['integrity_check']` by defaul ([#1742](https://github.com/torrentpier/torrentpier/pull/1742)) - ([7e3601e](https://github.com/torrentpier/torrentpier/commit/7e3601e63aff73be1428969ca37dda3da2537d9b))
## New Contributors ❤️
* @actions-user made their first contribution
<!-- generated by git-cliff --> <!-- generated by git-cliff -->

View file

@ -8,29 +8,29 @@
<p align="center"> <p align="center">
<a href="https://github.com/torrentpier/torrentpier/blob/master/LICENSE"><img src="https://img.shields.io/github/license/torrentpier/torrentpier" alt="License"></a> <a href="https://github.com/torrentpier/torrentpier/blob/master/LICENSE"><img src="https://img.shields.io/github/license/torrentpier/torrentpier" alt="License"></a>
<a href="https://packagist.org/packages/torrentpier/torrentpier"><img src="https://img.shields.io/packagist/stars/torrentpier/torrentpier" alt="Stars Packagist"></a> <a href="https://packagist.org/packages/torrentpier/torrentpier"><img src="https://img.shields.io/packagist/stars/torrentpier/torrentpier" alt="Stars Packagist"></a>
<a href="https://github.com/torrentpier/torrentpier/actions"><img src="https://img.shields.io/github/actions/workflow/status/torrentpier/torrentpier/phpmd.yml" alt="Build status"></a>
<a href="https://crowdin.com/project/torrentpier"><img src="https://badges.crowdin.net/torrentpier/localized.svg" alt="Crowdin"></a> <a href="https://crowdin.com/project/torrentpier"><img src="https://badges.crowdin.net/torrentpier/localized.svg" alt="Crowdin"></a>
<a href="https://nightly.link/torrentpier/torrentpier/workflows/build/master/TorrentPier"><img src="https://img.shields.io/badge/Nightly%20release-gray?logo=hackthebox&logoColor=fff" alt="TorrentPier nightly"></a> <a href="https://nightly.link/torrentpier/torrentpier/workflows/ci/master/TorrentPier-master"><img src="https://img.shields.io/badge/Nightly%20release-gray?logo=hackthebox&logoColor=fff" alt="TorrentPier nightly"></a>
<a href="https://packagist.org/packages/torrentpier/torrentpier"><img src="https://img.shields.io/packagist/dt/torrentpier/torrentpier" alt="Downloads"></a> <a href="https://packagist.org/packages/torrentpier/torrentpier"><img src="https://img.shields.io/packagist/dt/torrentpier/torrentpier" alt="Downloads"></a>
<a href="https://packagist.org/packages/torrentpier/torrentpier"><img src="https://img.shields.io/packagist/v/torrentpier/torrentpier" alt="Version"></a> <a href="https://packagist.org/packages/torrentpier/torrentpier"><img src="https://img.shields.io/packagist/v/torrentpier/torrentpier" alt="Version"></a>
<a href="https://github.com/torrentpier/torrentpier/releases"><img src="https://img.shields.io/github/release-date/torrentpier/torrentpier" alt="Last release"></a> <a href="https://github.com/torrentpier/torrentpier/releases"><img src="https://img.shields.io/github/release-date/torrentpier/torrentpier" alt="Last release"></a>
<img src="https://img.shields.io/github/repo-size/torrentpier/torrentpier" alt="Size"> <img src="https://img.shields.io/github/repo-size/torrentpier/torrentpier" alt="Size">
<a href="https://github.com/SamKirkland/FTP-Deploy-Action"><img src="https://img.shields.io/badge/Deployed to TorrentPier Demo with-FTP DEPLOY ACTION-%3CCOLOR%3E?color=2b9348" alt="Deployed to TorrentPier Demo with FTP Deploy Action"></a>
</p> </p>
## 🐂 About TorrentPier ## 🐂 About TorrentPier
TorrentPier — bull-powered BitTorrent Public/Private tracker engine, written in php. High speed, simple modification, high load TorrentPier — bull-powered BitTorrent Public/Private tracker engine, written in PHP. High speed, simple modifications, load-balanced
architecture. In addition, we have very helpful architecture. In addition, we have a very helpful
[official support forum](https://torrentpier.com), where it's possible to get any support and download modifications for engine. [official support forum](https://torrentpier.com), where it's possible to get support and download modifications for the engine.
## 🌈 Current status ## 🌈 Current status
TorrentPier is currently in active development. The goal is to remove all legacy code and rewrite existing to TorrentPier is currently in active development. The goal is to remove all legacy code and rewrite the existing code to
modern standards. If you want to go deep on the code, check our [issues](https://github.com/torrentpier/torrentpier/issues) modern specifications. If you want delve deep into the code, check our [issues](https://github.com/torrentpier/torrentpier/issues)
and go from there. The documentation will be translated into english in the near future, currently russian is the main language of it. and go from there. The documentation will be translated to english in the near future, currently russian is the main language of it.
## ✨ Features ## ✨ Features
* Rich forum browsing/moderation tools * Rich forum with browsing/moderation tools
* High-load capable, heavily configurable announcer * High-load capable, heavily configurable announcer
* Scrape support * Scrape support
* FreeLeech * FreeLeech
@ -38,11 +38,11 @@ and go from there. The documentation will be translated into english in the near
* BitTorrent v2 support * BitTorrent v2 support
* Event-based invite system * Event-based invite system
* Bonus points * Bonus points
* Polls system * Polling system
* PM system * PM/DM system
* Multilingual support (Fully supported for now only Russia and English languages) * Multilingual support (Russian and English is currently fully supported, with others in the future)
* Atom feeds * Atom/RSS feeds
* ... and MUCH MORE! * ... and so MUCH MORE!
## 🖥️ Demo ## 🖥️ Demo
@ -51,41 +51,56 @@ and go from there. The documentation will be translated into english in the near
* Password: `admin` * Password: `admin`
> [!NOTE] > [!NOTE]
> Demo is resetting every 24 hours! > Demo resets every 24 hours!
## 🔧 Requirements ## 🔧 Requirements
* Apache / nginx * Apache / nginx ([example config](install/nginx.conf)) / caddy ([example config](install/Caddyfile))
* MySQL 5.5.3 or above / MariaDB 10.0 or above / Percona * MySQL 5.5.3 or above / MariaDB 10.0 or above / Percona
* PHP: 8.1 / 8.2 / 8.3 * PHP: 8.1 / 8.2 / 8.3 / 8.4
* PHP Extensions: mbstring, gd, bcmath, intl, tidy (optional), xml, xmlwriter * PHP Extensions: mbstring, gd, bcmath, intl, tidy (optional), xml, xmlwriter
* Crontab (Recommended) * Crontab (Recommended)
## 💾 Installation ## 💾 Installation
For installation, select one of installation variants below. For the installation, select one of the installation variants below:
### Quick (Clean install) 🚀 ### Quick (Clean install) 🚀
Check out our [autoinstall](https://github.com/torrentpier/autoinstall) repository with detailed instructions. Check out our [autoinstall](https://github.com/torrentpier/autoinstall) repository with detailed instructions.
> [!IMPORTANT] > [!IMPORTANT]
> Thanks to [Sergei Solovev](https://github.com/SeAnSolovev) for installation script ❤️ > Thanks to [Sergei Solovev](https://github.com/SeAnSolovev) for this installation script ❤️
### Quick (For web-panels) ☕️ ### Quick (For web-panels) ☕️
1. Select the folder where you want to install TorrentPier (`cd /path/to/public_html`) 1. Select the folder where you want TorrentPier installed
2. Download latest version of TorrentPier (`sudo git clone https://github.com/torrentpier/torrentpier.git .`) ```shell
3. After, run `php install.php` and follow the given steps cd /path/to/public_html
```
2. Download the latest version of TorrentPier
```shell
sudo git clone https://github.com/torrentpier/torrentpier.git .
```
3. After completing, execute the command below and follow the instructions
```shell
php install.php
```
4. Voila! ✨ 4. Voila! ✨
### Manual 🔩 ### Manual 🔩
1. Install [Composer](https://getcomposer.org/) 1. Install [Composer](https://getcomposer.org/)
2. Run `composer create-project torrentpier/torrentpier` 2. Run the following command to create the TorrentPier project
```shell
composer create-project torrentpier/torrentpier
```
3. [Check our system requirements](#-requirements) 3. [Check our system requirements](#-requirements)
4. After, run `composer install` on the project directory 4. After, run this command in the project directory to install Composer dependencies
5. Create database and import dump located at `install/sql/mysql.sql` ```shell
composer install
```
5. Create a database and import the dump located at `install/sql/mysql.sql`
6. Edit database configuration settings in the environment (`.env.example`), after, rename to `.env` 6. Edit database configuration settings in the environment (`.env.example`), after, rename to `.env`
7. Provide write permissions to the specified folders: 7. Provide write permissions to the specified folders:
* `data/avatars`, `data/uploads`, `data/uploads/thumbs` * `data/avatars`, `data/uploads`, `data/uploads/thumbs`
@ -94,15 +109,14 @@ Check out our [autoinstall](https://github.com/torrentpier/autoinstall) reposito
8. Voila! ✨ 8. Voila! ✨
> [!IMPORTANT] > [!IMPORTANT]
> The specific settings depend on the server you are using, but in general case we recommend chmod **0755** for folders, and chmod **0644** for files in them. > The specific settings depend on the server you are using, but in general we recommend chmod **0755** for folders, and chmod **0644** for the files in them.
### Additional steps 👣 ### Additional steps 👣
1. Edit domain name and domain port in the configuration file or a local copy (`$reserved_name` and `$reserved_port`) 1. Edit these files:
2. Edit this files: * `favicon.png` (change to your own)
* `favicon.png` (change on your own) * `robots.txt` (change the addresses in lines `Host` and `Sitemap` to your own)
* `robots.txt` (change the addresses in lines `Host` and `Sitemap` on your own) 2. Log in to the forum using the **admin/admin** login/password, and finish setting up via admin panel. Don't forget to change your password!
3. Log in to the forum with **admin/admin** login/password and finish setting up via admin panel
## 🔐 Security vulnerabilities ## 🔐 Security vulnerabilities
@ -110,8 +124,8 @@ If you discover a security vulnerability within TorrentPier, please follow our [
## 📌 Our recommendations ## 📌 Our recommendations
* *The recommended way to run `cron.php`.* - For significant tracker speed increase may be required to replace built-in cron.php by operating system daemon. * *It's recommended to run `cron.php`.* - For significant tracker speed increase it ay be required to replace the built-in cron.php in operating system daemon.
* *Local configuration copy.* - You can override the settings using local configuration file `library/config.local.php`. * *Local configuration copy.* - You can override the settings using the local configuration file `library/config.local.php`.
## 💚 Contributing / Contributors ## 💚 Contributing / Contributors
@ -134,12 +148,18 @@ Support this project by becoming a sponsor or a backer.
<details> <details>
<summary>Monero</summary> <summary>Monero</summary>
42zJE3FDvN8foP9QYgDrBjgtd7h2FipGCGmAcmG5VFQuRkJBGMbCvoLSmivepmAMEgik2E8MPWUzKaoYsGCtmhvL7ZN73jh
```
42zJE3FDvN8foP9QYgDrBjgtd7h2FipGCGmAcmG5VFQuRkJBGMbCvoLSmivepmAMEgik2E8MPWUzKaoYsGCtmhvL7ZN73jh
```
</details> </details>
<details> <details>
<summary>YooMoney</summary> <summary>YooMoney</summary>
4100118022415720
```
4100118022415720
```
</details> </details>
## 📦 Versioning ## 📦 Versioning

85
_cleanup.php Normal file
View file

@ -0,0 +1,85 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2025 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
if (!defined('BB_ROOT')) {
define('BB_ROOT', __DIR__ . DIRECTORY_SEPARATOR);
}
// Check CLI mode
if (php_sapi_name() !== 'cli') {
exit;
}
$items = [
'.github',
'.cliffignore',
'.editorconfig',
'.gitignore',
'.styleci.yml',
'CHANGELOG.md',
'cliff.toml',
'cliff-releases.toml',
'CODE_OF_CONDUCT.md',
'CONTRIBUTING.md',
'crowdin.yml',
'HISTORY.md',
'README.md',
'SECURITY.md'
];
foreach ($items as $item) {
$path = BB_ROOT . $item;
if (is_file($path)) {
removeFile($path);
} elseif (is_dir($path)) {
removeDir($path);
}
}
/**
* Remove target file
*
* @param string $file Path to file
*/
function removeFile(string $file): void
{
if (unlink($file)) {
echo "- File removed: $file" . PHP_EOL;
} else {
echo "- File cannot be removed: $file" . PHP_EOL;
exit;
}
}
/**
* Remove folder (recursively)
*
* @param string $dir Path to folder
*/
function removeDir(string $dir): void
{
$it = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS);
$files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
foreach ($files as $file) {
if ($file->isDir()) {
removeDir($file->getPathname());
} else {
removeFile($file->getPathname());
}
}
if (rmdir($dir)) {
echo "- Folder removed: $dir" . PHP_EOL;
} else {
echo "- Folder cannot be removed: $dir" . PHP_EOL;
exit;
}
}

View file

@ -136,8 +136,8 @@ switch ($mode) {
'POSTS_PER_PAGE' => $new['posts_per_page'], 'POSTS_PER_PAGE' => $new['posts_per_page'],
'HOT_TOPIC' => $new['hot_threshold'], 'HOT_TOPIC' => $new['hot_threshold'],
'DEFAULT_DATEFORMAT' => $new['default_dateformat'], 'DEFAULT_DATEFORMAT' => $new['default_dateformat'],
'LANG_SELECT' => \TorrentPier\Legacy\Select::language($new['default_lang'], 'default_lang'), 'LANG_SELECT' => \TorrentPier\Legacy\Common\Select::language($new['default_lang'], 'default_lang'),
'TIMEZONE_SELECT' => \TorrentPier\Legacy\Select::timezone($new['board_timezone'], 'board_timezone'), 'TIMEZONE_SELECT' => \TorrentPier\Legacy\Common\Select::timezone($new['board_timezone'], 'board_timezone'),
'MAX_LOGIN_ATTEMPTS' => $new['max_login_attempts'], 'MAX_LOGIN_ATTEMPTS' => $new['max_login_attempts'],
'LOGIN_RESET_TIME' => $new['login_reset_time'], 'LOGIN_RESET_TIME' => $new['login_reset_time'],
'PRUNE_ENABLE' => (bool)$new['prune_enable'], 'PRUNE_ENABLE' => (bool)$new['prune_enable'],

View file

@ -123,6 +123,7 @@ if ($submit) {
} }
$datastore->update('cat_forums'); $datastore->update('cat_forums');
CACHE('bb_cache')->rm();
bb_die($lang['FORUM_AUTH_UPDATED'] . '<br /><br />' . sprintf($lang['CLICK_RETURN_FORUMAUTH'], '<a href="' . 'admin_forumauth.php' . '">', '</a>')); bb_die($lang['FORUM_AUTH_UPDATED'] . '<br /><br />' . sprintf($lang['CLICK_RETURN_FORUMAUTH'], '<a href="' . 'admin_forumauth.php' . '">', '</a>'));
} }

View file

@ -153,6 +153,7 @@ if ($submit) {
} }
$datastore->update('cat_forums'); $datastore->update('cat_forums');
CACHE('bb_cache')->rm();
bb_die($lang['FORUM_AUTH_UPDATED'] . '<br /><br />' . sprintf($lang['CLICK_RETURN_FORUMAUTH'], '<a href="admin_forumauth_list.php">', '</a>')); bb_die($lang['FORUM_AUTH_UPDATED'] . '<br /><br />' . sprintf($lang['CLICK_RETURN_FORUMAUTH'], '<a href="admin_forumauth_list.php">', '</a>'));
} // End of submit } // End of submit

View file

@ -29,6 +29,10 @@ if (isset($_GET['mode']) || isset($_POST['mode'])) {
} }
} }
if ($mode == 'delete' && isset($_POST['cancel'])) {
$mode = '';
}
if ($mode != '') { if ($mode != '') {
if ($mode == 'edit' || $mode == 'add') { if ($mode == 'edit' || $mode == 'add') {
// //
@ -123,12 +127,14 @@ if ($mode != '') {
// Ok, they want to delete their rank // Ok, they want to delete their rank
// //
$confirmed = isset($_POST['confirm']);
if (isset($_POST['id']) || isset($_GET['id'])) { if (isset($_POST['id']) || isset($_GET['id'])) {
$rank_id = isset($_POST['id']) ? (int)$_POST['id'] : (int)$_GET['id']; $rank_id = isset($_POST['id']) ? (int)$_POST['id'] : (int)$_GET['id'];
} else { } else {
$rank_id = 0; $rank_id = 0;
} }
if ($confirmed) {
if ($rank_id) { if ($rank_id) {
$sql = 'DELETE FROM ' . BB_RANKS . " WHERE rank_id = $rank_id"; $sql = 'DELETE FROM ' . BB_RANKS . " WHERE rank_id = $rank_id";
@ -147,6 +153,15 @@ if ($mode != '') {
} else { } else {
bb_die($lang['MUST_SELECT_RANK']); bb_die($lang['MUST_SELECT_RANK']);
} }
} else {
$hidden_fields = '<input type="hidden" name="mode" value="' . $mode . '" />';
$hidden_fields .= '<input type="hidden" name="id" value="' . $rank_id . '" />';
print_confirmation([
'FORM_ACTION' => 'admin_ranks.php',
'HIDDEN_FIELDS' => $hidden_fields,
]);
}
} else { } else {
bb_die('Invalid mode'); bb_die('Invalid mode');
} }

View file

@ -14,7 +14,7 @@ if (!empty($setmodules)) {
require __DIR__ . '/pagestart.php'; require __DIR__ . '/pagestart.php';
$sql = 'SELECT * FROM ' . BB_CONFIG; $sql = "SELECT * FROM " . BB_CONFIG . " WHERE config_name IN('sitemap_time', 'static_sitemap')";
if (!$result = DB()->sql_query($sql)) { if (!$result = DB()->sql_query($sql)) {
bb_die('Could not query config information in admin_sitemap'); bb_die('Could not query config information in admin_sitemap');

View file

@ -22,6 +22,10 @@ if (isset($_POST['mode']) || isset($_GET['mode'])) {
$mode = ''; $mode = '';
} }
if ($mode == 'delete' && isset($_POST['cancel'])) {
$mode = '';
}
$pathToSmilesDir = BB_ROOT . $bb_cfg['smilies_path']; $pathToSmilesDir = BB_ROOT . $bb_cfg['smilies_path'];
$delimeter = '=+:'; $delimeter = '=+:';
$s_hidden_fields = ''; $s_hidden_fields = '';
@ -174,17 +178,28 @@ if (isset($_GET['import_pack']) || isset($_POST['import_pack'])) {
} elseif ($mode != '') { } elseif ($mode != '') {
switch ($mode) { switch ($mode) {
case 'delete': case 'delete':
$confirmed = isset($_POST['confirm']);
$smiley_id = (!empty($_POST['id'])) ? $_POST['id'] : $_GET['id']; $smiley_id = (!empty($_POST['id'])) ? $_POST['id'] : $_GET['id'];
$smiley_id = (int)$smiley_id; $smiley_id = (int)$smiley_id;
if ($confirmed) {
$sql = 'DELETE FROM ' . BB_SMILIES . ' WHERE smilies_id = ' . $smiley_id; $sql = 'DELETE FROM ' . BB_SMILIES . ' WHERE smilies_id = ' . $smiley_id;
$result = DB()->sql_query($sql); $result = DB()->sql_query($sql);
if (!$result) { if (!$result) {
bb_die('Could not delete smiley'); bb_die('Could not delete smiley');
} }
$datastore->update('smile_replacements');
$datastore->update('smile_replacements');
bb_die($lang['SMILEY_DEL_SUCCESS'] . '<br /><br />' . sprintf($lang['CLICK_RETURN_SMILEADMIN'], '<a href="admin_smilies.php">', '</a>') . '<br /><br />' . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '<a href="index.php?pane=right">', '</a>')); bb_die($lang['SMILEY_DEL_SUCCESS'] . '<br /><br />' . sprintf($lang['CLICK_RETURN_SMILEADMIN'], '<a href="admin_smilies.php">', '</a>') . '<br /><br />' . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '<a href="index.php?pane=right">', '</a>'));
} else {
$hidden_fields = '<input type="hidden" name="mode" value="' . $mode . '" />';
$hidden_fields .= '<input type="hidden" name="id" value="' . $smiley_id . '" />';
print_confirmation([
'FORM_ACTION' => 'admin_smilies.php',
'HIDDEN_FIELDS' => $hidden_fields,
]);
}
break; break;
case 'edit': case 'edit':

View file

@ -20,9 +20,9 @@ $max_forum_name_length = 50;
$yes_sign = '&radic;'; $yes_sign = '&radic;';
$no_sign = 'x'; $no_sign = 'x';
$group_id = isset($_REQUEST['g']) ? (int)$_REQUEST['g'] : 0; $group_id = isset($_REQUEST[POST_GROUPS_URL]) ? (int)$_REQUEST[POST_GROUPS_URL] : 0;
$user_id = isset($_REQUEST['u']) ? (int)$_REQUEST['u'] : 0; $user_id = isset($_REQUEST[POST_USERS_URL]) ? (int)$_REQUEST[POST_USERS_URL] : 0;
$cat_id = isset($_REQUEST['c']) ? (int)$_REQUEST['c'] : 0; $cat_id = isset($_REQUEST[POST_CAT_URL]) ? (int)$_REQUEST[POST_CAT_URL] : 0;
$mode = isset($_REQUEST['mode']) ? (string)$_REQUEST['mode'] : ''; $mode = isset($_REQUEST['mode']) ? (string)$_REQUEST['mode'] : '';
$submit = isset($_REQUEST['submit']); $submit = isset($_REQUEST['submit']);
@ -200,7 +200,7 @@ if ($mode == 'user' && (!empty($_POST['username']) || $user_id)) {
'CAT_HREF' => "$base_url&amp;" . POST_CAT_URL . "=$c_id", 'CAT_HREF' => "$base_url&amp;" . POST_CAT_URL . "=$c_id",
)); ));
if (!$c =& $_REQUEST['c'] or !in_array($c, array('all', $c_id)) or empty($c_data['forums'])) { if (!$c =& $_REQUEST[POST_CAT_URL] or !in_array($c, array('all', $c_id)) or empty($c_data['forums'])) {
continue; continue;
} }
@ -316,7 +316,7 @@ if ($mode == 'user' && (!empty($_POST['username']) || $user_id)) {
'CAT_HREF' => "$base_url&amp;" . POST_CAT_URL . "=$c_id", 'CAT_HREF' => "$base_url&amp;" . POST_CAT_URL . "=$c_id",
)); ));
if (!($c =& $_REQUEST['c']) || !in_array($c, array('all', $c_id)) || empty($c_data['forums'])) { if (!($c =& $_REQUEST[POST_CAT_URL]) || !in_array($c, array('all', $c_id)) || empty($c_data['forums'])) {
continue; continue;
} }

View file

@ -52,8 +52,8 @@ if (!isset($_REQUEST['dosearch'])) {
} }
} }
$language_list = \TorrentPier\Legacy\Select::language('', 'language_type'); $language_list = \TorrentPier\Legacy\Common\Select::language('', 'language_type');
$timezone_list = \TorrentPier\Legacy\Select::timezone('', 'timezone_type'); $timezone_list = \TorrentPier\Legacy\Common\Select::timezone('', 'timezone_type');
$sql = 'SELECT f.forum_id, f.forum_name, f.forum_parent, c.cat_id, c.cat_title $sql = 'SELECT f.forum_id, f.forum_name, f.forum_parent, c.cat_id, c.cat_title
FROM ( ' . BB_FORUMS . ' AS f INNER JOIN ' . BB_CATEGORIES . ' AS c ON c.cat_id = f.cat_id ) FROM ( ' . BB_FORUMS . ' AS f INNER JOIN ' . BB_CATEGORIES . ' AS c ON c.cat_id = f.cat_id )

View file

@ -15,12 +15,6 @@ if (!$stats = $datastore->get('stats')) {
$stats = $datastore->get('stats'); $stats = $datastore->get('stats');
} }
// Files integrity check
if (!$files_integrity_data = $datastore->get('files_integrity')) {
$datastore->update('files_integrity');
$files_integrity_data = $datastore->get('files_integrity');
}
// Check for updates // Check for updates
if (!$update_data = $datastore->get('check_updates')) { if (!$update_data = $datastore->get('check_updates')) {
$datastore->update('check_updates'); $datastore->update('check_updates');
@ -88,16 +82,6 @@ if (isset($_GET['pane']) && $_GET['pane'] == 'left') {
'ADMIN_LOCK_CRON' => is_file(BB_DISABLED), 'ADMIN_LOCK_CRON' => is_file(BB_DISABLED),
]); ]);
// Files integrity check results
if (!empty($files_integrity_data)) {
$template->assign_block_vars('integrity_check', [
'INTEGRITY_SUCCESS' => (bool)$files_integrity_data['success'],
'INTEGRITY_WRONG_FILES_LIST' => implode("\n</li>\n<li>\n", $files_integrity_data['wrong_files']),
'INTEGRITY_LAST_CHECK_TIME' => sprintf($lang['INTEGRITY_LAST_CHECK'], bb_date($files_integrity_data['timestamp'])),
'INTEGRITY_CHECKED_FILES' => sprintf($lang['INTEGRITY_CHECKED'], $files_integrity_data['total_num'], ($files_integrity_data['total_num'] - $files_integrity_data['wrong_files_num'])),
]);
}
// Check for updates // Check for updates
if (isset($update_data['available_update'])) { if (isset($update_data['available_update'])) {
$template->assign_block_vars('updater', [ $template->assign_block_vars('updater', [

View file

@ -39,7 +39,7 @@ foreach ($sql as $i => $query) {
echo '</table>'; echo '</table>';
echo '<div align="center"><pre>'; echo '<div align="center"><pre>';
echo 'gen time: <b>' . sprintf('%.4f', array_sum(explode(' ', microtime())) - TIMESTART) . "</b> sec\n"; echo 'gen time: <b>' . sprintf('%.3f', array_sum(explode(' ', microtime())) - TIMESTART) . "</b> sec\n";
echo '</pre></div>'; echo '</pre></div>';
echo '</body></html>'; echo '</body></html>';

View file

@ -173,7 +173,7 @@ echo '</table>';
echo !$client_full ? '<p style = "text-align:right;">Simple stats for clients are being cached for one hour.</p>' : ''; echo !$client_full ? '<p style = "text-align:right;">Simple stats for clients are being cached for one hour.</p>' : '';
echo '<div align="center"><pre>'; echo '<div align="center"><pre>';
echo 'gen time: <b>' . sprintf('%.4f', array_sum(explode(' ', microtime())) - TIMESTART) . "</b> sec\n"; echo 'gen time: <b>' . sprintf('%.3f', array_sum(explode(' ', microtime())) - TIMESTART) . "</b> sec\n";
echo '</pre></div>'; echo '</pre></div>';
echo '</body></html>'; echo '</body></html>';

View file

@ -41,5 +41,5 @@ $ajax->exec();
/** /**
* @deprecated ajax_common * @deprecated ajax_common
* Dirty class removed from here since 2.2.0 * Dirty class removed from here since 2.2.0
* To add new actions see at src/Legacy/Ajax.php * To add new actions see at src/Ajax.php
*/ */

View file

@ -13,7 +13,9 @@ require dirname(__DIR__) . '/common.php';
global $bb_cfg; global $bb_cfg;
if (empty($_SERVER['HTTP_USER_AGENT'])) { // Check User-Agent for existence
$userAgent = (string)$_SERVER['HTTP_USER_AGENT'];
if (empty($userAgent)) {
header('Location: http://127.0.0.1', true, 301); header('Location: http://127.0.0.1', true, 301);
die; die;
} }
@ -99,7 +101,7 @@ if (!isset($info_hash)) {
* *
* @see https://github.com/HDInnovations/UNIT3D-Community-Edition/blob/c64275f0b5dcb3c4c845d5204871adfe24f359d6/app/Http/Controllers/AnnounceController.php#L275 * @see https://github.com/HDInnovations/UNIT3D-Community-Edition/blob/c64275f0b5dcb3c4c845d5204871adfe24f359d6/app/Http/Controllers/AnnounceController.php#L275
*/ */
$event = strtolower($event); $event = strtolower((string)$event);
if (!in_array($event, ['started', 'completed', 'stopped', 'paused', ''])) { if (!in_array($event, ['started', 'completed', 'stopped', 'paused', ''])) {
msg_die('Invalid event: ' . $event); msg_die('Invalid event: ' . $event);
} }
@ -151,7 +153,6 @@ if (!isset($left) || !is_numeric($left) || $left < 0) {
* *
* @see https://github.com/HDInnovations/UNIT3D-Community-Edition/blob/c64275f0b5dcb3c4c845d5204871adfe24f359d6/app/Http/Controllers/AnnounceController.php#L177 * @see https://github.com/HDInnovations/UNIT3D-Community-Edition/blob/c64275f0b5dcb3c4c845d5204871adfe24f359d6/app/Http/Controllers/AnnounceController.php#L177
*/ */
$userAgent = (string)$_SERVER['HTTP_USER_AGENT'];
if (strlen($userAgent) > 64) { if (strlen($userAgent) > 64) {
msg_die('User-Agent must be less than 64 characters long'); msg_die('User-Agent must be less than 64 characters long');
} }

View file

@ -1 +0,0 @@
Require all denied

125
cliff-releases.toml Normal file
View file

@ -0,0 +1,125 @@
# git-cliff ~ TorrentPier configuration file
# https://git-cliff.org/docs/configuration
#
# Lines starting with "#" are comments.
# Configuration options are organized into tables and keys.
# See documentation for more information on available options.
[remote.github]
owner = "torrentpier"
repo = "torrentpier"
[changelog]
# template for the changelog header
header = """
[![TorrentPier](https://raw.githubusercontent.com/torrentpier/.github/refs/heads/main/versions/Cattle.png)](https://github.com/torrentpier)\n
"""
# template for the changelog body
# https://keats.github.io/tera/docs/#introduction
body = """
{%- macro remote_url() -%}
https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
{%- endmacro -%}
{%- macro nightly_url() -%}
https://nightly.link/{{ remote.github.owner }}/{{ remote.github.repo }}/workflows/build/master/TorrentPier
{%- endmacro -%}
{% macro print_commit(commit) -%}
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
{% if commit.breaking %}[**breaking**] {% endif %}\
{{ commit.message | upper_first }} - \
([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\
{% endmacro -%}
{% if version %}\
{% if previous.version %}\
## [{{ version }}]\
({{ self::remote_url() }}/compare/{{ previous.version }}..{{ version }}) ({{ timestamp | date(format="%Y-%m-%d") }})
{% else %}\
## {{ version }} ({{ timestamp | date(format="%Y-%m-%d") }})
{% endif %}\
{% else %}\
## [nightly]({{ self::nightly_url() }})
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | striptags | trim | upper_first }}
{% for commit in commits
| filter(attribute="scope")
| sort(attribute="scope") %}
{{ self::print_commit(commit=commit) }}
{%- endfor %}
{% for commit in commits %}
{%- if not commit.scope -%}
{{ self::print_commit(commit=commit) }}
{% endif -%}
{% endfor -%}
{% endfor -%}
{%- if github -%}
{% if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %}
## New Contributors ❤️
{% endif %}\
{% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %}
* @{{ contributor.username }} made their first contribution
{%- if contributor.pr_number %} in \
[#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \
{%- endif %}
{%- endfor -%}
{%- endif %}
"""
# template for the changelog footer
footer = """
"""
# remove the leading and trailing whitespace from the templates
trim = true
# postprocessors
postprocessors = [
{ pattern = '<REPO>', replace = "https://github.com/torrentpier/torrentpier" }, # replace repository URL
]
[git]
# parse the commits based on https://www.conventionalcommits.org
conventional_commits = true
# filter out the commits that are not conventional
filter_unconventional = true
# process each line of a commit as an individual commit
split_commits = false
# regex for preprocessing the commit messages
commit_preprocessors = [
# Replace issue numbers
{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](<REPO>/pull/${2}))" },
# Check spelling of the commit with https://github.com/crate-ci/typos
# If the spelling is incorrect, it will be automatically fixed.
# { pattern = '.*', replace_command = 'typos --write-changes -' },
]
# regex for parsing and grouping commits
commit_parsers = [
{ message = "^feat", group = "<!-- 0 -->🚀 Features" },
{ message = "^fix", group = "<!-- 1 -->🐛 Bug Fixes" },
{ message = "^doc", group = "<!-- 3 -->📚 Documentation" },
{ message = "^perf", group = "<!-- 4 -->⚡ Performance" },
{ message = "^refactor", group = "<!-- 2 -->🚜 Refactor" },
{ message = "^style", group = "<!-- 5 -->🎨 Styling" },
{ message = "^test", group = "<!-- 6 -->🧪 Testing" },
{ message = "^ignore|^release", skip = true },
{ message = "^chore|^ci|^misc", group = "<!-- 7 -->⚙️ Miscellaneous" },
{ body = ".*security", group = "<!-- 8 -->🛡️ Security" },
{ message = "^revert", group = "<!-- 9 -->◀️ Revert" },
{ message = "^crowdin", group = "<!-- 10 -->🈳 New translations" }, # crowdin pulls supporting
{ message = "^Composer", group = "<!-- 11 -->📦 Dependencies" }, # dependabot pulls supporting
{ message = "^rem|^drop|^removed", group = "<!-- 12 -->🗑️ Removed" },
{ message = ".*", group = "<!-- 13 -->💼 Other" },
]
# protect breaking changes from being skipped due to matching a skipping commit_parser
protect_breaking_commits = false
# filter out the commits that are not matched by commit parsers
filter_commits = false
# regex for matching git tags
tag_pattern = "v[0-9].*"
# sort the tags topologically
topo_order = false
# sort the commits inside sections by oldest/newest order
sort_commits = "newest"

View file

@ -63,12 +63,14 @@ body = """
## New Contributors ❤️ ## New Contributors ❤️
{% endif %}\ {% endif %}\
{% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %} {% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %}
* [@{{ contributor.username }}](https://github.com/{{ contributor.username }}) made their first contribution * @{{ contributor.username }} made their first contribution
{%- if contributor.pr_number %} in \ {%- if contributor.pr_number %} in \
[#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \ [#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \
{%- endif %} {%- endif %}
{%- endfor -%} {%- endfor -%}
{%- endif %} {%- endif %}
""" """
# template for the changelog footer # template for the changelog footer
footer = """ footer = """

View file

@ -46,23 +46,23 @@
"forum": "https://torrentpier.com" "forum": "https://torrentpier.com"
}, },
"require": { "require": {
"php": "^8.1 | ^8.2 | ^8.3 | ^8.4", "php": ">=8.1",
"arokettu/random-polyfill": "1.0.2", "arokettu/random-polyfill": "1.0.2",
"arokettu/bencode": "^4.1.0", "arokettu/bencode": "^4.1.0",
"arokettu/monsterid": "dev-master", "arokettu/monsterid": "dev-master",
"arokettu/torrent-file": "^5.2.1", "arokettu/torrent-file": "^5.2.1",
"bugsnag/bugsnag": "^v3.29.1", "bugsnag/bugsnag": "^v3.29.1",
"claviska/simpleimage": "^4.0", "claviska/simpleimage": "^4.0",
"belomaxorka/captcha": "1.*",
"egulias/email-validator": "^4.0.1", "egulias/email-validator": "^4.0.1",
"filp/whoops": "^2.15", "filp/whoops": "^2.15",
"z4kn4fein/php-semver": "^v3.0.0", "z4kn4fein/php-semver": "^v3.0.0",
"nemorize/indexnow": "^0.0.1",
"gigablah/sphinxphp": "2.0.8", "gigablah/sphinxphp": "2.0.8",
"google/recaptcha": "^1.3", "google/recaptcha": "^1.3",
"jacklul/monolog-telegram": "^3.1", "jacklul/monolog-telegram": "^3.1",
"josantonius/cookie": "^2.0", "josantonius/cookie": "^2.0",
"gemorroj/m3u-parser": "dev-master", "gemorroj/m3u-parser": "dev-master",
"php-curl-class/php-curl-class": "^11.0.0", "php-curl-class/php-curl-class": "^12.0.0",
"league/flysystem": "^3.28", "league/flysystem": "^3.28",
"longman/ip-tools": "1.2.1", "longman/ip-tools": "1.2.1",
"matthiasmullie/scrapbook": "^1.5.4", "matthiasmullie/scrapbook": "^1.5.4",
@ -73,7 +73,7 @@
"symfony/event-dispatcher": "^6.4", "symfony/event-dispatcher": "^6.4",
"symfony/mime": "^6.4", "symfony/mime": "^6.4",
"symfony/mailer": "^6.4", "symfony/mailer": "^6.4",
"symfony/polyfill": "v1.31.0", "symfony/polyfill": "v1.32.0",
"vlucas/phpdotenv": "^5.5" "vlucas/phpdotenv": "^5.5"
}, },
"require-dev": { "require-dev": {

434
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "9024100c87e72c5ee811638607aa15f5", "content-hash": "2acad3dafd9fd57bc8c26303df22dd15",
"packages": [ "packages": [
{ {
"name": "arokettu/bencode", "name": "arokettu/bencode",
@ -144,12 +144,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/arokettu/monsterid.git", "url": "https://github.com/arokettu/monsterid.git",
"reference": "de2873a5cf6f2ed7cf2c8709ee1bae0e6aec1ed8" "reference": "4e7484a593c42eba960ee555877dd9b26577fe8a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/arokettu/monsterid/zipball/de2873a5cf6f2ed7cf2c8709ee1bae0e6aec1ed8", "url": "https://api.github.com/repos/arokettu/monsterid/zipball/4e7484a593c42eba960ee555877dd9b26577fe8a",
"reference": "de2873a5cf6f2ed7cf2c8709ee1bae0e6aec1ed8", "reference": "4e7484a593c42eba960ee555877dd9b26577fe8a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -157,20 +157,26 @@
"arokettu/random-polyfill": "^1.0.1", "arokettu/random-polyfill": "^1.0.1",
"ext-gd": "*", "ext-gd": "*",
"php": "^8.0", "php": "^8.0",
"php-http/discovery": "^1.19",
"psr/http-factory": "^1.0" "psr/http-factory": "^1.0"
}, },
"require-dev": { "require-dev": {
"arokettu/random-polyfill": ">= 1.0.1 < 1.99", "arokettu/random-polyfill": ">= 1.0.1 < 1.99",
"httpsoft/http-message": "^1.1", "httpsoft/http-message": "^1.1",
"php-http/discovery": "^1.20",
"phpunit/phpunit": ">= 7.0 < 10", "phpunit/phpunit": ">= 7.0 < 10",
"psy/psysh": "*", "psy/psysh": "*",
"sandfox.dev/code-standard": "^1.2024.07.05", "sandfox.dev/code-standard": "^1.2025.03.27",
"slim/psr7": "^1.7",
"squizlabs/php_codesniffer": "*", "squizlabs/php_codesniffer": "*",
"vimeo/psalm": "^5.4" "vimeo/psalm": "^5.4 || ^6.0"
}, },
"default-branch": true, "default-branch": true,
"type": "library", "type": "library",
"extra": {
"discovery": {
"psr/http-factory-implementation": "Arokettu\\MonsterID\\Tests\\Helpers\\HttpFactory"
}
},
"autoload": { "autoload": {
"files": [ "files": [
"src/functions.php" "src/functions.php"
@ -191,7 +197,7 @@
}, },
{ {
"name": "Anton Smirnov", "name": "Anton Smirnov",
"email": "sandfox@sandfox.me", "email": "sandfox+composer@sandfox.me",
"homepage": "https://sandfox.me/", "homepage": "https://sandfox.me/",
"role": "maintainer" "role": "maintainer"
} }
@ -203,11 +209,12 @@
"monsterid" "monsterid"
], ],
"support": { "support": {
"chat": "https://gitter.im/arokettu/community",
"docs": "https://monsterid.readthedocs.io/", "docs": "https://monsterid.readthedocs.io/",
"issues": "https://gitlab.com/sandfox/monsterid/-/issues", "issues": "https://gitlab.com/sandfox/monsterid/-/issues",
"source": "https://gitlab.com/sandfox/monsterid" "source": "https://gitlab.com/sandfox/monsterid"
}, },
"time": "2024-10-13T00:45:20+00:00" "time": "2025-04-03T13:37:00+00:00"
}, },
{ {
"name": "arokettu/random-polyfill", "name": "arokettu/random-polyfill",
@ -347,16 +354,16 @@
}, },
{ {
"name": "arokettu/unsigned", "name": "arokettu/unsigned",
"version": "1.3.5", "version": "1.3.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/arokettu/unsigned.git", "url": "https://github.com/arokettu/unsigned.git",
"reference": "559dd1247fb4bbc9d70a6ff8581d8e9fd742e096" "reference": "1e5b3a131d669ee31c4d941bc27e4ba4ef64ae76"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/arokettu/unsigned/zipball/559dd1247fb4bbc9d70a6ff8581d8e9fd742e096", "url": "https://api.github.com/repos/arokettu/unsigned/zipball/1e5b3a131d669ee31c4d941bc27e4ba4ef64ae76",
"reference": "559dd1247fb4bbc9d70a6ff8581d8e9fd742e096", "reference": "1e5b3a131d669ee31c4d941bc27e4ba4ef64ae76",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -365,13 +372,16 @@
"require-dev": { "require-dev": {
"phpunit/phpunit": ">= 6.5 <10", "phpunit/phpunit": ">= 6.5 <10",
"psy/psysh": "*", "psy/psysh": "*",
"sandfox.dev/code-standard": "^1.2023.12.09", "sandfox.dev/code-standard": "^1.2025.03.27",
"squizlabs/php_codesniffer": "*" "squizlabs/php_codesniffer": "*"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
"files": [ "files": [
"src/lib.php" "src/lib.php"
],
"classmap": [
"src/Unsigned.php"
] ]
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
@ -398,20 +408,90 @@
"issues": "https://gitlab.com/sandfox/unsigned/-/issues", "issues": "https://gitlab.com/sandfox/unsigned/-/issues",
"source": "https://gitlab.com/sandfox/unsigned" "source": "https://gitlab.com/sandfox/unsigned"
}, },
"time": "2024-02-01T20:40:11+00:00" "time": "2025-03-31T23:49:37+00:00"
}, },
{ {
"name": "bugsnag/bugsnag", "name": "belomaxorka/captcha",
"version": "v3.29.2", "version": "v1.2.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/bugsnag/bugsnag-php.git", "url": "https://github.com/belomaxorka/Captcha.git",
"reference": "437ac553e3dfb546b93a7191e031643b00da20f2" "reference": "db51723a9539b57ac3faff0211c117b4c55dbe23"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/bugsnag/bugsnag-php/zipball/437ac553e3dfb546b93a7191e031643b00da20f2", "url": "https://api.github.com/repos/belomaxorka/Captcha/zipball/db51723a9539b57ac3faff0211c117b4c55dbe23",
"reference": "437ac553e3dfb546b93a7191e031643b00da20f2", "reference": "db51723a9539b57ac3faff0211c117b4c55dbe23",
"shasum": ""
},
"require": {
"ext-fileinfo": "*",
"ext-gd": "*",
"ext-mbstring": "*",
"php": ">=5.3.0",
"symfony/finder": "*"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6.4 || ^7.0 || ^8.0 || ^9.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Gregwar\\": "src/Gregwar"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Grégoire Passault",
"email": "g.passault@gmail.com",
"homepage": "https://www.gregwar.com/",
"role": "Developer"
},
{
"name": "Jeremy Livingston",
"email": "jeremy.j.livingston@gmail.com"
},
{
"name": "belomaxorka",
"email": "roman25052006.kelesh@gmail.com",
"homepage": "https://belomaxorka.github.io/",
"role": "Developer"
}
],
"description": "Captcha generator",
"homepage": "https://github.com/belomaxorka/Captcha",
"keywords": [
"anti-bot",
"anti-spam",
"bot-protection",
"captcha",
"no-bot",
"obfuscation",
"security",
"spam",
"spam-protection"
],
"support": {
"source": "https://github.com/belomaxorka/Captcha/tree/v1.2.4"
},
"time": "2025-03-10T13:15:53+00:00"
},
{
"name": "bugsnag/bugsnag",
"version": "v3.29.3",
"source": {
"type": "git",
"url": "https://github.com/bugsnag/bugsnag-php.git",
"reference": "9d9aa665f5e9d24f45aad5114dbd2d861119febb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/bugsnag/bugsnag-php/zipball/9d9aa665f5e9d24f45aad5114dbd2d861119febb",
"reference": "9d9aa665f5e9d24f45aad5114dbd2d861119febb",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -459,9 +539,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/bugsnag/bugsnag-php/issues", "issues": "https://github.com/bugsnag/bugsnag-php/issues",
"source": "https://github.com/bugsnag/bugsnag-php/tree/v3.29.2" "source": "https://github.com/bugsnag/bugsnag-php/tree/v3.29.3"
}, },
"time": "2025-01-13T16:29:41+00:00" "time": "2025-03-06T12:03:07+00:00"
}, },
{ {
"name": "claviska/simpleimage", "name": "claviska/simpleimage",
@ -518,16 +598,16 @@
}, },
{ {
"name": "composer/ca-bundle", "name": "composer/ca-bundle",
"version": "1.5.5", "version": "1.5.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/composer/ca-bundle.git", "url": "https://github.com/composer/ca-bundle.git",
"reference": "08c50d5ec4c6ced7d0271d2862dec8c1033283e6" "reference": "f65c239c970e7f072f067ab78646e9f0b2935175"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/08c50d5ec4c6ced7d0271d2862dec8c1033283e6", "url": "https://api.github.com/repos/composer/ca-bundle/zipball/f65c239c970e7f072f067ab78646e9f0b2935175",
"reference": "08c50d5ec4c6ced7d0271d2862dec8c1033283e6", "reference": "f65c239c970e7f072f067ab78646e9f0b2935175",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -574,7 +654,7 @@
"support": { "support": {
"irc": "irc://irc.freenode.org/composer", "irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/ca-bundle/issues", "issues": "https://github.com/composer/ca-bundle/issues",
"source": "https://github.com/composer/ca-bundle/tree/1.5.5" "source": "https://github.com/composer/ca-bundle/tree/1.5.6"
}, },
"funding": [ "funding": [
{ {
@ -590,7 +670,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-01-08T16:17:16+00:00" "time": "2025-03-06T14:30:56+00:00"
}, },
{ {
"name": "doctrine/lexer", "name": "doctrine/lexer",
@ -671,16 +751,16 @@
}, },
{ {
"name": "egulias/email-validator", "name": "egulias/email-validator",
"version": "4.0.3", "version": "4.0.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/egulias/EmailValidator.git", "url": "https://github.com/egulias/EmailValidator.git",
"reference": "b115554301161fa21467629f1e1391c1936de517" "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/egulias/EmailValidator/zipball/b115554301161fa21467629f1e1391c1936de517", "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa",
"reference": "b115554301161fa21467629f1e1391c1936de517", "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -726,7 +806,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/egulias/EmailValidator/issues", "issues": "https://github.com/egulias/EmailValidator/issues",
"source": "https://github.com/egulias/EmailValidator/tree/4.0.3" "source": "https://github.com/egulias/EmailValidator/tree/4.0.4"
}, },
"funding": [ "funding": [
{ {
@ -734,20 +814,20 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-12-27T00:36:43+00:00" "time": "2025-03-06T22:45:56+00:00"
}, },
{ {
"name": "filp/whoops", "name": "filp/whoops",
"version": "2.16.0", "version": "2.18.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/filp/whoops.git", "url": "https://github.com/filp/whoops.git",
"reference": "befcdc0e5dce67252aa6322d82424be928214fa2" "reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/filp/whoops/zipball/befcdc0e5dce67252aa6322d82424be928214fa2", "url": "https://api.github.com/repos/filp/whoops/zipball/a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e",
"reference": "befcdc0e5dce67252aa6322d82424be928214fa2", "reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -797,7 +877,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/filp/whoops/issues", "issues": "https://github.com/filp/whoops/issues",
"source": "https://github.com/filp/whoops/tree/2.16.0" "source": "https://github.com/filp/whoops/tree/2.18.0"
}, },
"funding": [ "funding": [
{ {
@ -805,7 +885,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-09-25T12:00:00+00:00" "time": "2025-03-15T12:00:00+00:00"
}, },
{ {
"name": "gemorroj/m3u-parser", "name": "gemorroj/m3u-parser",
@ -813,21 +893,21 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Gemorroj/M3uParser.git", "url": "https://github.com/Gemorroj/M3uParser.git",
"reference": "fcb37acd137a6e1d6aa2ef3745e1bc7a6e0b46e6" "reference": "92fc0fe236d77e1b5a26c735ffcb6fc637eb298a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Gemorroj/M3uParser/zipball/fcb37acd137a6e1d6aa2ef3745e1bc7a6e0b46e6", "url": "https://api.github.com/repos/Gemorroj/M3uParser/zipball/92fc0fe236d77e1b5a26c735ffcb6fc637eb298a",
"reference": "fcb37acd137a6e1d6aa2ef3745e1bc7a6e0b46e6", "reference": "92fc0fe236d77e1b5a26c735ffcb6fc637eb298a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=8.0.2" "php": ">=8.0.2"
}, },
"require-dev": { "require-dev": {
"friendsofphp/php-cs-fixer": "^3.46", "friendsofphp/php-cs-fixer": "^3.73.1",
"phpstan/phpstan": "^1.10", "phpstan/phpstan": "^2.1",
"phpunit/phpunit": "^9.6" "phpunit/phpunit": "^9.6.22"
}, },
"default-branch": true, "default-branch": true,
"type": "library", "type": "library",
@ -853,9 +933,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/Gemorroj/M3uParser/issues", "issues": "https://github.com/Gemorroj/M3uParser/issues",
"source": "https://github.com/Gemorroj/M3uParser/tree/master" "source": "https://github.com/Gemorroj/M3uParser/tree/6.0.1"
}, },
"time": "2024-07-27T11:53:30+00:00" "time": "2025-03-25T19:21:43+00:00"
}, },
{ {
"name": "gigablah/sphinxphp", "name": "gigablah/sphinxphp",
@ -1028,16 +1108,16 @@
}, },
{ {
"name": "guzzlehttp/guzzle", "name": "guzzlehttp/guzzle",
"version": "7.9.2", "version": "7.9.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/guzzle.git", "url": "https://github.com/guzzle/guzzle.git",
"reference": "d281ed313b989f213357e3be1a179f02196ac99b" "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b", "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
"reference": "d281ed313b989f213357e3be1a179f02196ac99b", "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1134,7 +1214,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/guzzle/issues", "issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.9.2" "source": "https://github.com/guzzle/guzzle/tree/7.9.3"
}, },
"funding": [ "funding": [
{ {
@ -1150,20 +1230,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-07-24T11:22:20+00:00" "time": "2025-03-27T13:37:11+00:00"
}, },
{ {
"name": "guzzlehttp/promises", "name": "guzzlehttp/promises",
"version": "2.0.4", "version": "2.2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/promises.git", "url": "https://github.com/guzzle/promises.git",
"reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455" "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/f9c436286ab2892c7db7be8c8da4ef61ccf7b455", "url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c",
"reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455", "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1217,7 +1297,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/promises/issues", "issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/2.0.4" "source": "https://github.com/guzzle/promises/tree/2.2.0"
}, },
"funding": [ "funding": [
{ {
@ -1233,20 +1313,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-10-17T10:06:22+00:00" "time": "2025-03-27T13:27:01+00:00"
}, },
{ {
"name": "guzzlehttp/psr7", "name": "guzzlehttp/psr7",
"version": "2.7.0", "version": "2.7.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/psr7.git", "url": "https://github.com/guzzle/psr7.git",
"reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", "url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16",
"reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1333,7 +1413,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/psr7/issues", "issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.7.0" "source": "https://github.com/guzzle/psr7/tree/2.7.1"
}, },
"funding": [ "funding": [
{ {
@ -1349,20 +1429,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-07-18T11:15:46+00:00" "time": "2025-03-27T12:30:47+00:00"
}, },
{ {
"name": "jacklul/monolog-telegram", "name": "jacklul/monolog-telegram",
"version": "3.1.0", "version": "3.2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/jacklul/monolog-telegram.git", "url": "https://github.com/jacklul/monolog-telegram.git",
"reference": "ec8674fbd280bbb369b5f48447259e44a92f39c8" "reference": "1f2069f5556b1c8d6eb2d8b8ac29ff376675cf46"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/jacklul/monolog-telegram/zipball/ec8674fbd280bbb369b5f48447259e44a92f39c8", "url": "https://api.github.com/repos/jacklul/monolog-telegram/zipball/1f2069f5556b1c8d6eb2d8b8ac29ff376675cf46",
"reference": "ec8674fbd280bbb369b5f48447259e44a92f39c8", "reference": "1f2069f5556b1c8d6eb2d8b8ac29ff376675cf46",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1410,7 +1490,7 @@
"issues": "https://github.com/jacklul/monolog-telegram/issues", "issues": "https://github.com/jacklul/monolog-telegram/issues",
"source": "https://github.com/jacklul/monolog-telegram" "source": "https://github.com/jacklul/monolog-telegram"
}, },
"time": "2023-11-21T18:26:36+00:00" "time": "2025-01-24T18:07:58+00:00"
}, },
{ {
"name": "josantonius/cookie", "name": "josantonius/cookie",
@ -1886,16 +1966,16 @@
}, },
{ {
"name": "monolog/monolog", "name": "monolog/monolog",
"version": "3.8.1", "version": "3.9.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Seldaek/monolog.git", "url": "https://github.com/Seldaek/monolog.git",
"reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4" "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/aef6ee73a77a66e404dd6540934a9ef1b3c855b4", "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6",
"reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4", "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1973,7 +2053,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/Seldaek/monolog/issues", "issues": "https://github.com/Seldaek/monolog/issues",
"source": "https://github.com/Seldaek/monolog/tree/3.8.1" "source": "https://github.com/Seldaek/monolog/tree/3.9.0"
}, },
"funding": [ "funding": [
{ {
@ -1985,48 +2065,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-12-05T17:15:07+00:00" "time": "2025-03-24T10:02:05+00:00"
},
{
"name": "nemorize/indexnow",
"version": "0.0.1",
"source": {
"type": "git",
"url": "https://github.com/nemorize/php-indexnow.git",
"reference": "7602a8ae1de0cf1dd11692a7627f10111c55731a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nemorize/php-indexnow/zipball/7602a8ae1de0cf1dd11692a7627f10111c55731a",
"reference": "7602a8ae1de0cf1dd11692a7627f10111c55731a",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "^7.7",
"php": ">=8.1"
},
"type": "library",
"autoload": {
"psr-4": {
"Nemorize\\Indexnow\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ji Yong, Kim",
"email": "nemo@qroffle.com"
}
],
"description": "PHP library for submitting website URLs using IndexNow to search engines.",
"support": {
"issues": "https://github.com/nemorize/php-indexnow/issues",
"source": "https://github.com/nemorize/php-indexnow/tree/0.0.1"
},
"time": "2023-07-31T17:08:12+00:00"
}, },
{ {
"name": "nikic/iter", "name": "nikic/iter",
@ -2082,21 +2121,21 @@
}, },
{ {
"name": "php-curl-class/php-curl-class", "name": "php-curl-class/php-curl-class",
"version": "11.0.1", "version": "12.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/php-curl-class/php-curl-class.git", "url": "https://github.com/php-curl-class/php-curl-class.git",
"reference": "c8a7bc92f2337e634611eb127b5d269a243d2034" "reference": "7a8f05efb18bb865dbce864b8fd34d4f5d920c74"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/php-curl-class/php-curl-class/zipball/c8a7bc92f2337e634611eb127b5d269a243d2034", "url": "https://api.github.com/repos/php-curl-class/php-curl-class/zipball/7a8f05efb18bb865dbce864b8fd34d4f5d920c74",
"reference": "c8a7bc92f2337e634611eb127b5d269a243d2034", "reference": "7a8f05efb18bb865dbce864b8fd34d4f5d920c74",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-curl": "*", "ext-curl": "*",
"php": ">=7.4" "php": ">=8.0"
}, },
"require-dev": { "require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "*", "dealerdirect/phpcodesniffer-composer-installer": "*",
@ -2156,88 +2195,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/php-curl-class/php-curl-class/issues", "issues": "https://github.com/php-curl-class/php-curl-class/issues",
"source": "https://github.com/php-curl-class/php-curl-class/tree/11.0.1" "source": "https://github.com/php-curl-class/php-curl-class/tree/12.0.0"
}, },
"time": "2025-01-13T18:04:13+00:00" "time": "2025-03-25T18:04:16+00:00"
},
{
"name": "php-http/discovery",
"version": "1.20.0",
"source": {
"type": "git",
"url": "https://github.com/php-http/discovery.git",
"reference": "82fe4c73ef3363caed49ff8dd1539ba06044910d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-http/discovery/zipball/82fe4c73ef3363caed49ff8dd1539ba06044910d",
"reference": "82fe4c73ef3363caed49ff8dd1539ba06044910d",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.0|^2.0",
"php": "^7.1 || ^8.0"
},
"conflict": {
"nyholm/psr7": "<1.0",
"zendframework/zend-diactoros": "*"
},
"provide": {
"php-http/async-client-implementation": "*",
"php-http/client-implementation": "*",
"psr/http-client-implementation": "*",
"psr/http-factory-implementation": "*",
"psr/http-message-implementation": "*"
},
"require-dev": {
"composer/composer": "^1.0.2|^2.0",
"graham-campbell/phpspec-skip-example-extension": "^5.0",
"php-http/httplug": "^1.0 || ^2.0",
"php-http/message-factory": "^1.0",
"phpspec/phpspec": "^5.1 || ^6.1 || ^7.3",
"sebastian/comparator": "^3.0.5 || ^4.0.8",
"symfony/phpunit-bridge": "^6.4.4 || ^7.0.1"
},
"type": "composer-plugin",
"extra": {
"class": "Http\\Discovery\\Composer\\Plugin",
"plugin-optional": true
},
"autoload": {
"psr-4": {
"Http\\Discovery\\": "src/"
},
"exclude-from-classmap": [
"src/Composer/Plugin.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com"
}
],
"description": "Finds and installs PSR-7, PSR-17, PSR-18 and HTTPlug implementations",
"homepage": "http://php-http.org",
"keywords": [
"adapter",
"client",
"discovery",
"factory",
"http",
"message",
"psr17",
"psr7"
],
"support": {
"issues": "https://github.com/php-http/discovery/issues",
"source": "https://github.com/php-http/discovery/tree/1.20.0"
},
"time": "2024-10-02T11:20:13+00:00"
}, },
{ {
"name": "phpoption/phpoption", "name": "phpoption/phpoption",
@ -3185,16 +3145,16 @@
}, },
{ {
"name": "symfony/mailer", "name": "symfony/mailer",
"version": "v6.4.13", "version": "v6.4.21",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/mailer.git", "url": "https://github.com/symfony/mailer.git",
"reference": "c2f7e0d8d7ac8fe25faccf5d8cac462805db2663" "reference": "ada2809ccd4ec27aba9fc344e3efdaec624c6438"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/mailer/zipball/c2f7e0d8d7ac8fe25faccf5d8cac462805db2663", "url": "https://api.github.com/repos/symfony/mailer/zipball/ada2809ccd4ec27aba9fc344e3efdaec624c6438",
"reference": "c2f7e0d8d7ac8fe25faccf5d8cac462805db2663", "reference": "ada2809ccd4ec27aba9fc344e3efdaec624c6438",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3245,7 +3205,7 @@
"description": "Helps sending emails", "description": "Helps sending emails",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/mailer/tree/v6.4.13" "source": "https://github.com/symfony/mailer/tree/v6.4.21"
}, },
"funding": [ "funding": [
{ {
@ -3261,20 +3221,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-09-25T14:18:03+00:00" "time": "2025-04-26T23:47:35+00:00"
}, },
{ {
"name": "symfony/mime", "name": "symfony/mime",
"version": "v6.4.17", "version": "v6.4.21",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/mime.git", "url": "https://github.com/symfony/mime.git",
"reference": "ea87c8850a54ff039d3e0ab4ae5586dd4e6c0232" "reference": "fec8aa5231f3904754955fad33c2db50594d22d1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/mime/zipball/ea87c8850a54ff039d3e0ab4ae5586dd4e6c0232", "url": "https://api.github.com/repos/symfony/mime/zipball/fec8aa5231f3904754955fad33c2db50594d22d1",
"reference": "ea87c8850a54ff039d3e0ab4ae5586dd4e6c0232", "reference": "fec8aa5231f3904754955fad33c2db50594d22d1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3330,7 +3290,7 @@
"mime-type" "mime-type"
], ],
"support": { "support": {
"source": "https://github.com/symfony/mime/tree/v6.4.17" "source": "https://github.com/symfony/mime/tree/v6.4.21"
}, },
"funding": [ "funding": [
{ {
@ -3346,20 +3306,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-12-02T11:09:41+00:00" "time": "2025-04-27T13:27:38+00:00"
}, },
{ {
"name": "symfony/polyfill", "name": "symfony/polyfill",
"version": "v1.31.0", "version": "v1.32.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill.git", "url": "https://github.com/symfony/polyfill.git",
"reference": "c5ce28b35b2784b7b508aaa4447a6c3e39041e50" "reference": "c4ee386e95ccdbea59cea802ea776d806319d506"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill/zipball/c5ce28b35b2784b7b508aaa4447a6c3e39041e50", "url": "https://api.github.com/repos/symfony/polyfill/zipball/c4ee386e95ccdbea59cea802ea776d806319d506",
"reference": "c5ce28b35b2784b7b508aaa4447a6c3e39041e50", "reference": "c4ee386e95ccdbea59cea802ea776d806319d506",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3382,6 +3342,7 @@
"symfony/polyfill-php82": "self.version", "symfony/polyfill-php82": "self.version",
"symfony/polyfill-php83": "self.version", "symfony/polyfill-php83": "self.version",
"symfony/polyfill-php84": "self.version", "symfony/polyfill-php84": "self.version",
"symfony/polyfill-php85": "self.version",
"symfony/polyfill-util": "self.version", "symfony/polyfill-util": "self.version",
"symfony/polyfill-uuid": "self.version" "symfony/polyfill-uuid": "self.version"
}, },
@ -3412,6 +3373,7 @@
"src/Intl/Icu/Resources/stubs", "src/Intl/Icu/Resources/stubs",
"src/Intl/MessageFormatter/Resources/stubs", "src/Intl/MessageFormatter/Resources/stubs",
"src/Intl/Normalizer/Resources/stubs", "src/Intl/Normalizer/Resources/stubs",
"src/Php85/Resources/stubs",
"src/Php84/Resources/stubs", "src/Php84/Resources/stubs",
"src/Php83/Resources/stubs", "src/Php83/Resources/stubs",
"src/Php82/Resources/stubs", "src/Php82/Resources/stubs",
@ -3445,7 +3407,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/symfony/polyfill/issues", "issues": "https://github.com/symfony/polyfill/issues",
"source": "https://github.com/symfony/polyfill/tree/v1.31.0" "source": "https://github.com/symfony/polyfill/tree/v1.32.0"
}, },
"funding": [ "funding": [
{ {
@ -3461,7 +3423,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-09-09T12:16:23+00:00" "time": "2025-05-02T09:40:28+00:00"
}, },
{ {
"name": "symfony/service-contracts", "name": "symfony/service-contracts",
@ -3548,16 +3510,16 @@
}, },
{ {
"name": "vlucas/phpdotenv", "name": "vlucas/phpdotenv",
"version": "v5.6.1", "version": "v5.6.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/vlucas/phpdotenv.git", "url": "https://github.com/vlucas/phpdotenv.git",
"reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2" "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a59a13791077fe3d44f90e7133eb68e7d22eaff2", "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/24ac4c74f91ee2c193fa1aaa5c249cb0822809af",
"reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2", "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3616,7 +3578,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/vlucas/phpdotenv/issues", "issues": "https://github.com/vlucas/phpdotenv/issues",
"source": "https://github.com/vlucas/phpdotenv/tree/v5.6.1" "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.2"
}, },
"funding": [ "funding": [
{ {
@ -3628,7 +3590,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-07-20T21:52:34+00:00" "time": "2025-04-30T23:37:27+00:00"
}, },
{ {
"name": "z4kn4fein/php-semver", "name": "z4kn4fein/php-semver",
@ -3688,16 +3650,16 @@
"packages-dev": [ "packages-dev": [
{ {
"name": "symfony/var-dumper", "name": "symfony/var-dumper",
"version": "v6.4.15", "version": "v6.4.21",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/var-dumper.git", "url": "https://github.com/symfony/var-dumper.git",
"reference": "38254d5a5ac2e61f2b52f9caf54e7aa3c9d36b80" "reference": "22560f80c0c5cd58cc0bcaf73455ffd81eb380d5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/38254d5a5ac2e61f2b52f9caf54e7aa3c9d36b80", "url": "https://api.github.com/repos/symfony/var-dumper/zipball/22560f80c0c5cd58cc0bcaf73455ffd81eb380d5",
"reference": "38254d5a5ac2e61f2b52f9caf54e7aa3c9d36b80", "reference": "22560f80c0c5cd58cc0bcaf73455ffd81eb380d5",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3753,7 +3715,7 @@
"dump" "dump"
], ],
"support": { "support": {
"source": "https://github.com/symfony/var-dumper/tree/v6.4.15" "source": "https://github.com/symfony/var-dumper/tree/v6.4.21"
}, },
"funding": [ "funding": [
{ {
@ -3769,7 +3731,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-11-08T15:28:48+00:00" "time": "2025-04-09T07:34:50+00:00"
} }
], ],
"aliases": [], "aliases": [],
@ -3781,7 +3743,7 @@
"prefer-stable": true, "prefer-stable": true,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
"php": "^8.1 | ^8.2 | ^8.3 | ^8.4" "php": ">=8.1"
}, },
"platform-dev": [], "platform-dev": [],
"plugin-api-version": "2.3.0" "plugin-api-version": "2.3.0"

View file

@ -1,3 +0,0 @@
php_flag engine off
RemoveHandler .php .php5 .php4 .php3 .phtml .pl .asp
AddType text/plain .php .php .htm .html .phtml .pl .asp

View file

@ -23,7 +23,7 @@ if (!$topic_id) {
bb_die($lang['INVALID_TOPIC_ID'], 404); bb_die($lang['INVALID_TOPIC_ID'], 404);
} }
$sql = 'SELECT t.attach_id, t.info_hash, t.info_hash_v2, t.size, ad.physical_filename $sql = 'SELECT t.forum_id, t.attach_id, t.info_hash, t.info_hash_v2, t.size, ad.physical_filename
FROM ' . BB_BT_TORRENTS . ' t FROM ' . BB_BT_TORRENTS . ' t
LEFT JOIN ' . BB_ATTACHMENTS_DESC . ' ad LEFT JOIN ' . BB_ATTACHMENTS_DESC . ' ad
ON t.attach_id = ad.attach_id ON t.attach_id = ad.attach_id
@ -34,6 +34,12 @@ if (!$row = DB()->fetch_row($sql)) {
bb_die($lang['INVALID_TOPIC_ID_DB'], 404); bb_die($lang['INVALID_TOPIC_ID_DB'], 404);
} }
// Check rights
$is_auth = auth(AUTH_ALL, $row['forum_id'], $userdata);
if (!$is_auth['auth_view']) {
bb_die($lang['SORRY_AUTH_VIEW_ATTACH'], 403);
}
// Protocol meta // Protocol meta
$meta_v1 = !empty($row['info_hash']); $meta_v1 = !empty($row['info_hash']);
$meta_v2 = !empty($row['info_hash_v2']); $meta_v2 = !empty($row['info_hash_v2']);

View file

@ -573,7 +573,7 @@ if (!$group_id) {
$template->assign_block_vars('pending', [ $template->assign_block_vars('pending', [
'ROW_CLASS' => $row_class, 'ROW_CLASS' => $row_class,
'AVATAR_IMG' => $pending_info['avatar'], 'AVATAR_IMG' => $pending_info['avatar'],
'USER' => profile_url($pending_info), 'USER' => profile_url($member),
'FROM' => $pending_info['from'], 'FROM' => $pending_info['from'],
'JOINED' => $pending_info['joined'], 'JOINED' => $pending_info['joined'],
'JOINED_RAW' => $pending_info['joined_raw'], 'JOINED_RAW' => $pending_info['joined_raw'],

View file

@ -46,7 +46,7 @@ if ($bb_cfg['show_network_news']) {
$user->session_start(); $user->session_start();
// Init main vars // Init main vars
$viewcat = isset($_GET['c']) ? (int)$_GET['c'] : 0; $viewcat = isset($_GET[POST_CAT_URL]) ? (int)$_GET[POST_CAT_URL] : 0;
$lastvisit = IS_GUEST ? TIMENOW : $userdata['user_lastvisit']; $lastvisit = IS_GUEST ? TIMENOW : $userdata['user_lastvisit'];
// Caching output // Caching output
@ -80,6 +80,7 @@ $forum_name_html = $forums['forum_name_html'];
$anon = GUEST_UID; $anon = GUEST_UID;
$excluded_forums_csv = $user->get_excluded_forums(AUTH_VIEW); $excluded_forums_csv = $user->get_excluded_forums(AUTH_VIEW);
$excluded_forums_array = $excluded_forums_csv ? explode(',', $excluded_forums_csv) : [];
$only_new = $user->opt_js['only_new']; $only_new = $user->opt_js['only_new'];
// Validate requested category id // Validate requested category id
@ -329,6 +330,10 @@ if ($bb_cfg['show_latest_news']) {
$template->assign_vars(['SHOW_LATEST_NEWS' => true]); $template->assign_vars(['SHOW_LATEST_NEWS' => true]);
foreach ($latest_news as $news) { foreach ($latest_news as $news) {
if (in_array($news['forum_id'], $excluded_forums_array)) {
continue;
}
$template->assign_block_vars('news', [ $template->assign_block_vars('news', [
'NEWS_TOPIC_ID' => $news['topic_id'], 'NEWS_TOPIC_ID' => $news['topic_id'],
'NEWS_TITLE' => str_short($wordCensor->censorString($news['topic_title']), $bb_cfg['max_news_title']), 'NEWS_TITLE' => str_short($wordCensor->censorString($news['topic_title']), $bb_cfg['max_news_title']),
@ -348,6 +353,10 @@ if ($bb_cfg['show_network_news']) {
$template->assign_vars(['SHOW_NETWORK_NEWS' => true]); $template->assign_vars(['SHOW_NETWORK_NEWS' => true]);
foreach ($network_news as $net) { foreach ($network_news as $net) {
if (in_array($net['forum_id'], $excluded_forums_array)) {
continue;
}
$template->assign_block_vars('net', [ $template->assign_block_vars('net', [
'NEWS_TOPIC_ID' => $net['topic_id'], 'NEWS_TOPIC_ID' => $net['topic_id'],
'NEWS_TITLE' => str_short($wordCensor->censorString($net['topic_title']), $bb_cfg['max_net_title']), 'NEWS_TITLE' => str_short($wordCensor->censorString($net['topic_title']), $bb_cfg['max_net_title']),

View file

@ -16,8 +16,9 @@ $user->session_start();
$info = []; $info = [];
$htmlDir = LANG_DIR . 'html/'; $htmlDir = LANG_DIR . 'html/';
$show = isset($_REQUEST['show']) ? (string)$_REQUEST['show'] : '';
switch ((string)$_REQUEST['show'] ?? 'not_found') { switch ($show) {
case 'advert': case 'advert':
$info['title'] = $lang['ADVERT']; $info['title'] = $lang['ADVERT'];
$info['src'] = 'advert.html'; $info['src'] = 'advert.html';

View file

@ -7,7 +7,7 @@
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License * @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/ */
define('BB_ROOT', __DIR__ . '/'); define('BB_ROOT', __DIR__ . DIRECTORY_SEPARATOR);
// Check CLI mode // Check CLI mode
if (php_sapi_name() !== 'cli') { if (php_sapi_name() !== 'cli') {
@ -185,7 +185,7 @@ if (!defined('EXTENSIONS_NOT_INSTALLED')) {
if (is_file(BB_ROOT . '.env')) { if (is_file(BB_ROOT . '.env')) {
out('- TorrentPier already installed', 'warning'); out('- TorrentPier already installed', 'warning');
echo 'Are you sure want to re-install TorrentPier? [y/N]: '; echo 'Are you sure want to re-install TorrentPier? [y/N]: ';
if (str_starts_with(mb_strtolower(readline()), 'y')) { if (str_starts_with(mb_strtolower(trim(readline())), 'y')) {
out("\n- Re-install process started...", 'info'); out("\n- Re-install process started...", 'info');
// environment // environment
if (is_file(BB_ROOT . '.env')) { if (is_file(BB_ROOT . '.env')) {
@ -257,6 +257,8 @@ if (!is_file(BB_ROOT . 'vendor/autoload.php')) {
// Installing dependencies // Installing dependencies
if (is_file(BB_ROOT . 'composer.phar')) { if (is_file(BB_ROOT . 'composer.phar')) {
out('- Installing dependencies...', 'info'); out('- Installing dependencies...', 'info');
runProcess('php ' . BB_ROOT . 'composer.phar update --no-install');
sleep(3);
runProcess('php ' . BB_ROOT . 'composer.phar install --no-interaction --no-ansi'); runProcess('php ' . BB_ROOT . 'composer.phar install --no-interaction --no-ansi');
define('COMPOSER_COMPLETED', true); define('COMPOSER_COMPLETED', true);
} else { } else {
@ -288,7 +290,7 @@ if (is_file(BB_ROOT . '.env.example') && !is_file(BB_ROOT . '.env')) {
} }
// Editing ENV file // Editing ENV file
$DB_HOST = ''; $DB_HOST = 'localhost';
$DB_PORT = 3306; $DB_PORT = 3306;
$DB_DATABASE = ''; $DB_DATABASE = '';
$DB_USERNAME = ''; $DB_USERNAME = '';
@ -309,20 +311,17 @@ if (is_file(BB_ROOT . '.env')) {
if (trim($line) !== '' && !str_starts_with($line, '#')) { if (trim($line) !== '' && !str_starts_with($line, '#')) {
$parts = explode('=', $line, 2); $parts = explode('=', $line, 2);
$key = trim($parts[0]); $key = trim($parts[0]);
$value = (isset($parts[1]) && $key !== 'DB_PASSWORD') ? trim($parts[1]) : ''; $value = (!empty($parts[1]) && $key !== 'DB_PASSWORD') ? trim($parts[1]) : '';
// Database default values
if (in_array($key, ['DB_HOST', 'DB_PORT', 'DB_DATABASE', 'DB_USERNAME', 'DB_PASSWORD'])) {
$$key = $value;
}
out("\nCurrent value of $key: $value", 'debug'); out("\nCurrent value of $key: $value", 'debug');
echo "Enter a new value for $key (or leave empty to not change): "; echo "Enter a new value for $key (or leave empty to not change): ";
$newValue = readline(); $newValue = trim(readline());
if (!empty($newValue) || $key === 'DB_PASSWORD') { if (!empty($newValue) || $key === 'DB_PASSWORD') {
$line = "$key=$newValue"; $line = "$key=$newValue";
$$key = $newValue; $$key = $newValue;
} else {
$$key = $value;
} }
} }
@ -418,5 +417,23 @@ if (!empty($DB_HOST) && !empty($DB_DATABASE) && !empty($DB_USERNAME)) {
} }
} }
// Cleanup...
if (is_file(BB_ROOT . '_cleanup.php')) {
out("\n--- Finishing installation (Cleanup) ---\n", 'info');
out('The cleanup process will remove:');
out('- Development documentation (README, CHANGELOG)', 'debug');
out('- Git configuration files', 'debug');
out('- CI/CD pipelines and code analysis tools', 'debug');
out('- Translation and contribution guidelines', 'debug');
echo 'Do you want to delete these files permanently? [y/N]: ';
if (str_starts_with(mb_strtolower(trim(readline())), 'y')) {
out("\n- Cleanup...", 'info');
require_once BB_ROOT . '_cleanup.php';
unlink(BB_ROOT . '_cleanup.php');
} else {
out('- Skipping...', 'info');
}
}
out("\n- Voila! Good luck & have fun!", 'success'); out("\n- Voila! Good luck & have fun!", 'success');
} }

View file

@ -1 +0,0 @@
Require all denied

27
install/Caddyfile Normal file
View file

@ -0,0 +1,27 @@
# Example Caddy configuration for TorrentPier
example.com {
root * /path/to/root
encode gzip zstd
php_fastcgi unix//run/php/php-fpm.sock
try_files {path} {path}/ /index.php?{query}
file_server
@blocked {
path /install/* /internal_data/* /library/*
path /.ht* /.en*
path /.git/*
path *.sql *.tpl *.db *.inc *.log *.md
}
respond @blocked 404
redir /sitemap.xml /sitemap/sitemap.xml
@html_css_js {
path *.html *.css *.js *.json *.xml *.txt
}
header @html_css_js Content-Type "{mime}; charset=utf-8"
}
# Refer to the Caddy docs for more information:
# https://caddyserver.com/docs/caddyfile

39
install/nginx.conf Normal file
View file

@ -0,0 +1,39 @@
# Example nginx configuration for TorrentPier
server {
listen 80; # port
server_name example.com; # your domain
root /path/to/root; # folder with TorrentPier installed
index index.php;
charset utf-8;
location / {
try_files \$uri \$uri/ /index.php?\$args;
}
location ~ \/(install|internal_data|library)\/ {
return 404;
}
location ~ /\.(ht|en) {
return 404;
}
location ~ /\.git {
return 404;
}
location ~ \.(.*sql|tpl|db|inc|log|md)$ {
return 404;
}
rewrite ^/sitemap.xml$ /sitemap/sitemap.xml;
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
include fastcgi_params;
}
}

View file

@ -600,8 +600,7 @@ VALUES ('allow_autologin', '1'),
('premod', '0'), ('premod', '0'),
('tor_comment', '1'), ('tor_comment', '1'),
('terms', ''), ('terms', ''),
('show_board_start_index', '1'), ('show_board_start_index', '1');
('tp_instance_hash', '');
-- ---------------------------- -- ----------------------------
-- Table structure for `bb_cron` -- Table structure for `bb_cron`
@ -1047,7 +1046,7 @@ CREATE TABLE IF NOT EXISTS `bb_privmsgs`
( (
`privmsgs_id` MEDIUMINT(8) UNSIGNED NOT NULL AUTO_INCREMENT, `privmsgs_id` MEDIUMINT(8) UNSIGNED NOT NULL AUTO_INCREMENT,
`privmsgs_type` TINYINT(4) NOT NULL DEFAULT '0', `privmsgs_type` TINYINT(4) NOT NULL DEFAULT '0',
`privmsgs_subject` VARCHAR(255) NOT NULL DEFAULT '0', `privmsgs_subject` VARCHAR(255) NOT NULL DEFAULT '',
`privmsgs_from_userid` MEDIUMINT(8) NOT NULL DEFAULT '0', `privmsgs_from_userid` MEDIUMINT(8) NOT NULL DEFAULT '0',
`privmsgs_to_userid` MEDIUMINT(8) NOT NULL DEFAULT '0', `privmsgs_to_userid` MEDIUMINT(8) NOT NULL DEFAULT '0',
`privmsgs_date` INT(11) NOT NULL DEFAULT '0', `privmsgs_date` INT(11) NOT NULL DEFAULT '0',

View file

@ -154,3 +154,4 @@ INSERT INTO `bb_config` VALUES ('magnet_links_for_guests', '0');
INSERT INTO `bb_config` VALUES ('tp_instance_hash', ''); INSERT INTO `bb_config` VALUES ('tp_instance_hash', '');
// 2.4.5 // 2.4.5
DELETE FROM `bb_config` WHERE `config_name` = 'tp_instance_hash';

View file

@ -1 +0,0 @@
Require all denied

0
internal_data/cache/.keep vendored Normal file
View file

File diff suppressed because it is too large Load diff

View file

@ -1 +0,0 @@
Require all denied

0
internal_data/log/.keep Normal file
View file

View file

@ -1 +0,0 @@
Require all denied

View file

@ -82,10 +82,6 @@ switch ($mode) {
\TorrentPier\Helpers\CronHelper::enableBoard(); \TorrentPier\Helpers\CronHelper::enableBoard();
$this->response['unlock_cron_html'] = '<span class="seed bold">' . $lang['ADMIN_UNLOCKED'] . '</span>'; $this->response['unlock_cron_html'] = '<span class="seed bold">' . $lang['ADMIN_UNLOCKED'] . '</span>';
break; break;
case 'restore_corrupt_files':
file_write('', RESTORE_CORRUPT_CONFIRM_FILE, replace_content: true);
$this->response['restore_corrupt_files_html'] = '<span class="seed bold">' . $lang['INTEGRITY_RESTORE_CONFIRM_OK'] . '</span>';
break;
default: default:
$this->ajax_die('Invalid mode: ' . $mode); $this->ajax_die('Invalid mode: ' . $mode);
} }

View file

@ -15,7 +15,7 @@ global $user, $lang, $bb_cfg;
$post_id = isset($this->request['post_id']) ? (int)$this->request['post_id'] : null; $post_id = isset($this->request['post_id']) ? (int)$this->request['post_id'] : null;
$topic_id = isset($this->request['topic_id']) ? (int)$this->request['topic_id'] : null; $topic_id = isset($this->request['topic_id']) ? (int)$this->request['topic_id'] : null;
$return_text = $bb_cfg['show_post_bbcode_button'] && isset($this->request['return_text']) && (bool)$this->request['return_text']; $return_text = $bb_cfg['show_post_bbcode_button']['enabled'] && isset($this->request['return_text']) && (bool)$this->request['return_text'];
if (is_null($post_id)) { if (is_null($post_id)) {
$post_id = DB()->fetch_row("SELECT topic_first_post_id FROM " . BB_TOPICS . " WHERE topic_id = $topic_id", 'topic_first_post_id'); $post_id = DB()->fetch_row("SELECT topic_first_post_id FROM " . BB_TOPICS . " WHERE topic_id = $topic_id", 'topic_first_post_id');

View file

@ -1 +0,0 @@
Require all denied

View file

@ -79,7 +79,7 @@ $tor_auth_del = ($tor_auth && $tor_reged);
$tracker_link = ($tor_reged) ? $lang['BT_REG_YES'] : $lang['BT_REG_NO']; $tracker_link = ($tor_reged) ? $lang['BT_REG_YES'] : $lang['BT_REG_NO'];
$download_link = DL_URL . $attach_id; $download_link = DL_URL . $attach_id;
$description = ($comment) ?: preg_replace("#.torrent$#i", '', $display_name); $description = ($comment) ?: preg_replace("#" . "." . TORRENT_EXT . "$#i", '', $display_name);
if ($tor_auth_reg || $tor_auth_del) { if ($tor_auth_reg || $tor_auth_del) {
$reg_tor_url = '<a class="txtb" href="#" onclick="ajax.exec({ action: \'change_torrent\', attach_id : ' . $attach_id . ', type: \'reg\'}); return false;">' . $lang['BT_REG_ON_TRACKER'] . '</a>'; $reg_tor_url = '<a class="txtb" href="#" onclick="ajax.exec({ action: \'change_torrent\', attach_id : ' . $attach_id . ', type: \'reg\'}); return false;">' . $lang['BT_REG_ON_TRACKER'] . '</a>';
@ -88,7 +88,11 @@ if ($tor_auth_reg || $tor_auth_del) {
$tracker_link = ($tor_reged) ? $unreg_tor_url : $reg_tor_url; $tracker_link = ($tor_reged) ? $unreg_tor_url : $reg_tor_url;
} }
$display_name = $t_data['topic_title'] . ' [' . $bb_cfg['server_name'] . '-' . $bt_topic_id . ']' . '.' . TORRENT_EXT; if ($bb_cfg['tracker']['use_old_torrent_name_format']) {
$display_name = '[' . $bb_cfg['server_name'] . '].t' . $bt_topic_id . '.' . TORRENT_EXT;
} else {
$display_name = $t_data['topic_title'] . ' [' . $bb_cfg['server_name'] . '-' . $bt_topic_id . ']' . '.' . TORRENT_EXT;
}
if (!$tor_reged) { if (!$tor_reged) {
$template->assign_block_vars('postrow.attach.tor_not_reged', [ $template->assign_block_vars('postrow.attach.tor_not_reged', [
@ -145,7 +149,7 @@ if ($tor_reged && $tor_info) {
// Magnet link // Magnet link
$user_passkey = \TorrentPier\Legacy\Torrent::getPasskey($bt_user_id); $user_passkey = \TorrentPier\Legacy\Torrent::getPasskey($bt_user_id);
$tor_magnet = create_magnet($tor_info['info_hash'], $tor_info['info_hash_v2'], $user_passkey, html_ent_decode($t_data['topic_title'])); $tor_magnet = create_magnet($tor_info['info_hash'], $tor_info['info_hash_v2'], $user_passkey, html_ent_decode($t_data['topic_title']), $tor_size);
// ratio limits // ratio limits
$min_ratio_dl = $bb_cfg['bt_min_ratio_allow_dl_tor']; $min_ratio_dl = $bb_cfg['bt_min_ratio_allow_dl_tor'];
@ -215,7 +219,6 @@ if ($tor_reged && $tor_info) {
'HASH' => !empty($tor_info['info_hash']) ? strtoupper(bin2hex($tor_info['info_hash'])) : false, 'HASH' => !empty($tor_info['info_hash']) ? strtoupper(bin2hex($tor_info['info_hash'])) : false,
'HASH_V2' => !empty($tor_info['info_hash_v2']) ? strtoupper(bin2hex($tor_info['info_hash_v2'])) : false, 'HASH_V2' => !empty($tor_info['info_hash_v2']) ? strtoupper(bin2hex($tor_info['info_hash_v2'])) : false,
'FILELIST_ICON' => $images['icon_tor_filelist'], 'FILELIST_ICON' => $images['icon_tor_filelist'],
'FILELIST_LINK' => FILELIST_URL . $tor_info['topic_id'],
'REGED_TIME' => bb_date($tor_info['reg_time']), 'REGED_TIME' => bb_date($tor_info['reg_time']),
'REGED_DELTA' => delta_time($tor_info['reg_time']), 'REGED_DELTA' => delta_time($tor_info['reg_time']),
'TORRENT_SIZE' => humn_size($tor_size, 2), 'TORRENT_SIZE' => humn_size($tor_size, 2),
@ -241,7 +244,7 @@ if ($tor_reged && $tor_info) {
'SHOW_DL_LIST' => true, 'SHOW_DL_LIST' => true,
'SHOW_DL_LIST_TOR_INFO' => true, 'SHOW_DL_LIST_TOR_INFO' => true,
'TOR_SIZE' => humn_size($tor_size, 1), 'TOR_SIZE' => humn_size($tor_size, 2),
'TOR_LONGEVITY' => delta_time($tor_info['reg_time']), 'TOR_LONGEVITY' => delta_time($tor_info['reg_time']),
'TOR_DOWNLOAD_COUNT' => $download_count, 'TOR_DOWNLOAD_COUNT' => $download_count,
'TOR_COMPLETED' => $tor_completed_count, 'TOR_COMPLETED' => $tor_completed_count,
@ -298,7 +301,7 @@ if ($tor_reged && $tor_info) {
$sql = "SELECT $sql = "SELECT
tr.user_id, tr.ip, tr.ipv6, tr.port, tr.peer_id, tr.uploaded, tr.downloaded, tr.remain, tr.user_id, tr.ip, tr.ipv6, tr.port, tr.peer_id, tr.uploaded, tr.downloaded, tr.remain,
tr.seeder, tr.releaser, tr.speed_up, tr.speed_down, tr.update_time, tr.seeder, tr.releaser, tr.speed_up, tr.speed_down, tr.update_time,
tr.complete_percent, u.username, u.user_rank tr.complete_percent, u.username, u.user_rank, u.user_opt
FROM " . BB_BT_TRACKER . " tr FROM " . BB_BT_TRACKER . " tr
LEFT JOIN " . BB_USERS . " u ON u.user_id = tr.user_id LEFT JOIN " . BB_USERS . " u ON u.user_id = tr.user_id
WHERE tr.topic_id = $tor_id WHERE tr.topic_id = $tor_id
@ -369,8 +372,8 @@ if ($tor_reged && $tor_info) {
$peers = $tmp; $peers = $tmp;
$template->assign_vars([ $template->assign_vars([
'TOR_SPEED_UP' => ($tor_speed_up) ? humn_size($tor_speed_up, 0, 'KB') . '/s' : '0 KB/s', 'TOR_SPEED_UP' => ($tor_speed_up) ? humn_size($tor_speed_up, min: 'KB') . '/s' : '0 KB/s',
'TOR_SPEED_DOWN' => ($tor_speed_down) ? humn_size($tor_speed_down, 0, 'KB') . '/s' : '0 KB/s' 'TOR_SPEED_DOWN' => ($tor_speed_down) ? humn_size($tor_speed_down, min: 'KB') . '/s' : '0 KB/s'
]); ]);
} }
@ -403,7 +406,7 @@ if ($tor_reged && $tor_info) {
$template->assign_block_vars((string)$x_full, [ $template->assign_block_vars((string)$x_full, [
'SEED_ORD_ACT' => $seed_order_action, 'SEED_ORD_ACT' => $seed_order_action,
'SEEDERS_UP_TOT' => humn_size($sp_up_tot[$x], 0, 'KB') . '/s' 'SEEDERS_UP_TOT' => humn_size($sp_up_tot[$x], min: 'KB') . '/s'
]); ]);
if ($ip) { if ($ip) {
@ -425,8 +428,8 @@ if ($tor_reged && $tor_info) {
$template->assign_block_vars((string)$x_full, [ $template->assign_block_vars((string)$x_full, [
'LEECH_ORD_ACT' => $leech_order_action, 'LEECH_ORD_ACT' => $leech_order_action,
'LEECHERS_UP_TOT' => humn_size($sp_up_tot[$x], 0, 'KB') . '/s', 'LEECHERS_UP_TOT' => humn_size($sp_up_tot[$x], min: 'KB') . '/s',
'LEECHERS_DOWN_TOT' => humn_size($sp_down_tot[$x], 0, 'KB') . '/s' 'LEECHERS_DOWN_TOT' => humn_size($sp_down_tot[$x], min: 'KB') . '/s'
]); ]);
if ($ip) { if ($ip) {
@ -445,18 +448,36 @@ if ($tor_reged && $tor_info) {
$up_tot = ($p_max_up) ? humn_size($p_max_up) : '-'; $up_tot = ($p_max_up) ? humn_size($p_max_up) : '-';
$down_tot = ($p_max_down) ? humn_size($p_max_down) : '-'; $down_tot = ($p_max_down) ? humn_size($p_max_down) : '-';
$up_ratio = ($p_max_down) ? round(($p_max_up / $p_max_down), 2) : ''; $up_ratio = ($p_max_down) ? round(($p_max_up / $p_max_down), 2) : '';
$sp_up = ($peer['speed_up']) ? humn_size($peer['speed_up'], 0, 'KB') . '/s' : '-'; $sp_up = ($peer['speed_up']) ? humn_size($peer['speed_up'], min: 'KB') . '/s' : '-';
$sp_down = ($peer['speed_down']) ? humn_size($peer['speed_down'], 0, 'KB') . '/s' : '-'; $sp_down = ($peer['speed_down']) ? humn_size($peer['speed_down'], min: 'KB') . '/s' : '-';
$bgr_class = (!($tr[$x] % 2)) ? $bgr_class_1 : $bgr_class_2; $bgr_class = (!($tr[$x] % 2)) ? $bgr_class_1 : $bgr_class_2;
$row_bgr = ($change_peers_bgr_over) ? " class=\"$bgr_class\" onmouseover=\"this.className='$bgr_class_over';\" onmouseout=\"this.className='$bgr_class';\"" : ''; $row_bgr = ($change_peers_bgr_over) ? " class=\"$bgr_class\" onmouseover=\"this.className='$bgr_class_over';\" onmouseout=\"this.className='$bgr_class';\"" : '';
$tr[$x]++; $tr[$x]++;
$peerTorrentClient = $lang['UNKNOWN'];
if (IS_AM || $peer['user_id'] == $userdata['user_id'] || !bf($peer['user_opt'], 'user_opt', 'user_hide_torrent_client')) {
if (isset($peer['peer_id'])) {
$peerTorrentClient = get_user_torrent_client($peer['peer_id']);
}
}
$peerCountry = $lang['UNKNOWN'];
if ($bb_cfg['ip2country_settings']['enabled']) {
if (IS_AM || $peer['user_id'] == $userdata['user_id'] || !bf($peer['user_opt'], 'user_opt', 'user_hide_peer_country')) {
if ($infoByIP = infoByIP((!empty($peer['ipv6']) ? $peer['ipv6'] : $peer['ip']), $peer['port'])) {
if (!empty($infoByIP['countryCode'])) {
$peerCountry = render_flag($infoByIP['countryCode'], false);
}
}
}
}
$template->assign_block_vars("$x_full.$x_row", [ $template->assign_block_vars("$x_full.$x_row", [
'ROW_BGR' => $row_bgr, 'ROW_BGR' => $row_bgr,
'NAME' => ($peer['update_time']) ? $name : "<s>$name</s>", 'NAME' => ($peer['update_time']) ? $name : "<s>$name</s>",
'PEER_ID' => isset($peer['peer_id']) ? get_user_torrent_client($peer['peer_id']) : $lang['UNKNOWN'], 'PEER_ID' => $peerTorrentClient,
'COUNTRY' => render_flag(infoByIP((!empty($peer['ipv6']) ? $peer['ipv6'] : $peer['ip']), $peer['port'])['countryCode'], false), 'COUNTRY' => $peerCountry,
'COMPL_PRC' => $compl_perc, 'COMPL_PRC' => $compl_perc,
'UP_TOTAL' => ($max_up_id[$x] == $pid) ? "<b>$up_tot</b>" : $up_tot, 'UP_TOTAL' => ($max_up_id[$x] == $pid) ? "<b>$up_tot</b>" : $up_tot,
'DOWN_TOTAL' => ($max_down_id[$x] == $pid) ? "<b>$down_tot</b>" : $down_tot, 'DOWN_TOTAL' => ($max_down_id[$x] == $pid) ? "<b>$down_tot</b>" : $down_tot,

View file

@ -342,7 +342,7 @@ function _set_var(&$result, $var, $type, $multibyte = false)
* @param $var_name * @param $var_name
* @param $default * @param $default
* @param bool $multibyte * @param bool $multibyte
* @return array * @return array|string
*/ */
function get_var($var_name, $default, $multibyte = false) function get_var($var_name, $default, $multibyte = false)
{ {

View file

@ -12,14 +12,14 @@ if (!defined('BB_ROOT')) {
} }
// Server settings // Server settings
$reserved_name = 'example.com'; $reserved_name = env('TP_HOST', 'example.com');
$reserved_port = 80; $reserved_port = env('TP_PORT', 80);
$bb_cfg = []; $bb_cfg = [];
// Version info // Version info
$bb_cfg['tp_version'] = 'v2.4.5'; $bb_cfg['tp_version'] = 'v2.4.5-rc.5';
$bb_cfg['tp_release_date'] = 'XX-XX-2025'; $bb_cfg['tp_release_date'] = '03-05-2025';
$bb_cfg['tp_release_codename'] = 'Cattle'; $bb_cfg['tp_release_codename'] = 'Cattle';
// Increase version number after changing JS or CSS // Increase version number after changing JS or CSS
@ -144,10 +144,12 @@ $bb_cfg['torr_server'] = [
'disable_for_guest' => true 'disable_for_guest' => true
]; ];
// IndexNow settings // FreeIPAPI settings
$bb_cfg['indexnow_settings'] = [ $bb_cfg['ip2country_settings'] = [
'enabled' => false, // Documentation: https://docs.freeipapi.com/
'host' => 'bing', // Available: yandex, bing, seznam, naver 'enabled' => true,
'endpoint' => 'https://freeipapi.com/api/json/',
'api_token' => '', // not required for basic usage
]; ];
// FAQ url help link // FAQ url help link
@ -193,6 +195,7 @@ $bb_cfg['posting_url'] = 'posting.php'; # "http://{$domain_name}/posting.php"
$bb_cfg['pm_url'] = 'privmsg.php'; # "http://{$domain_name}/privmsg.php" $bb_cfg['pm_url'] = 'privmsg.php'; # "http://{$domain_name}/privmsg.php"
// Language // Language
$bb_cfg['auto_language_detection'] = true; // Use browser language (auto-detect) as default language for guests
$bb_cfg['lang'] = [ $bb_cfg['lang'] = [
// Languages available for selecting // Languages available for selecting
'af' => [ 'af' => [
@ -425,7 +428,7 @@ $bb_cfg['invites_system'] = [
// Syntax: 'invite_code' => 'validity_period' // Syntax: 'invite_code' => 'validity_period'
// The 'validity_period' value is based on strtotime() function: https://www.php.net/manual/en/function.strtotime.php // The 'validity_period' value is based on strtotime() function: https://www.php.net/manual/en/function.strtotime.php
// You can also create a permanent invite, set 'permanent' value for 'validity_period' // You can also create a permanent invite, set 'permanent' value for 'validity_period'
// Invite link example: site_url/profile.php?mode=register&invite=new_year // Invite link example: site_url/profile.php?mode=register&invite=new_year2023
'new_year2023' => '2022-12-31 00:00:01', 'new_year2023' => '2022-12-31 00:00:01',
'340c4bb6ea2d284c13e085b60b990a8a' => '12 April 1961', '340c4bb6ea2d284c13e085b60b990a8a' => '12 April 1961',
'tp_birthday' => '2005-04-04', 'tp_birthday' => '2005-04-04',
@ -434,22 +437,23 @@ $bb_cfg['invites_system'] = [
]; ];
$bb_cfg['password_symbols'] = [ $bb_cfg['password_symbols'] = [
// What symbols should be required in the password // What symbols should be required in the password
'nums' => true, // Numeric 'nums' => true,
'spec_symbols' => false, // Special symbols 'spec_symbols' => false,
'letters' => [ // Letters 'letters' => [
'uppercase' => true, // Uppercase letters 'uppercase' => false,
'lowercase' => true // Lowercase letters 'lowercase' => true
] ]
]; ];
$bb_cfg['password_hash_options'] = [ $bb_cfg['password_hash_options'] = [
// https://www.php.net/manual/ru/password.constants.php // https://www.php.net/manual/ru/password.constants.php
'algo' => PASSWORD_BCRYPT, 'algo' => PASSWORD_BCRYPT,
'options' => [] 'options' => ['cost' => 12]
]; ];
// Email // Email
$bb_cfg['emailer'] = [ $bb_cfg['emailer'] = [
'enabled' => true, 'enabled' => true,
'sendmail_command' => '/usr/sbin/sendmail -bs',
'smtp' => [ 'smtp' => [
'enabled' => false, // send email via external SMTP server 'enabled' => false, // send email via external SMTP server
'host' => 'localhost', // SMTP server host 'host' => 'localhost', // SMTP server host
@ -521,7 +525,10 @@ $bb_cfg['sf_on_first_page_only'] = true; // Show subforums only on the first pag
$bb_cfg['allowed_topics_per_page'] = [50, 100, 150, 200, 250, 300]; // Allowed number of topics per page $bb_cfg['allowed_topics_per_page'] = [50, 100, 150, 200, 250, 300]; // Allowed number of topics per page
// Topics // Topics
$bb_cfg['show_post_bbcode_button'] = true; // Show "Code" button in topic to display BBCode of topic $bb_cfg['show_post_bbcode_button'] = [ // Show "Code" button in topic to display BBCode of topic
'enabled' => true,
'only_for_first_post' => true,
];
$bb_cfg['show_quick_reply'] = true; // Show quick reply forim $bb_cfg['show_quick_reply'] = true; // Show quick reply forim
$bb_cfg['show_rank_text'] = false; // Show user rank name in topics $bb_cfg['show_rank_text'] = false; // Show user rank name in topics
$bb_cfg['show_rank_image'] = true; // Show user rank image in topics $bb_cfg['show_rank_image'] = true; // Show user rank image in topics
@ -602,7 +609,6 @@ $bb_cfg['flist_max_files'] = 0; // Max allowed number of files to process for gi
$bb_cfg['last_visit_date_format'] = 'd-M H:i'; $bb_cfg['last_visit_date_format'] = 'd-M H:i';
$bb_cfg['last_post_date_format'] = 'd-M-y H:i'; $bb_cfg['last_post_date_format'] = 'd-M-y H:i';
$bb_cfg['poll_max_days'] = 180; // How many days will the poll be active $bb_cfg['poll_max_days'] = 180; // How many days will the poll be active
$bb_cfg['integrity_check'] = true; // TorrentPier files integrity check
$bb_cfg['allow_change'] = [ $bb_cfg['allow_change'] = [
'language' => true, // Allow user to change language 'language' => true, // Allow user to change language
@ -670,12 +676,12 @@ $bb_cfg['group_avatars'] = [
]; ];
// Captcha // Captcha
// Get a Google reCAPTCHA API Key: https://www.google.com/recaptcha/admin
$bb_cfg['captcha'] = [ $bb_cfg['captcha'] = [
'disabled' => true, 'disabled' => true,
'service' => 'googleV3', // Available services: text, googleV2, googleV3, hCaptcha, yandex, cloudflare
'public_key' => '', 'public_key' => '',
'secret_key' => '', 'secret_key' => '',
'theme' => 'light', // theming (available: light, dark) 'theme' => 'light', // theming (available: light, dark) (working only if supported by captcha service)
]; ];
// Atom feed // Atom feed
@ -736,7 +742,8 @@ $bb_cfg['tracker'] = [
'gold_silver_enabled' => true, // golden / silver days mode (If enabled, then disable "freeleech") 'gold_silver_enabled' => true, // golden / silver days mode (If enabled, then disable "freeleech")
'hybrid_stat_protocol' => 1, // For hybrid torrents there are two identical requests sent by clients, for counting stats we gotta choose one, you can change this to '2' in future, when v1 protocol is outdated 'hybrid_stat_protocol' => 1, // For hybrid torrents there are two identical requests sent by clients, for counting stats we gotta choose one, you can change this to '2' in future, when v1 protocol is outdated
'disabled_v1_torrents' => false, // disallow registration of v1-only torrents, for future implementations where client will use v2 only and there won't be need for v1, thus relieving tracker 'disabled_v1_torrents' => false, // disallow registration of v1-only torrents, for future implementations where client will use v2 only and there won't be need for v1, thus relieving tracker
'disabled_v2_torrents' => false // disallow registration of v2-only torrents 'disabled_v2_torrents' => false, // disallow registration of v2-only torrents
'use_old_torrent_name_format' => false, // when enabled, the names of torrent files will have the classic format: [yoursite.com].txxx.torrent
]; ];
// Ratio settings // Ratio settings

View file

@ -33,13 +33,8 @@ define('APP_NAME', 'TorrentPier');
define('DEFAULT_CHARSET', 'UTF-8'); define('DEFAULT_CHARSET', 'UTF-8');
define('UPDATER_URL', 'https://api.github.com/repos/torrentpier/torrentpier/releases'); define('UPDATER_URL', 'https://api.github.com/repos/torrentpier/torrentpier/releases');
define('UPDATER_FILE', INT_DATA_DIR . '/updater.json'); define('UPDATER_FILE', INT_DATA_DIR . '/updater.json');
define('CHECKSUMS_FILE', INT_DATA_DIR . '/checksums.md5');
define('RESTORE_CORRUPT_CONFIRM_FILE', INT_DATA_DIR . '/rescorrupt.integrity');
define('COOKIE_DBG', 'bb_dbg'); define('COOKIE_DBG', 'bb_dbg');
// TODO: Move in another section
define('API_IP_URL', 'https://freeipapi.com/api/json/');
// Templates // Templates
define('ADMIN_TPL_DIR', TEMPLATES_DIR . '/admin/'); define('ADMIN_TPL_DIR', TEMPLATES_DIR . '/admin/');
define('XS_USE_ISSET', '1'); define('XS_USE_ISSET', '1');

View file

@ -1 +0,0 @@
Require all denied

View file

@ -118,7 +118,7 @@ function generate_smilies($mode)
$data = $datastore->get('smile_replacements'); $data = $datastore->get('smile_replacements');
if ($sql = $data['smile']) { if (isset($data['smile']) && $sql = $data['smile']) {
$num_smilies = 0; $num_smilies = 0;
$rowset = []; $rowset = [];
foreach ($sql as $row) { foreach ($sql as $row) {

View file

@ -54,27 +54,10 @@ if (empty($bb_cfg['bt_announce_url']) || ($bb_cfg['bt_announce_url'] === 'https:
bb_update_config(['bt_announce_url' => FULL_URL . 'bt/announce.php']); bb_update_config(['bt_announce_url' => FULL_URL . 'bt/announce.php']);
} }
// [Demo mode] Allow registering torrents by default // [Demo mode] Allow registering torrents by default for "Your first forum"
if (IN_DEMO_MODE) { if (IN_DEMO_MODE) {
DB()->query("UPDATE " . BB_FORUMS . " SET allow_reg_tracker = 1 WHERE allow_reg_tracker = 0"); DB()->query("UPDATE " . BB_FORUMS . " SET allow_reg_tracker = 1 WHERE allow_reg_tracker = 0 AND forum_id = 1 LIMIT 1");
}
// Create unique TorrentPier instance hash
if (empty($bb_cfg['tp_instance_hash']) || ($bb_cfg['tp_instance_hash'] !== hash('xxh128', FULL_URL))) {
bb_update_config(['tp_instance_hash' => hash('xxh128', FULL_URL)]);
}
// Generate IndexNow key
if ($bb_cfg['indexnow_settings']['enabled'] && !is_file(BB_ROOT . $bb_cfg['indexnow_key'] . \TorrentPier\IndexNow::$keyFileExtension)) {
$randomIndexNowKey = empty($bb_cfg['indexnow_key']) ? make_rand_str(rand(64, 128)) : $bb_cfg['indexnow_key'];
if ($bb_cfg['indexnow_key'] !== $randomIndexNowKey) {
bb_update_config(['indexnow_key' => $randomIndexNowKey]);
}
file_write($randomIndexNowKey, (BB_ROOT . $randomIndexNowKey . \TorrentPier\IndexNow::$keyFileExtension));
} }
// Check for updates // Check for updates
$datastore->update('check_updates'); $datastore->update('check_updates');
// Integrity check
$datastore->update('files_integrity');

View file

@ -29,25 +29,18 @@ if ($bb_cfg['seed_bonus_enabled'] && $bb_cfg['seed_bonus_points'] && $bb_cfg['se
WHERE tor.topic_id = bt.topic_id WHERE tor.topic_id = bt.topic_id
AND tor.size > $tor_size AND tor.size > $tor_size
AND bt.seeder > 0 AND bt.seeder > 0
GROUP BY user_id GROUP BY bt.user_id
"); ");
$seed_bonus = unserialize($bb_cfg['seed_bonus_points']); $seed_bonus = unserialize($bb_cfg['seed_bonus_points']);
$seed_release = unserialize($bb_cfg['seed_bonus_release']); $seed_release = unserialize($bb_cfg['seed_bonus_release']);
$sql = "SELECT last_run
FROM " . BB_CRON . "
WHERE cron_script = '" . basename(__FILE__) . "'
LIMIT 1";
$cron_runs = DB()->fetch_row($sql);
$cron_job_last_run = (TIMENOW - strtotime($cron_runs['last_run']));
foreach ($seed_bonus as $i => $points) { foreach ($seed_bonus as $i => $points) {
if (!$points || !$seed_release[$i]) { if (!$points || !$seed_release[$i]) {
continue; continue;
} }
$user_points = ($cron_job_last_run < 3600) ? round((float)$points * ($cron_job_last_run / 3600), 2) : 0; $user_points = ((float)$points / 4);
$release = (int)$seed_release[$i]; $release = (int)$seed_release[$i];
$user_regdate = (TIMENOW - $bb_cfg['seed_bonus_user_regdate'] * 86400); $user_regdate = (TIMENOW - $bb_cfg['seed_bonus_user_regdate'] * 86400);

View file

@ -1,95 +0,0 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2025 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
if (!defined('BB_ROOT')) {
die(basename(__FILE__));
}
global $bb_cfg;
if (!$bb_cfg['integrity_check']) {
return;
}
$filesList = [];
$wrongFilesList = [];
$checksumFile = new SplFileObject(CHECKSUMS_FILE, 'r');
$checksumFile->setFlags(SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE);
$ignoreFiles = [
'.env.example',
'.htaccess',
'robots.txt',
'install.php',
'favicon.png',
'composer.json',
'composer.lock',
hide_bb_path(CHECKSUMS_FILE),
hide_bb_path(BB_ENABLED),
'library/config.php',
'library/defines.php',
'styles/images/logo/logo.png'
];
foreach ($checksumFile as $line) {
$parts = explode(' ', $line);
if (!isset($parts[0]) || !isset($parts[1])) {
// Skip end line
break;
}
if (!empty($ignoreFiles) && in_array($parts[1], $ignoreFiles)) {
// Skip files from "Ignoring list"
continue;
}
$filesList[] = [
'path' => trim($parts[1]),
'hash' => trim($parts[0])
];
}
foreach ($filesList as $file) {
if (!file_exists(BB_ROOT . $file['path']) || (strtolower(md5_file(BB_ROOT . $file['path'])) !== strtolower($file['hash']))) {
$wrongFilesList[] = $file['path'];
}
}
// Restore corrupt files
if (is_file(RESTORE_CORRUPT_CONFIRM_FILE)) {
$buildDownloader = new \TorrentPier\Updater();
if ($buildDownloader->download(INT_DATA_DIR . '/', $bb_cfg['tp_version'])) {
// Unzip downloaded build file
$zipArchive = new ZipArchive;
$extractDownloadedFile = $zipArchive->open($buildDownloader->savePath);
if ($extractDownloadedFile === true) {
if ($zipArchive->extractTo(BB_ROOT, $wrongFilesList)) {
$wrongFilesList = [];
}
$zipArchive->close();
}
}
// Delete restore confirm file & build file
if (isset($buildDownloader->savePath)) {
unlink($buildDownloader->savePath);
}
if (is_file(RESTORE_CORRUPT_CONFIRM_FILE)) {
unlink(RESTORE_CORRUPT_CONFIRM_FILE);
}
}
$data = [
'success' => empty($wrongFilesList),
'wrong_files' => $wrongFilesList,
'wrong_files_num' => count($wrongFilesList),
'total_num' => count($filesList),
'timestamp' => TIMENOW,
];
$this->store('files_integrity', $data);

View file

@ -197,6 +197,8 @@ $bf['user_opt'] = [
'dis_post_edit' => 13, // [PROHIBITIONS] Block editing own posts / topics 'dis_post_edit' => 13, // [PROHIBITIONS] Block editing own posts / topics
'user_dls' => 14, // [SETTINGS] Hide list of "Current downloads" in my profile 'user_dls' => 14, // [SETTINGS] Hide list of "Current downloads" in my profile
'user_retracker' => 15, // [SETTINGS] Add my retracker into downloaded torrent files 'user_retracker' => 15, // [SETTINGS] Add my retracker into downloaded torrent files
'user_hide_torrent_client' => 16, // [SETTINGS] Option to hide user's torrent client in peer list
'user_hide_peer_country' => 17 // [SETTINGS] Option to hide user's country name in peer list
]; ];
function bit2dec($bit_num) function bit2dec($bit_num)
@ -601,7 +603,13 @@ function bt_show_ip($ip, $port = '')
if (IS_AM) { if (IS_AM) {
$ip = \TorrentPier\Helpers\IPHelper::long2ip_extended($ip); $ip = \TorrentPier\Helpers\IPHelper::long2ip_extended($ip);
$ip .= ($port) ? ":$port" : '';
// Wrap IPv6 address in square brackets
if ($port && str_contains($ip, ':')) {
$ip = "[$ip]";
}
$ip .= $port ? ":$port" : '';
return $ip; return $ip;
} }
@ -876,8 +884,8 @@ function show_bt_userdata($user_id): void
'YS_BONUS' => humn_size($btu['up_bonus_yesterday']), 'YS_BONUS' => humn_size($btu['up_bonus_yesterday']),
'YS_POINTS' => $btu['auth_key'] ? $btu['points_yesterday'] : '0.00', 'YS_POINTS' => $btu['auth_key'] ? $btu['points_yesterday'] : '0.00',
'SPEED_UP' => humn_size($btu['speed_up'], 0, 'KB') . '/s', 'SPEED_UP' => humn_size($btu['speed_up'], min: 'KB') . '/s',
'SPEED_DOWN' => humn_size($btu['speed_down'], 0, 'KB') . '/s', 'SPEED_DOWN' => humn_size($btu['speed_down'], min: 'KB') . '/s',
]); ]);
} }
@ -898,13 +906,16 @@ function bb_get_config($table, $from_db = false, $update_cache = true)
{ {
if ($from_db or !$cfg = CACHE('bb_config')->get("config_{$table}")) { if ($from_db or !$cfg = CACHE('bb_config')->get("config_{$table}")) {
$cfg = []; $cfg = [];
foreach (DB()->fetch_rowset("SELECT * FROM $table") as $row) { foreach (DB()->fetch_rowset("SELECT * FROM $table") as $row) {
$cfg[$row['config_name']] = $row['config_value']; $cfg[$row['config_name']] = $row['config_value'];
} }
if ($update_cache) { if ($update_cache) {
CACHE('bb_config')->set("config_{$table}", $cfg); CACHE('bb_config')->set("config_{$table}", $cfg);
} }
} }
return $cfg; return $cfg;
} }
@ -1184,14 +1195,21 @@ function render_flag(string $code, bool $showName = true): string
global $lang; global $lang;
static $iconExtension = '.svg'; static $iconExtension = '.svg';
$nameIgnoreList = [
'WBW',
'PACE',
'LGBT'
];
if (isset($lang['COUNTRIES'][$code])) { if (isset($lang['COUNTRIES'][$code])) {
if ($code === '0') { if ($code === '0') {
return ''; // No selected return ''; // No selected
} else { } else {
$flagIconPath = BB_ROOT . 'styles/images/flags/' . $code . $iconExtension; $flagIconPath = BB_ROOT . 'styles/images/flags/' . $code . $iconExtension;
if (is_file($flagIconPath)) { if (is_file($flagIconPath)) {
$countryName = $showName ? '&nbsp;' . str_short($lang['COUNTRIES'][$code], 20) : ''; $langName = $lang['COUNTRIES'][$code];
return '<span title="' . $lang['COUNTRIES'][$code] . '"><img src="' . $flagIconPath . '" class="poster-flag" alt="' . $code . '">' . $countryName . '</span>'; $countryName = ($showName && !in_array($code, $nameIgnoreList)) ? '&nbsp;' . str_short($langName, 20) : '';
return '<span title="' . $langName . '"><img src="' . $flagIconPath . '" class="poster-flag" alt="' . $code . '">' . $countryName . '</span>';
} }
} }
} }
@ -1224,11 +1242,16 @@ function generate_pagination($base_url, $num_items, $per_page, $start_item, $add
$total_pages = ceil($num_items / $per_page); $total_pages = ceil($num_items / $per_page);
$on_page = floor($start_item / $per_page) + 1; $on_page = floor($start_item / $per_page) + 1;
$query_separator = '&amp;';
if (!str_contains($base_url, '?')) {
$query_separator = '?';
}
$page_string = ''; $page_string = '';
if ($total_pages > ((2 * ($begin_end + $from_middle)) + 2)) { if ($total_pages > ((2 * ($begin_end + $from_middle)) + 2)) {
$init_page_max = ($total_pages > $begin_end) ? $begin_end : $total_pages; $init_page_max = ($total_pages > $begin_end) ? $begin_end : $total_pages;
for ($i = 1; $i < $init_page_max + 1; $i++) { for ($i = 1; $i < $init_page_max + 1; $i++) {
$page_string .= ($i == $on_page) ? '<b>' . $i . '</b>' : '<a href="' . $base_url . "&amp;start=" . (($i - 1) * $per_page) . '">' . $i . '</a>'; $page_string .= ($i == $on_page) ? '<b>' . $i . '</b>' : '<a href="' . $base_url . "{$query_separator}start=" . (($i - 1) * $per_page) . '">' . $i . '</a>';
if ($i < $init_page_max) { if ($i < $init_page_max) {
$page_string .= ", "; $page_string .= ", ";
} }
@ -1242,7 +1265,7 @@ function generate_pagination($base_url, $num_items, $per_page, $start_item, $add
$init_page_max = ($on_page < $total_pages - ($begin_end + $from_middle)) ? $on_page : $total_pages - ($begin_end + $from_middle); $init_page_max = ($on_page < $total_pages - ($begin_end + $from_middle)) ? $on_page : $total_pages - ($begin_end + $from_middle);
for ($i = $init_page_min - $from_middle; $i < $init_page_max + ($from_middle + 1); $i++) { for ($i = $init_page_min - $from_middle; $i < $init_page_max + ($from_middle + 1); $i++) {
$page_string .= ($i == $on_page) ? '<b>' . $i . '</b>' : '<a href="' . $base_url . "&amp;start=" . (($i - 1) * $per_page) . '">' . $i . '</a>'; $page_string .= ($i == $on_page) ? '<b>' . $i . '</b>' : '<a href="' . $base_url . "{$query_separator}start=" . (($i - 1) * $per_page) . '">' . $i . '</a>';
if ($i < $init_page_max + $from_middle) { if ($i < $init_page_max + $from_middle) {
$page_string .= ', '; $page_string .= ', ';
} }
@ -1252,7 +1275,7 @@ function generate_pagination($base_url, $num_items, $per_page, $start_item, $add
$page_string .= '&nbsp;...&nbsp;'; $page_string .= '&nbsp;...&nbsp;';
} }
for ($i = $total_pages - ($begin_end - 1); $i < $total_pages + 1; $i++) { for ($i = $total_pages - ($begin_end - 1); $i < $total_pages + 1; $i++) {
$page_string .= ($i == $on_page) ? '<b>' . $i . '</b>' : '<a href="' . $base_url . "&amp;start=" . (($i - 1) * $per_page) . '">' . $i . '</a>'; $page_string .= ($i == $on_page) ? '<b>' . $i . '</b>' : '<a href="' . $base_url . "{$query_separator}start=" . (($i - 1) * $per_page) . '">' . $i . '</a>';
if ($i < $total_pages) { if ($i < $total_pages) {
$page_string .= ", "; $page_string .= ", ";
} }
@ -1260,7 +1283,7 @@ function generate_pagination($base_url, $num_items, $per_page, $start_item, $add
} }
} else { } else {
for ($i = 1; $i < $total_pages + 1; $i++) { for ($i = 1; $i < $total_pages + 1; $i++) {
$page_string .= ($i == $on_page) ? '<b>' . $i . '</b>' : '<a href="' . $base_url . "&amp;start=" . (($i - 1) * $per_page) . '">' . $i . '</a>'; $page_string .= ($i == $on_page) ? '<b>' . $i . '</b>' : '<a href="' . $base_url . "{$query_separator}start=" . (($i - 1) * $per_page) . '">' . $i . '</a>';
if ($i < $total_pages) { if ($i < $total_pages) {
$page_string .= ', '; $page_string .= ', ';
} }
@ -1269,20 +1292,20 @@ function generate_pagination($base_url, $num_items, $per_page, $start_item, $add
if ($add_prevnext_text) { if ($add_prevnext_text) {
if ($on_page > 1) { if ($on_page > 1) {
$page_string = ' <a href="' . $base_url . "&amp;start=" . (($on_page - 2) * $per_page) . '">' . $lang['PREVIOUS_PAGE'] . '</a>&nbsp;&nbsp;' . $page_string; $page_string = ' <a href="' . $base_url . "{$query_separator}start=" . (($on_page - 2) * $per_page) . '">' . $lang['PREVIOUS_PAGE'] . '</a>&nbsp;&nbsp;' . $page_string;
$meta_prev_link = FULL_URL . $base_url . "&amp;start=" . (($on_page - 2) * $per_page); $meta_prev_link = FULL_URL . $base_url . "{$query_separator}start=" . (($on_page - 2) * $per_page);
} }
if ($on_page < $total_pages) { if ($on_page < $total_pages) {
$page_string .= '&nbsp;&nbsp;<a href="' . $base_url . "&amp;start=" . ($on_page * $per_page) . '">' . $lang['NEXT_PAGE'] . '</a>'; $page_string .= '&nbsp;&nbsp;<a href="' . $base_url . "{$query_separator}start=" . ($on_page * $per_page) . '">' . $lang['NEXT_PAGE'] . '</a>';
$meta_next_link = FULL_URL . $base_url . "&amp;start=" . ($on_page * $per_page); $meta_next_link = FULL_URL . $base_url . "{$query_separator}start=" . ($on_page * $per_page);
} }
} }
$pagination = false; $pagination = false;
if ($page_string && $total_pages > 1) { if ($page_string && $total_pages > 1) {
$pagination = '<a class="menu-root" href="#pg-jump">' . $lang['GOTO_PAGE'] . '</a> :&nbsp;&nbsp;' . $page_string; $pagination = '<a class="menu-root" href="#pg-jump">' . $lang['GOTO_PAGE'] . '</a> :&nbsp;&nbsp;' . $page_string;
$pagination = str_replace('&amp;start=0', '', $pagination); $pagination = str_replace("{$query_separator}start=0", '', $pagination);
} }
$template->assign_vars([ $template->assign_vars([
@ -1577,7 +1600,7 @@ function build_topic_pagination($url, $replies, $per_page)
return $pg; return $pg;
} }
function print_confirmation($tpl_vars) function print_confirmation($tpl_vars): void
{ {
global $template, $lang; global $template, $lang;
@ -1796,14 +1819,14 @@ function decode_text_match($txt)
/** /**
* Create magnet link * Create magnet link
* *
* @param string $infohash * @param string $infohash (xt=urn:btih)
* @param string $infohash_v2 * @param string $infohash_v2 (xt=urn:btmh:1220)
* @param string $auth_key * @param string $auth_key (tr)
* @param string $name * @param string $name (dn)
* * @param int|string $length (xl)
* @return string * @return string
*/ */
function create_magnet(string $infohash, string $infohash_v2, string $auth_key, string $name): string function create_magnet(string $infohash, string $infohash_v2, string $auth_key, string $name, int|string $length = 0): string
{ {
global $bb_cfg, $images, $lang; global $bb_cfg, $images, $lang;
@ -1832,6 +1855,11 @@ function create_magnet(string $infohash, string $infohash_v2, string $auth_key,
$magnet .= 'xt=urn:btmh:1220' . bin2hex($infohash_v2); $magnet .= 'xt=urn:btmh:1220' . bin2hex($infohash_v2);
} }
$length = (int)$length;
if ($length > 0) {
$magnet .= '&xl=' . $length;
}
return '<a title="' . ($v2_support ? $lang['MAGNET_v2'] : $lang['MAGNET']) . '" href="' . $magnet . '&tr=' . urlencode($bb_cfg['bt_announce_url'] . "?{$bb_cfg['passkey_key']}=$auth_key") . '&dn=' . urlencode($name) . '"><img src="' . ($v2_support ? $images['icon_magnet_v2'] : $images['icon_magnet']) . '" width="12" height="12" border="0" /></a>'; return '<a title="' . ($v2_support ? $lang['MAGNET_v2'] : $lang['MAGNET']) . '" href="' . $magnet . '&tr=' . urlencode($bb_cfg['bt_announce_url'] . "?{$bb_cfg['passkey_key']}=$auth_key") . '&dn=' . urlencode($name) . '"><img src="' . ($v2_support ? $images['icon_magnet_v2'] : $images['icon_magnet']) . '" width="12" height="12" border="0" /></a>';
} }
@ -1868,7 +1896,7 @@ function send_pm($user_id, $subject, $message, $poster_id = BOT_UID)
$message = DB()->escape($message); $message = DB()->escape($message);
if ($poster_id == BOT_UID) { if ($poster_id == BOT_UID) {
$poster_ip = '7f000001'; $poster_ip = '0';
} elseif ($row = DB()->fetch_row("SELECT user_reg_ip FROM " . BB_USERS . " WHERE user_id = $poster_id")) { } elseif ($row = DB()->fetch_row("SELECT user_reg_ip FROM " . BB_USERS . " WHERE user_id = $poster_id")) {
$poster_ip = $row['user_reg_ip']; $poster_ip = $row['user_reg_ip'];
} else { } else {
@ -2044,56 +2072,51 @@ function hash_search($hash)
} }
/** /**
* Функция для получения и проверки правильности ответа от Google ReCaptcha. * Function for checking captcha answer
*
* @param $mode
* @param string $callback
* *
* @param string $mode
* @return bool|string * @return bool|string
*/ */
function bb_captcha($mode, $callback = '') function bb_captcha(string $mode): bool|string
{ {
global $bb_cfg, $lang; global $bb_cfg, $lang;
$secret = $bb_cfg['captcha']['secret_key']; $settings = $bb_cfg['captcha'];
$public = $bb_cfg['captcha']['public_key']; $settings['language'] = $bb_cfg['default_lang'];
$cp_theme = $bb_cfg['captcha']['theme'] ?? 'light';
if (!$bb_cfg['captcha']['disabled'] && (!$public || !$secret)) { // Checking captcha settings
if (!$settings['disabled'] && $settings['service'] !== 'text') {
if (empty($settings['public_key']) || empty($settings['secret_key'])) {
bb_die($lang['CAPTCHA_SETTINGS']); bb_die($lang['CAPTCHA_SETTINGS']);
} }
}
$reCaptcha = new \ReCaptcha\ReCaptcha($secret); // Selecting captcha service
$captchaClasses = [
'googleV2' => \TorrentPier\Captcha\GoogleCaptchaV2::class,
'googleV3' => \TorrentPier\Captcha\GoogleCaptchaV3::class,
'hCaptcha' => \TorrentPier\Captcha\HCaptcha::class,
'yandex' => \TorrentPier\Captcha\YandexSmartCaptcha::class,
'cloudflare' => \TorrentPier\Captcha\CloudflareTurnstileCaptcha::class,
'text' => \TorrentPier\Captcha\TextCaptcha::class
];
if (!isset($captchaClasses[$settings['service']])) {
bb_die(sprintf('Captcha service (%s) not supported', $settings['service']));
}
$captchaClass = $captchaClasses[$settings['service']];
$captcha = new $captchaClass($settings);
// Selection mode
if (isset($captcha)) {
switch ($mode) { switch ($mode) {
case 'get': case 'get':
return "
<script type=\"text/javascript\">
var onloadCallback = function() {
grecaptcha.render('tp-captcha', {
'sitekey' : '" . $public . "',
'theme' : '" . $cp_theme . "',
'callback' : '" . $callback . "'
});
};
</script>
<div id=\"tp-captcha\"></div>
<script src=\"https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit\" async defer></script>";
break;
case 'check': case 'check':
$resp = $reCaptcha->verify( return $captcha->$mode();
request_var('g-recaptcha-response', ''),
$_SERVER["REMOTE_ADDR"]
);
if ($resp->isSuccess()) {
return true;
}
break;
default: default:
bb_simple_die(__FUNCTION__ . ": invalid mode '$mode'"); bb_die(sprintf('Invalid mode: %s', $mode));
} }
}
return false; return false;
} }
@ -2131,10 +2154,7 @@ function getBanInfo(?int $userId = null): ?array
global $datastore; global $datastore;
// Get bans info from datastore // Get bans info from datastore
if (!$bans = $datastore->get('ban_list')) {
$datastore->update('ban_list');
$bans = $datastore->get('ban_list'); $bans = $datastore->get('ban_list');
}
if (!isset($userId)) { if (!isset($userId)) {
return $bans; return $bans;
@ -2166,10 +2186,31 @@ function readUpdaterFile(): array|bool
*/ */
function infoByIP(string $ipAddress, int $port = 0): array function infoByIP(string $ipAddress, int $port = 0): array
{ {
if (!$data = CACHE('bb_ip2countries')->get($ipAddress . '_' . $port)) { global $bb_cfg;
if (!$bb_cfg['ip2country_settings']['enabled']) {
return [];
}
$ipAddress = \TorrentPier\Helpers\IPHelper::long2ip_extended($ipAddress);
$cacheName = hash('xxh128', ($ipAddress . '_' . $port));
if (!$data = CACHE('bb_ip2countries')->get($cacheName)) {
$data = []; $data = [];
$response = file_get_contents(API_IP_URL . $ipAddress);
$contextOptions = [];
if (!empty($bb_cfg['ip2country_settings']['api_token'])) {
$contextOptions['http'] = [
'header' => "Authorization: Bearer " . $bb_cfg['ip2country_settings']['api_token'] . "\r\n"
];
}
$context = stream_context_create($contextOptions);
$response = file_get_contents($bb_cfg['ip2country_settings']['endpoint'] . $ipAddress, context: $context);
if ($response !== false) {
$json = json_decode($response, true); $json = json_decode($response, true);
if (is_array($json) && !empty($json)) { if (is_array($json) && !empty($json)) {
$data = [ $data = [
'ipVersion' => $json['ipVersion'], 'ipVersion' => $json['ipVersion'],
@ -2177,9 +2218,17 @@ function infoByIP(string $ipAddress, int $port = 0): array
'continent' => $json['continent'], 'continent' => $json['continent'],
'continentCode' => $json['continentCode'] 'continentCode' => $json['continentCode']
]; ];
CACHE('bb_ip2countries')->set($ipAddress . '_' . $port, $data, 1200);
} }
} }
if (empty($data)) {
$data = [
'response' => false,
'timestamp' => TIMENOW
];
}
CACHE('bb_ip2countries')->set($cacheName, $data, 1200);
}
return $data; return $data;
} }

View file

@ -299,6 +299,9 @@ define('HTML_DISABLED', ' disabled ');
define('HTML_READONLY', ' readonly '); define('HTML_READONLY', ' readonly ');
define('HTML_SELECTED', ' selected '); define('HTML_SELECTED', ' selected ');
define('EMAIL_TYPE_HTML', 'text/html');
define('EMAIL_TYPE_TEXT', 'text/plain');
// $GPC // $GPC
define('KEY_NAME', 0); // position in $GPC['xxx'] define('KEY_NAME', 0); // position in $GPC['xxx']
define('DEF_VAL', 1); define('DEF_VAL', 1);
@ -384,11 +387,6 @@ $user = new TorrentPier\Legacy\Common\User();
$userdata =& $user->data; $userdata =& $user->data;
/**
* Some shared defines
*/
define('TP_INSTANCE_HASH', $bb_cfg['tp_instance_hash']);
/** /**
* Cron * Cron
*/ */

View file

@ -14,9 +14,11 @@ if (!defined('BB_ROOT')) {
global $bb_cfg, $userdata, $template, $DBS, $lang; global $bb_cfg, $userdata, $template, $DBS, $lang;
if (!empty($template)) { if (!empty($template)) {
$birthday_tp = ((string)bb_date(TIMENOW, 'd.m', false) === '04.04') ? '&nbsp;|&nbsp;&#127881;&#127856;&#128154;' : '';
$template->assign_vars([ $template->assign_vars([
'SIMPLE_FOOTER' => !empty($gen_simple_header), 'SIMPLE_FOOTER' => !empty($gen_simple_header),
'POWERED' => 'Fueled by <a target="_blank" referrerpolicy="origin" href="https://github.com/torrentpier/torrentpier">TorrentPier</a> &copy; 2005-' . date('Y'), 'POWERED' => 'Fueled by <a target="_blank" referrerpolicy="origin" href="https://github.com/torrentpier/torrentpier">TorrentPier</a> &copy; 2005-' . date('Y') . $birthday_tp,
'SHOW_ADMIN_LINK' => (IS_ADMIN && !defined('IN_ADMIN')), 'SHOW_ADMIN_LINK' => (IS_ADMIN && !defined('IN_ADMIN')),
'ADMIN_LINK_HREF' => 'admin/index.php', 'ADMIN_LINK_HREF' => 'admin/index.php',
]); ]);
@ -33,7 +35,7 @@ if (!$bb_cfg['gzip_compress']) {
if ($show_dbg_info) { if ($show_dbg_info) {
$gen_time = utime() - TIMESTART; $gen_time = utime() - TIMESTART;
$gen_time_txt = sprintf('%.4f', $gen_time); $gen_time_txt = sprintf('%.3f', $gen_time);
$gzip_text = UA_GZIP_SUPPORTED ? "{$lang['GZIP_COMPRESSION']}: " : "<s>{$lang['GZIP_COMPRESSION']}:</s> "; $gzip_text = UA_GZIP_SUPPORTED ? "{$lang['GZIP_COMPRESSION']}: " : "<s>{$lang['GZIP_COMPRESSION']}:</s> ";
$gzip_text .= $bb_cfg['gzip_compress'] ? $lang['ON'] : $lang['OFF']; $gzip_text .= $bb_cfg['gzip_compress'] ? $lang['ON'] : $lang['OFF'];
@ -41,7 +43,7 @@ if ($show_dbg_info) {
if (!empty($DBS)) { if (!empty($DBS)) {
$sql_t = $DBS->sql_timetotal; $sql_t = $DBS->sql_timetotal;
$sql_time_txt = ($sql_t) ? sprintf('%.4f ' . $lang['SEC'] . ' (%d%%) &middot; ', $sql_t, round($sql_t * 100 / $gen_time)) : ''; $sql_time_txt = ($sql_t) ? sprintf('%.3f ' . $lang['SEC'] . ' (%d%%) &middot; ', $sql_t, round($sql_t * 100 / $gen_time)) : '';
$num_q = $DBS->num_queries; $num_q = $DBS->num_queries;
$stat .= " &nbsp;|&nbsp; {$DBS->get_db_obj()->engine}: {$sql_time_txt}{$num_q} " . $lang['QUERIES']; $stat .= " &nbsp;|&nbsp; {$DBS->get_db_obj()->engine}: {$sql_time_txt}{$num_q} " . $lang['QUERIES'];
} }

View file

@ -11,7 +11,7 @@ if (!defined('BB_ROOT')) {
die(basename(__FILE__)); die(basename(__FILE__));
} }
if (empty($_GET['u']) || empty($_GET['act_key'])) { if (empty($_GET[POST_USERS_URL]) || empty($_GET['act_key'])) {
bb_die('Bad request'); bb_die('Bad request');
} }

View file

@ -122,8 +122,8 @@ switch ($mode) {
]; ];
// Select a profile: your own for the user, any for the admin // Select a profile: your own for the user, any for the admin
if (IS_ADMIN && !empty($_REQUEST['u'])) { if (IS_ADMIN && !empty($_REQUEST[POST_USERS_URL])) {
$pr_user_id = (int)$_REQUEST['u']; $pr_user_id = (int)$_REQUEST[POST_USERS_URL];
$adm_edit = ($pr_user_id != $userdata['user_id']); $adm_edit = ($pr_user_id != $userdata['user_id']);
} else { } else {
$pr_user_id = $userdata['user_id']; $pr_user_id = $userdata['user_id'];
@ -365,6 +365,8 @@ foreach ($profile_fields as $field => $can_edit) {
'user_dls' => $reg_mode ? false : true, 'user_dls' => $reg_mode ? false : true,
'user_callseed' => $reg_mode ? true : true, 'user_callseed' => $reg_mode ? true : true,
'user_retracker' => $reg_mode ? true : true, 'user_retracker' => $reg_mode ? true : true,
'user_hide_torrent_client' => $reg_mode ? true : true,
'user_hide_peer_country' => $reg_mode ? true : $bb_cfg['ip2country_settings']['enabled'],
]; ];
foreach ($update_user_opt as $opt => $can_change_opt) { foreach ($update_user_opt as $opt => $can_change_opt) {
@ -565,7 +567,7 @@ foreach ($profile_fields as $field => $can_edit) {
} }
} }
} }
$tp_data['TEMPLATES_SELECT'] = \TorrentPier\Legacy\Select::template($pr_data['tpl_name'], 'tpl_name'); $tp_data['TEMPLATES_SELECT'] = \TorrentPier\Legacy\Common\Select::template($pr_data['tpl_name'], 'tpl_name');
break; break;
/** /**
@ -722,8 +724,8 @@ $template->assign_vars([
'INVITE_CODE' => !empty($_GET['invite']) ? htmlCHR($_GET['invite']) : '', 'INVITE_CODE' => !empty($_GET['invite']) ? htmlCHR($_GET['invite']) : '',
'CAPTCHA_HTML' => ($need_captcha) ? bb_captcha('get') : '', 'CAPTCHA_HTML' => ($need_captcha) ? bb_captcha('get') : '',
'LANGUAGE_SELECT' => \TorrentPier\Legacy\Select::language($pr_data['user_lang'], 'user_lang'), 'LANGUAGE_SELECT' => \TorrentPier\Legacy\Common\Select::language($pr_data['user_lang'], 'user_lang'),
'TIMEZONE_SELECT' => \TorrentPier\Legacy\Select::timezone($pr_data['user_timezone'], 'user_timezone'), 'TIMEZONE_SELECT' => \TorrentPier\Legacy\Common\Select::timezone($pr_data['user_timezone'], 'user_timezone'),
'AVATAR_EXPLAIN' => sprintf($lang['AVATAR_EXPLAIN'], $bb_cfg['avatars']['max_width'], $bb_cfg['avatars']['max_height'], humn_size($bb_cfg['avatars']['max_size'])), 'AVATAR_EXPLAIN' => sprintf($lang['AVATAR_EXPLAIN'], $bb_cfg['avatars']['max_width'], $bb_cfg['avatars']['max_height'], humn_size($bb_cfg['avatars']['max_size'])),
'AVATAR_DISALLOWED' => bf($pr_data['user_opt'], 'user_opt', 'dis_avatar'), 'AVATAR_DISALLOWED' => bf($pr_data['user_opt'], 'user_opt', 'dis_avatar'),

View file

@ -76,7 +76,7 @@ if (bf($profiledata['user_opt'], 'user_opt', 'dis_sig')) {
// Null ratio // Null ratio
if ($bb_cfg['ratio_null_enabled'] && $btu = get_bt_userdata($profiledata['user_id'])) { if ($bb_cfg['ratio_null_enabled'] && $btu = get_bt_userdata($profiledata['user_id'])) {
$template->assign_vars(array('NULLED_RATIO' => $btu['ratio_nulled'])); $template->assign_vars(['NULLED_RATIO' => $btu['ratio_nulled']]);
} }
// Ban information // Ban information
@ -93,7 +93,7 @@ $template->assign_vars([
'PROFILE_USER_ID' => $profiledata['user_id'], 'PROFILE_USER_ID' => $profiledata['user_id'],
'PROFILE_USER' => $profile_user_id, 'PROFILE_USER' => $profile_user_id,
'USER_REGDATE' => bb_date($profiledata['user_regdate'], 'Y-m-d H:i', false), 'USER_REGDATE' => bb_date($profiledata['user_regdate'], 'Y-m-d H:i', false),
'POSTER_RANK' => ($poster_rank) ? "<span class=\"$rank_style\">" . $poster_rank . "</span>" : $lang['USER'], 'POSTER_RANK' => $poster_rank ? "<span class=\"$rank_style\">" . $poster_rank . "</span>" : $lang['USER'],
'RANK_IMAGE' => $rank_image, 'RANK_IMAGE' => $rank_image,
'RANK_SELECT' => $rank_select, 'RANK_SELECT' => $rank_select,
'POSTS' => $profiledata['user_posts'], 'POSTS' => $profiledata['user_posts'],
@ -101,8 +101,8 @@ $template->assign_vars([
'EMAIL' => $email, 'EMAIL' => $email,
'WWW' => $profiledata['user_website'], 'WWW' => $profiledata['user_website'],
'ICQ' => $profiledata['user_icq'], 'ICQ' => $profiledata['user_icq'],
'LAST_VISIT_TIME' => ($profiledata['user_lastvisit']) ? (!$profile_user_id && bf($profiledata['user_opt'], 'user_opt', 'user_viewonline') && !IS_ADMIN) ? $lang['HIDDEN_USER'] : bb_date($profiledata['user_lastvisit'], 'Y-m-d H:i', false) : $lang['NEVER'], 'LAST_VISIT_TIME' => $profiledata['user_lastvisit'] ? (!$profile_user_id && bf($profiledata['user_opt'], 'user_opt', 'user_viewonline') && !IS_ADMIN) ? $lang['HIDDEN_USER'] : bb_date($profiledata['user_lastvisit'], 'Y-m-d H:i', false) : $lang['NEVER'],
'LAST_ACTIVITY_TIME' => ($profiledata['user_session_time']) ? (!$profile_user_id && bf($profiledata['user_opt'], 'user_opt', 'user_viewonline') && !IS_ADMIN) ? $lang['HIDDEN_USER'] : bb_date($profiledata['user_session_time'], 'Y-m-d H:i', false) : $lang['NEVER'], 'LAST_ACTIVITY_TIME' => $profiledata['user_session_time'] ? (!$profile_user_id && bf($profiledata['user_opt'], 'user_opt', 'user_viewonline') && !IS_ADMIN) ? $lang['HIDDEN_USER'] : bb_date($profiledata['user_session_time'], 'Y-m-d H:i', false) : $lang['NEVER'],
'USER_ACTIVE' => $profiledata['user_active'], 'USER_ACTIVE' => $profiledata['user_active'],
'LOCATION' => render_flag($profiledata['user_from']), 'LOCATION' => render_flag($profiledata['user_from']),
'OCCUPATION' => $profiledata['user_occ'], 'OCCUPATION' => $profiledata['user_occ'],

View file

@ -60,7 +60,7 @@ if ($releasing) {
'TOR_TYPE' => is_gold($row['tor_type']), 'TOR_TYPE' => is_gold($row['tor_type']),
'TOPIC_SEEDERS' => ($row['seeders']) ?: 0, 'TOPIC_SEEDERS' => ($row['seeders']) ?: 0,
'TOPIC_LEECHERS' => ($row['leechers']) ?: 0, 'TOPIC_LEECHERS' => ($row['leechers']) ?: 0,
'SPEED_UP' => ($row['speed_up']) ? humn_size($row['speed_up'], 0, 'KB') . '/s' : '-', 'SPEED_UP' => ($row['speed_up']) ? humn_size($row['speed_up'], min: 'KB') . '/s' : '-',
]); ]);
$releasing_count++; $releasing_count++;
@ -80,7 +80,7 @@ if ($seeding) {
'TOR_TYPE' => is_gold($row['tor_type']), 'TOR_TYPE' => is_gold($row['tor_type']),
'TOPIC_SEEDERS' => ($row['seeders']) ?: 0, 'TOPIC_SEEDERS' => ($row['seeders']) ?: 0,
'TOPIC_LEECHERS' => ($row['leechers']) ?: 0, 'TOPIC_LEECHERS' => ($row['leechers']) ?: 0,
'SPEED_UP' => ($row['speed_up']) ? humn_size($row['speed_up'], 0, 'KB') . '/s' : '-', 'SPEED_UP' => ($row['speed_up']) ? humn_size($row['speed_up'], min: 'KB') . '/s' : '-',
]); ]);
$seeding_count++; $seeding_count++;
@ -103,7 +103,7 @@ if ($leeching) {
'TOR_TYPE' => is_gold($row['tor_type']), 'TOR_TYPE' => is_gold($row['tor_type']),
'TOPIC_SEEDERS' => ($row['seeders']) ?: 0, 'TOPIC_SEEDERS' => ($row['seeders']) ?: 0,
'TOPIC_LEECHERS' => ($row['leechers']) ?: 0, 'TOPIC_LEECHERS' => ($row['leechers']) ?: 0,
'SPEED_DOWN' => ($row['speed_down']) ? humn_size($row['speed_down'], 0, 'KB') . '/s' : '-', 'SPEED_DOWN' => ($row['speed_down']) ? humn_size($row['speed_down'], min: 'KB') . '/s' : '-',
]); ]);
$leeching_count++; $leeching_count++;

View file

@ -1604,7 +1604,7 @@ $lang['ONLY_FOR_SUPER_ADMIN'] = 'This option only for super admins';
$lang['LOGS'] = 'Topic history'; $lang['LOGS'] = 'Topic history';
$lang['FORUM_LOGS'] = 'History Forum'; $lang['FORUM_LOGS'] = 'History Forum';
$lang['AUTOCLEAN'] = 'Autoclean:'; $lang['AUTOCLEAN'] = 'Autoclean';
$lang['DESIGNER'] = 'Designer'; $lang['DESIGNER'] = 'Designer';
$lang['LAST_IP'] = 'Last IP:'; $lang['LAST_IP'] = 'Last IP:';
@ -1879,6 +1879,8 @@ $lang['DL_ULR'] = 'ULR';
$lang['DL_STOPPED'] = 'stopped'; $lang['DL_STOPPED'] = 'stopped';
$lang['DL_UPD'] = 'upd: '; $lang['DL_UPD'] = 'upd: ';
$lang['DL_INFO'] = 'shows data <i><b>only for the current session</b></i>'; $lang['DL_INFO'] = 'shows data <i><b>only for the current session</b></i>';
$lang['HIDE_PEER_TORRENT_CLIENT'] = 'Hide my BitTorrent client name in peer list';
$lang['HIDE_PEER_COUNTRY_NAME'] = 'Hide my country name in peer list';
// Post PIN // Post PIN
$lang['POST_PIN'] = 'Pin first post'; $lang['POST_PIN'] = 'Pin first post';
@ -2322,14 +2324,6 @@ $lang['DISALLOWED_ALREADY'] = 'The name you entered could not be disallowed. It
$lang['CLICK_RETURN_DISALLOWADMIN'] = 'Click %sHere%s to return to Disallow Username Administration'; $lang['CLICK_RETURN_DISALLOWADMIN'] = 'Click %sHere%s to return to Disallow Username Administration';
// Integrity check
$lang['INTEGRITY_CHECK_SUCCESS'] = 'TorrentPier files integrity check was successful!';
$lang['INTEGRITY_CHECK_FAIL'] = 'Some TorrentPier files not pass integrity check!';
$lang['INTEGRITY_CHECKED'] = 'Total checked: %s file(s), of which pass integrity check: %s file(s).';
$lang['INTEGRITY_LAST_CHECK'] = 'Last check: %s.';
$lang['INTEGRITY_RESTORE_ON_NEXT_RUN'] = 'Restore corrupt files on next integrity check?';
$lang['INTEGRITY_RESTORE_CONFIRM_OK'] = 'Corrupt files will be restored on next integrity check!';
// Version Check // Version Check
$lang['VERSION_INFORMATION'] = 'Version Information'; $lang['VERSION_INFORMATION'] = 'Version Information';
$lang['UPDATE_AVAILABLE'] = 'Update available'; $lang['UPDATE_AVAILABLE'] = 'Update available';
@ -3080,7 +3074,8 @@ $lang['UPLOAD_ERRORS'] = [
// Captcha // Captcha
$lang['CAPTCHA'] = 'Check that you are not a robot'; $lang['CAPTCHA'] = 'Check that you are not a robot';
$lang['CAPTCHA_WRONG'] = 'You could not confirm that you are not a robot'; $lang['CAPTCHA_WRONG'] = 'You could not confirm that you are not a robot';
$lang['CAPTCHA_SETTINGS'] = '<h2>ReCaptcha not being fully configured</h2><p>If you haven\'t already generated the keys, you can do it on <a href="https://www.google.com/recaptcha/admin">https://www.google.com/recaptcha/admin</a>.<br />After you generate the keys, you need to put them at the file library/config.php.</p>'; $lang['CAPTCHA_SETTINGS'] = '<h2>Captcha is not fully configured</h2><p>Generate the keys using the dashboard of your captcha service, after you need to put them at the file library/config.php.</p>';
$lang['CAPTCHA_OCCURS_BACKGROUND'] = 'The CAPTCHA verification occurs in the background';
// Sending email // Sending email
$lang['REPLY_TO'] = 'Reply to'; $lang['REPLY_TO'] = 'Reply to';

View file

@ -34,7 +34,7 @@ if (!$topic_id) {
} }
// Getting torrent info from database // Getting torrent info from database
$sql = 'SELECT attach_id, info_hash, info_hash_v2 $sql = 'SELECT attach_id, forum_id, info_hash, info_hash_v2
FROM ' . BB_BT_TORRENTS . ' FROM ' . BB_BT_TORRENTS . '
WHERE topic_id = ' . $topic_id . ' WHERE topic_id = ' . $topic_id . '
LIMIT 1'; LIMIT 1';
@ -49,6 +49,15 @@ if (!$m3uFile = $torrServer->getM3UPath($row['attach_id'])) {
bb_die($lang['ERROR_NO_ATTACHMENT']); bb_die($lang['ERROR_NO_ATTACHMENT']);
} }
$forum_id = $row['forum_id'];
set_die_append_msg($forum_id, $topic_id);
// Check rights
$is_auth = auth(AUTH_ALL, $forum_id, $userdata);
if (!$is_auth['auth_download']) {
bb_die($lang['SORRY_AUTH_VIEW_ATTACH']);
}
// Parse M3U file // Parse M3U file
$m3uParser = new M3uParser\M3uParser(); $m3uParser = new M3uParser\M3uParser();
$m3uParser->addDefaultTags(); $m3uParser->addDefaultTags();

View file

@ -625,10 +625,6 @@ $template->assign_vars([
'POSTER_RGROUPS' => !empty($poster_rgroups) ? $poster_rgroups : '', 'POSTER_RGROUPS' => !empty($poster_rgroups) ? $poster_rgroups : '',
'ATTACH_RG_SIG' => $switch_rg_sig ?: false, 'ATTACH_RG_SIG' => $switch_rg_sig ?: false,
// todo: remove (cuz unused)
'U_VIEWTOPIC' => ($mode == 'reply') ? TOPIC_URL . "$topic_id&amp;postorder=desc" : '',
// todo: end
'S_NOTIFY_CHECKED' => $notify_user ? 'checked' : '', 'S_NOTIFY_CHECKED' => $notify_user ? 'checked' : '',
'S_ROBOTS_CHECKED' => $robots_indexing ? 'checked' : '', 'S_ROBOTS_CHECKED' => $robots_indexing ? 'checked' : '',
'S_TYPE_TOGGLE' => $topic_type_toggle, 'S_TYPE_TOGGLE' => $topic_type_toggle,

View file

@ -0,0 +1,38 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2025 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Captcha;
/**
* Interface CaptchaInterface
* @package TorrentPier\Captcha
*/
interface CaptchaInterface
{
/**
* Constructor
*
* @param array $settings
*/
public function __construct(array $settings);
/**
* Returns captcha widget
*
* @return string
*/
public function get(): string;
/**
* Checking captcha answer
*
* @return bool
*/
public function check(): bool;
}

View file

@ -0,0 +1,75 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2025 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Captcha;
/**
* Class CloudflareTurnstileCaptcha
* @package TorrentPier\Captcha
*/
class CloudflareTurnstileCaptcha implements CaptchaInterface
{
/**
* Captcha service settings
*
* @var array
*/
private array $settings;
/**
* Service verification endpoint
*
* @var string
*/
private string $verifyEndpoint = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
/**
* Constructor
*
* @param array $settings
*/
public function __construct(array $settings)
{
$this->settings = $settings;
}
/**
* Returns captcha widget
*
* @return string
*/
public function get(): string
{
return "
<script src='https://challenges.cloudflare.com/turnstile/v0/api.js' async defer></script>
<div class='cf-turnstile' data-sitekey='{$this->settings['public_key']}' data-language='{$this->settings['language']}' data-theme='" . ($this->settings['theme'] ?? 'light') . "'></div>
";
}
/**
* Checking captcha answer
*
* @return bool
*/
public function check(): bool
{
$turnstileResponse = $_POST['cf-turnstile-response'] ?? '';
$postFields = "secret={$this->settings['secret_key']}&response=$turnstileResponse";
$ch = curl_init($this->verifyEndpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
$response = curl_exec($ch);
curl_close($ch);
$responseData = json_decode($response);
return $responseData->success;
}
}

View file

@ -0,0 +1,69 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2025 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Captcha;
use ReCaptcha\ReCaptcha;
/**
* Class GoogleCaptchaV2
* @package TorrentPier\Captcha
*/
class GoogleCaptchaV2 implements CaptchaInterface
{
/**
* Captcha service settings
*
* @var array
*/
private array $settings;
/**
* Constructor
*
* @param array $settings
*/
public function __construct(array $settings)
{
$this->settings = $settings;
}
/**
* Returns captcha widget
*
* @return string
*/
public function get(): string
{
return "
<script type='text/javascript'>
var onloadCallback = function() {
grecaptcha.render('tp-captcha', {
'sitekey': '{$this->settings['public_key']}',
'theme': '" . ($this->settings['theme'] ?? 'light') . "'
});
};
</script>
<div id='tp-captcha'></div>
<script src='https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit&hl={$this->settings['language']}' async defer></script>";
}
/**
* Checking captcha answer
*
* @return bool
*/
public function check(): bool
{
$reCaptcha = new ReCaptcha($this->settings['secret_key']);
$resp = $reCaptcha->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']);
return $resp->isSuccess();
}
}

View file

@ -0,0 +1,72 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2025 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Captcha;
use ReCaptcha\ReCaptcha;
/**
* Class GoogleCaptchaV3
* @package TorrentPier\Captcha
*/
class GoogleCaptchaV3 implements CaptchaInterface
{
/**
* Captcha service settings
*
* @var array
*/
private array $settings;
/**
* Constructor
*
* @param array $settings
*/
public function __construct(array $settings)
{
$this->settings = $settings;
}
/**
* Returns captcha widget
*
* @return string
*/
public function get(): string
{
global $lang;
return "{$lang['CAPTCHA_OCCURS_BACKGROUND']}
<script src='https://www.google.com/recaptcha/api.js?render={$this->settings['public_key']}&lang={$this->settings['language']}'></script>
<script>
grecaptcha.ready(function() {
grecaptcha.execute('{$this->settings['public_key']}', { action:'validate_captcha' }).then(function(token) {
document.getElementById('g-recaptcha-response').value = token;
});
});
</script>
<input type='hidden' id='g-recaptcha-response' name='g-recaptcha-response'>";
}
/**
* Checking captcha answer
*
* @return bool
*/
public function check(): bool
{
$reCaptcha = new ReCaptcha($this->settings['secret_key']);
$resp = $reCaptcha
->setScoreThreshold(0.5)
->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']);
return $resp->isSuccess();
}
}

76
src/Captcha/HCaptcha.php Normal file
View file

@ -0,0 +1,76 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2025 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Captcha;
/**
* Class HCaptcha
* @package TorrentPier\Captcha
*/
class HCaptcha implements CaptchaInterface
{
/**
* Captcha service settings
*
* @var array
*/
private array $settings;
/**
* Service verification endpoint
*
* @var string
*/
private string $verifyEndpoint = 'https://hcaptcha.com/siteverify';
/**
* Constructor
*
* @param array $settings
*/
public function __construct(array $settings)
{
$this->settings = $settings;
}
/**
* Returns captcha widget
*
* @return string
*/
public function get(): string
{
return "
<div class='h-captcha' data-sitekey='{$this->settings['public_key']}' data-theme='" . ($this->settings['theme'] ?? 'light') . "'></div>
<script src='https://www.hCaptcha.com/1/api.js?hl={$this->settings['language']}' async defer></script>";
}
/**
* Checking captcha answer
*
* @return bool
*/
public function check(): bool
{
$data = [
'secret' => $this->settings['secret_key'],
'response' => $_POST['h-captcha-response'] ?? null,
];
$verify = curl_init();
curl_setopt($verify, CURLOPT_URL, $this->verifyEndpoint);
curl_setopt($verify, CURLOPT_POST, true);
curl_setopt($verify, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($verify, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($verify);
$responseData = json_decode($response);
return $responseData->success;
}
}

View file

@ -0,0 +1,72 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2025 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Captcha;
use Gregwar\Captcha\CaptchaBuilder;
use Gregwar\Captcha\PhraseBuilder;
/**
* Class TextCaptcha
* @package TorrentPier\Captcha
*/
class TextCaptcha implements CaptchaInterface
{
/**
* CaptchaBuilder object
*
* @var CaptchaBuilder
*/
private CaptchaBuilder $captcha;
/**
* Constructor
*
* @param array $settings
*/
public function __construct(array $settings)
{
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
$this->captcha = new CaptchaBuilder;
$this->captcha->setScatterEffect(false);
}
/**
* Returns captcha widget
*
* @return string
*/
public function get(): string
{
$_SESSION['phrase'] = $this->captcha->getPhrase();
$this->captcha->build();
return "
<img src=" . $this->captcha->inline() . " /><br />
<input type='text' name='captcha_phrase' />
";
}
/**
* Checking captcha answer
*
* @return bool
*/
public function check(): bool
{
if (!isset($_POST['captcha_phrase']) || !isset($_SESSION['phrase'])) {
return false;
}
return PhraseBuilder::comparePhrases($_SESSION['phrase'], $_POST['captcha_phrase']);
}
}

View file

@ -0,0 +1,84 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2025 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Captcha;
/**
* Class YandexSmartCaptcha
* @package TorrentPier\Captcha
*/
class YandexSmartCaptcha implements CaptchaInterface
{
/**
* Captcha service settings
*
* @var array
*/
private array $settings;
/**
* Service verification endpoint
*
* @var string
*/
private string $verifyEndpoint = 'https://smartcaptcha.yandexcloud.net/validate';
/**
* Constructor
*
* @param array $settings
*/
public function __construct(array $settings)
{
$this->settings = $settings;
}
/**
* Returns captcha widget
*
* @return string
*/
public function get(): string
{
return "
<script src='https://smartcaptcha.yandexcloud.net/captcha.js' defer></script>
<div id='captcha-container' style='width: 402px;' class='smart-captcha' data-sitekey='{$this->settings['public_key']}' data-hl='{$this->settings['language']}'></div>";
}
/**
* Checking captcha answer
*
* @return bool
*/
public function check(): bool
{
$ch = curl_init($this->verifyEndpoint);
$args = [
'secret' => $this->settings['secret_key'],
'token' => $_POST['smart-token'] ?? null,
'ip' => $_SERVER['REMOTE_ADDR'],
];
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($args));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$serverOutput = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
return true;
}
$resp = json_decode($serverOutput);
return ($resp->status === 'ok');
}
}

View file

@ -41,14 +41,7 @@ class Censor
} }
// Get censored words // Get censored words
if (!$censoredWords = $datastore->get('censor')) {
$datastore->update('censor');
$censoredWords = $datastore->get('censor'); $censoredWords = $datastore->get('censor');
}
if (isset($censoredWords['no_words'])) {
return;
}
foreach ($censoredWords as $word) { foreach ($censoredWords as $word) {
$this->words[] = '#(?<![\p{Nd}\p{L}_])(' . str_replace('\*', '[\p{Nd}\p{L}_]*?', preg_quote($word['word'], '#')) . ')(?![\p{Nd}\p{L}_])#iu'; $this->words[] = '#(?<![\p{Nd}\p{L}_])(' . str_replace('\*', '[\p{Nd}\p{L}_]*?', preg_quote($word['word'], '#')) . ')(?![\p{Nd}\p{L}_])#iu';

View file

@ -230,7 +230,7 @@ class Dev
foreach ($db_obj->dbg as $i => $dbg) { foreach ($db_obj->dbg as $i => $dbg) {
$id = "sql_{$i}_" . random_int(0, mt_getrandmax()); $id = "sql_{$i}_" . random_int(0, mt_getrandmax());
$sql = self::shortQuery($dbg['sql'], true); $sql = self::shortQuery($dbg['sql'], true);
$time = sprintf('%.4f', $dbg['time']); $time = sprintf('%.3f', $dbg['time']);
$perc = '[' . round($dbg['time'] * 100 / $db_obj->sql_timetotal) . '%]'; $perc = '[' . round($dbg['time'] * 100 / $db_obj->sql_timetotal) . '%]';
$info = !empty($dbg['info']) ? $dbg['info'] . ' [' . $dbg['src'] . ']' : $dbg['src']; $info = !empty($dbg['info']) ? $dbg['info'] . ' [' . $dbg['src'] . ']' : $dbg['src'];

View file

@ -9,6 +9,8 @@
namespace TorrentPier; namespace TorrentPier;
use Exception;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface; use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mailer\Mailer; use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mailer\Transport\SendmailTransport; use Symfony\Component\Mailer\Transport\SendmailTransport;
@ -98,12 +100,12 @@ class Emailer
$tpl_file = LANG_ROOT_DIR . '/' . $bb_cfg['default_lang'] . '/email/' . $template_file . '.html'; $tpl_file = LANG_ROOT_DIR . '/' . $bb_cfg['default_lang'] . '/email/' . $template_file . '.html';
if (!is_file($tpl_file)) { if (!is_file($tpl_file)) {
bb_die('Could not find email template file: ' . $template_file); throw new Exception('Could not find email template file: ' . $template_file);
} }
} }
if (!$fd = fopen($tpl_file, 'rb')) { if (!$fd = fopen($tpl_file, 'rb')) {
bb_die('Failed opening email template file: ' . $tpl_file); throw new Exception('Failed opening email template file: ' . $tpl_file);
} }
$this->tpl_msg[$template_lang . $template_file] = fread($fd, filesize($tpl_file)); $this->tpl_msg[$template_lang . $template_file] = fread($fd, filesize($tpl_file));
@ -119,6 +121,7 @@ class Emailer
* @param string $email_format * @param string $email_format
* *
* @return bool * @return bool
* @throws Exception
*/ */
public function send(string $email_format = 'text/plain'): bool public function send(string $email_format = 'text/plain'): bool
{ {
@ -156,7 +159,7 @@ class Emailer
$transport = new EsmtpTransport('localhost', 25); $transport = new EsmtpTransport('localhost', 25);
} }
} else { } else {
$transport = new SendmailTransport('/usr/sbin/sendmail -bs'); $transport = new SendmailTransport($bb_cfg['emailer']['sendmail_command']);
} }
$mailer = new Mailer($transport); $mailer = new Mailer($transport);
@ -176,10 +179,15 @@ class Emailer
$message->getHeaders() $message->getHeaders()
->addTextHeader('X-Auto-Response-Suppress', 'OOF, DR, RN, NRN, AutoReply'); ->addTextHeader('X-Auto-Response-Suppress', 'OOF, DR, RN, NRN, AutoReply');
if ($email_format == 'text/html') { switch ($email_format) {
case EMAIL_TYPE_HTML:
$message->html($this->message); $message->html($this->message);
} else { break;
case EMAIL_TYPE_TEXT:
$message->text($this->message); $message->text($this->message);
break;
default:
throw new Exception('Unknown email format: ' . $email_format);
} }
/** Send message */ /** Send message */

View file

@ -62,7 +62,7 @@ class Env
/** /**
* Get the environment repository instance. * Get the environment repository instance.
* *
* @return RepositoryInterface * @return RepositoryInterface|null
*/ */
public static function getRepository(): ?RepositoryInterface public static function getRepository(): ?RepositoryInterface
{ {
@ -83,10 +83,10 @@ class Env
* Gets the value of an environment variable. * Gets the value of an environment variable.
* *
* @param string $key * @param string $key
* @param mixed $default * @param mixed|null $default
* @return mixed * @return mixed
*/ */
public static function get(string $key, $default = null) public static function get(string $key, mixed $default = null): mixed
{ {
return Option::fromValue(static::getRepository()->get($key)) return Option::fromValue(static::getRepository()->get($key))
->map(function ($value) { ->map(function ($value) {

View file

@ -1,83 +0,0 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2025 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier;
use Nemorize\Indexnow\Exceptions\IndexnowException;
/**
* Class IndexNow
* @package TorrentPier
*/
class IndexNow
{
/**
* IndexNow instance
*
* @var \Nemorize\Indexnow\Indexnow
*/
private \Nemorize\Indexnow\Indexnow $indexNow;
/**
* IndexNow Key-file extension
*
* @var string
*/
public static string $keyFileExtension = '.txt';
/**
* Log filename
*
* @var string
*/
private static string $logFile = 'index_now';
/**
* Available hosts
*
* @var array|string[]
*/
public array $hosts = [
'yandex' => 'yandex.com',
'bing' => 'bing.com',
'seznam' => 'search.seznam.cz',
'naver' => 'searchadvisor.naver.com'
];
public function __construct()
{
global $bb_cfg;
$this->indexNow = new \Nemorize\Indexnow\Indexnow();
$this->indexNow->setKey($bb_cfg['indexnow_key']);
if (in_array($bb_cfg['indexnow_settings']['host'], array_keys($this->hosts))) {
$this->indexNow->setHost($this->hosts[$bb_cfg['indexnow_settings']['host']]);
} else {
bb_log("IndexNow (ERROR): Invalid host: {$bb_cfg['indexnow_settings']['host']}\n", self::$logFile);
bb_die('Invalid host: ' . $bb_cfg['indexnow_settings']['host']);
}
$this->indexNow->setKeyLocation(FULL_URL . $bb_cfg['indexnow_key'] . self::$keyFileExtension);
}
/**
* Submit page to IndexNow
*
* @param string $url
* @return void
*/
public function submit(string $url): void
{
try {
$this->indexNow->submit($url);
} catch (IndexnowException $e) {
bb_log("IndexNow (ERROR) [$url]: Message: {$e->getMessage()}\n", self::$logFile);
bb_die($e->getMessage());
}
}
}

View file

@ -25,10 +25,17 @@ class Atom
*/ */
public static function update_forum_feed($forum_id, $forum_data) public static function update_forum_feed($forum_id, $forum_data)
{ {
global $bb_cfg, $lang; global $bb_cfg, $lang, $datastore;
$sql = null; $sql = null;
$file_path = $bb_cfg['atom']['path'] . '/f/' . $forum_id . '.atom'; $file_path = $bb_cfg['atom']['path'] . '/f/' . $forum_id . '.atom';
$select_tor_sql = $join_tor_sql = ''; $select_tor_sql = $join_tor_sql = '';
if (!$forums = $datastore->get('cat_forums')) {
$datastore->update('cat_forums');
$forums = $datastore->get('cat_forums');
}
$not_forums_id = $forums['not_auth_forums']['guest_view'];
if ($forum_id == 0) { if ($forum_id == 0) {
$forum_data['forum_name'] = $lang['ATOM_GLOBAL_FEED'] ?? $bb_cfg['server_name']; $forum_data['forum_name'] = $lang['ATOM_GLOBAL_FEED'] ?? $bb_cfg['server_name'];
} }
@ -77,6 +84,9 @@ class Atom
$topics_tmp = DB()->fetch_rowset($sql); $topics_tmp = DB()->fetch_rowset($sql);
$topics = []; $topics = [];
foreach ($topics_tmp as $topic) { foreach ($topics_tmp as $topic) {
if (in_array($topic['topic_id'], explode(',', $not_forums_id))) {
continue;
}
if (isset($topic['topic_status'])) { if (isset($topic['topic_status'])) {
if ($topic['topic_status'] == TOPIC_MOVED) { if ($topic['topic_status'] == TOPIC_MOVED) {
continue; continue;

View file

@ -67,7 +67,7 @@ class Attach
$this->attachment_extension_list = get_var('extension_list', ['']); $this->attachment_extension_list = get_var('extension_list', ['']);
$this->attachment_mimetype_list = get_var('mimetype_list', ['']); $this->attachment_mimetype_list = get_var('mimetype_list', ['']);
$this->filename = (isset($_FILES['fileupload'], $_FILES['fileupload']['name']) && $_FILES['fileupload']['name'] !== 'none') ? trim(stripslashes($_FILES['fileupload']['name'])) : ''; $this->filename = (isset($_FILES['fileupload']['name']) && $_FILES['fileupload']['name'] !== 'none') ? trim(stripslashes($_FILES['fileupload']['name'])) : '';
$this->attachment_list = get_var('attachment_list', ['']); $this->attachment_list = get_var('attachment_list', ['']);
$this->attachment_thumbnail_list = get_var('attach_thumbnail_list', [0]); $this->attachment_thumbnail_list = get_var('attach_thumbnail_list', [0]);
@ -431,7 +431,7 @@ class Attach
} }
} }
// Get current informations to delete the Old Attachment // Get current information to delete the Old Attachment
$sql = 'SELECT physical_filename, comment, thumbnail $sql = 'SELECT physical_filename, comment, thumbnail
FROM ' . BB_ATTACHMENTS_DESC . ' FROM ' . BB_ATTACHMENTS_DESC . '
WHERE attach_id = ' . (int)$attachment_id; WHERE attach_id = ' . (int)$attachment_id;

View file

@ -9,8 +9,6 @@
namespace TorrentPier\Legacy; namespace TorrentPier\Legacy;
use function in_array;
/** /**
* Class BBCode * Class BBCode
* @package TorrentPier\Legacy * @package TorrentPier\Legacy
@ -21,7 +19,7 @@ class BBCode
public array $tpl = []; public array $tpl = [];
/** @var array $smilies Replacements for smilies */ /** @var array $smilies Replacements for smilies */
public $smilies; public array $smilies = [];
/** @var array $tidy_cfg Tidy preprocessor configuration */ /** @var array $tidy_cfg Tidy preprocessor configuration */
public array $tidy_cfg = [ public array $tidy_cfg = [
@ -338,11 +336,16 @@ class BBCode
{ {
global $datastore; global $datastore;
if (null === $this->smilies) {
$this->smilies = $datastore->get('smile_replacements'); $this->smilies = $datastore->get('smile_replacements');
if (!empty($this->smilies)) {
if (defined('IN_ADMIN')) {
foreach ($this->smilies['repl'] as &$smile) {
$smile = preg_replace('/src="([^"]+)"/', 'src="./../$1"', $smile);
}
unset($smile);
} }
if ($this->smilies) {
/** @noinspection NestedPositiveIfStatementsInspection */ /** @noinspection NestedPositiveIfStatementsInspection */
if ($parsed_text = preg_replace($this->smilies['orig'], $this->smilies['repl'], $text)) { if ($parsed_text = preg_replace($this->smilies['orig'], $this->smilies['repl'], $text)) {
return $parsed_text; return $parsed_text;
@ -388,7 +391,7 @@ class BBCode
{ {
global $bb_cfg; global $bb_cfg;
if (in_array(parse_url($href, PHP_URL_HOST), $bb_cfg['nofollow']['allowed_url']) || $bb_cfg['nofollow']['disabled']) { if (\in_array(parse_url($href, PHP_URL_HOST), $bb_cfg['nofollow']['allowed_url']) || $bb_cfg['nofollow']['disabled']) {
$link = "<a href=\"$href\" class=\"postLink\">$name</a>"; $link = "<a href=\"$href\" class=\"postLink\">$name</a>";
} else { } else {
$link = "<a href=\"$href\" class=\"postLink\" rel=\"nofollow\">$name</a>"; $link = "<a href=\"$href\" class=\"postLink\" rel=\"nofollow\">$name</a>";

View file

@ -116,7 +116,7 @@ class APCu extends Common
* @param string|null $name * @param string|null $name
* @return bool * @return bool
*/ */
public function rm(string $name = null): bool public function rm(?string $name = null): bool
{ {
$targetMethod = is_string($name) ? 'delete' : 'flush'; $targetMethod = is_string($name) ? 'delete' : 'flush';
$name = is_string($name) ? $this->prefix . $name : null; $name = is_string($name) ? $this->prefix . $name : null;

View file

@ -172,7 +172,7 @@ class Memcached extends Common
* @param string|null $name * @param string|null $name
* @return bool * @return bool
*/ */
public function rm(string $name = null): bool public function rm(?string $name = null): bool
{ {
if (!$this->connected) { if (!$this->connected) {
$this->connect(); $this->connect();

View file

@ -174,7 +174,7 @@ class Redis extends Common
* @param string|null $name * @param string|null $name
* @return bool * @return bool
*/ */
public function rm(string $name = null): bool public function rm(?string $name = null): bool
{ {
if (!$this->connected) { if (!$this->connected) {
$this->connect(); $this->connect();

View file

@ -126,7 +126,7 @@ class Sqlite extends Common
* @param string|null $name * @param string|null $name
* @return bool * @return bool
*/ */
public function rm(string $name = null): bool public function rm(?string $name = null): bool
{ {
$targetMethod = is_string($name) ? 'delete' : 'flush'; $targetMethod = is_string($name) ? 'delete' : 'flush';
$name = is_string($name) ? $this->prefix . $name : null; $name = is_string($name) ? $this->prefix . $name : null;

View file

@ -7,11 +7,11 @@
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License * @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/ */
namespace TorrentPier\Legacy; namespace TorrentPier\Legacy\Common;
/** /**
* Class Select * Class Select
* @package TorrentPier\Legacy * @package TorrentPier\Legacy\Common
*/ */
class Select class Select
{ {

View file

@ -9,6 +9,9 @@
namespace TorrentPier\Legacy\Common; namespace TorrentPier\Legacy\Common;
use claviska\SimpleImage;
use Exception;
/** /**
* Class Upload * Class Upload
* @package TorrentPier\Legacy\Common * @package TorrentPier\Legacy\Common
@ -165,14 +168,14 @@ class Upload
if (($this->cfg['max_width'] && $width > $this->cfg['max_width']) || ($this->cfg['max_height'] && $height > $this->cfg['max_height'])) { if (($this->cfg['max_width'] && $width > $this->cfg['max_width']) || ($this->cfg['max_height'] && $height > $this->cfg['max_height'])) {
for ($i = 0, $max_try = 3; $i <= $max_try; $i++) { for ($i = 0, $max_try = 3; $i <= $max_try; $i++) {
try { try {
$image = new \claviska\SimpleImage(); $image = new SimpleImage();
$image $image
->fromFile($this->file['tmp_name']) ->fromFile($this->file['tmp_name'])
->autoOrient() ->autoOrient()
->resize($this->cfg['max_width'], $this->cfg['max_height']) ->resize($this->cfg['max_width'], $this->cfg['max_height'])
->toFile($this->file['tmp_name']); ->toFile($this->file['tmp_name']);
break; break;
} catch (\Exception $e) { } catch (Exception $e) {
if ($i == $max_try) { if ($i == $max_try) {
$this->errors[] = sprintf($lang['UPLOAD_ERROR_DIMENSIONS'], $this->cfg['max_width'], $this->cfg['max_height']); $this->errors[] = sprintf($lang['UPLOAD_ERROR_DIMENSIONS'], $this->cfg['max_width'], $this->cfg['max_height']);
return false; return false;

View file

@ -590,7 +590,8 @@ class User
return; return;
} // prevent multiple calling } // prevent multiple calling
if (IS_GUEST && isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { // Apply browser language // Apply browser language
if ($bb_cfg['auto_language_detection'] && IS_GUEST && isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$http_accept_language = locale_get_primary_language(locale_accept_from_http($_SERVER['HTTP_ACCEPT_LANGUAGE'])); $http_accept_language = locale_get_primary_language(locale_accept_from_http($_SERVER['HTTP_ACCEPT_LANGUAGE']));
if (isset($bb_cfg['lang'][$http_accept_language])) { if (isset($bb_cfg['lang'][$http_accept_language])) {
$bb_cfg['default_lang'] = $http_accept_language; $bb_cfg['default_lang'] = $http_accept_language;

View file

@ -43,7 +43,6 @@ class Common
'cat_forums' => 'build_cat_forums.php', 'cat_forums' => 'build_cat_forums.php',
'censor' => 'build_censor.php', 'censor' => 'build_censor.php',
'check_updates' => 'build_check_updates.php', 'check_updates' => 'build_check_updates.php',
'files_integrity' => 'build_files_integrity.php',
'jumpbox' => 'build_cat_forums.php', 'jumpbox' => 'build_cat_forums.php',
'viewtopic_forum_select' => 'build_cat_forums.php', 'viewtopic_forum_select' => 'build_cat_forums.php',
'latest_news' => 'build_cat_forums.php', 'latest_news' => 'build_cat_forums.php',

View file

@ -10,7 +10,6 @@
namespace TorrentPier\Legacy; namespace TorrentPier\Legacy;
use TorrentPier\Emailer; use TorrentPier\Emailer;
use TorrentPier\IndexNow;
use TorrentPier\Legacy\Admin\Common; use TorrentPier\Legacy\Admin\Common;
use TorrentPier\Validate; use TorrentPier\Validate;
@ -159,7 +158,7 @@ class Post
topic_id = $topic_id topic_id = $topic_id
"; ";
$sql = ($mode != "editpost") ? $sql_insert : $sql_update; $sql = ($mode != 'editpost') ? $sql_insert : $sql_update;
if (!DB()->sql_query($sql)) { if (!DB()->sql_query($sql)) {
bb_die('Error in posting #1'); bb_die('Error in posting #1');
@ -178,7 +177,7 @@ class Post
DB()->sql_query("UPDATE " . BB_TOPICS . " SET topic_last_post_time = $current_time WHERE topic_id = $topic_id LIMIT 1"); DB()->sql_query("UPDATE " . BB_TOPICS . " SET topic_last_post_time = $current_time WHERE topic_id = $topic_id LIMIT 1");
} }
$sql = ($mode != "editpost") ? "INSERT INTO " . BB_POSTS . " (topic_id, forum_id, poster_id, post_username, post_time, poster_ip, poster_rg_id, attach_rg_sig) VALUES ($topic_id, $forum_id, " . $userdata['user_id'] . ", '$post_username', $current_time, '" . USER_IP . "', $poster_rg_id, $attach_rg_sig)" : "UPDATE " . BB_POSTS . " SET post_username = '$post_username'" . $edited_sql . ", poster_rg_id = $poster_rg_id, attach_rg_sig = $attach_rg_sig WHERE post_id = $post_id"; $sql = ($mode != 'editpost') ? "INSERT INTO " . BB_POSTS . " (topic_id, forum_id, poster_id, post_username, post_time, poster_ip, poster_rg_id, attach_rg_sig) VALUES ($topic_id, $forum_id, " . $userdata['user_id'] . ", '$post_username', $current_time, '" . USER_IP . "', $poster_rg_id, $attach_rg_sig)" : "UPDATE " . BB_POSTS . " SET post_username = '$post_username'" . $edited_sql . ", poster_rg_id = $poster_rg_id, attach_rg_sig = $attach_rg_sig WHERE post_id = $post_id";
if (!DB()->sql_query($sql)) { if (!DB()->sql_query($sql)) {
bb_die('Error in posting #2'); bb_die('Error in posting #2');
} }
@ -221,12 +220,6 @@ class Post
} }
} }
// Send IndexNow
if ($bb_cfg['indexnow_settings']['enabled'] && ($mode === 'newtopic' || $mode === 'editpost')) {
$indexNow = new IndexNow();
$indexNow->submit(FULL_URL . POST_URL . "$post_id#$post_id");
}
meta_refresh(POST_URL . "$post_id#$post_id"); meta_refresh(POST_URL . "$post_id#$post_id");
set_die_append_msg($forum_id, $topic_id); set_die_append_msg($forum_id, $topic_id);
@ -444,7 +437,7 @@ class Post
$post_time = TIMENOW; $post_time = TIMENOW;
$poster_id = BOT_UID; $poster_id = BOT_UID;
$poster_ip = '7f000001'; $poster_ip = '0';
if ($mode == 'after_move') { if ($mode == 'after_move') {
if (!$forum_id || !$old_forum_id) { if (!$forum_id || !$old_forum_id) {

View file

@ -832,7 +832,7 @@ class SqlDb
*/ */
public function log_query($log_file = 'sql_queries') public function log_query($log_file = 'sql_queries')
{ {
$q_time = ($this->cur_query_time >= 10) ? round($this->cur_query_time, 0) : sprintf('%.4f', $this->cur_query_time); $q_time = ($this->cur_query_time >= 10) ? round($this->cur_query_time, 0) : sprintf('%.3f', $this->cur_query_time);
$msg = []; $msg = [];
$msg[] = round($this->sql_starttime); $msg[] = round($this->sql_starttime);
$msg[] = date('m-d H:i:s', (int)$this->sql_starttime); $msg[] = date('m-d H:i:s', (int)$this->sql_starttime);
@ -943,7 +943,7 @@ class SqlDb
$this->explain_out .= ' $this->explain_out .= '
<table width="98%" cellpadding="0" cellspacing="0" class="bodyline row2 bCenter" style="border-bottom: 0;"> <table width="98%" cellpadding="0" cellspacing="0" class="bodyline row2 bCenter" style="border-bottom: 0;">
<tr> <tr>
<th style="height: 22px;" align="left">&nbsp;' . $dbg['src'] . '&nbsp; [' . sprintf('%.4f', $dbg['time']) . ' s]&nbsp; <i>' . $dbg['info'] . '</i></th> <th style="height: 22px;" align="left">&nbsp;' . $dbg['src'] . '&nbsp; [' . sprintf('%.3f', $dbg['time']) . ' s]&nbsp; <i>' . $dbg['info'] . '</i></th>
<th class="copyElement" data-clipboard-target="#' . $htid . '" style="height: 22px;" align="right" title="Copy to clipboard">' . "[$this->engine] $this->db_server.$this->selected_db" . ' :: Query #' . ($this->num_queries + 1) . '&nbsp;</th> <th class="copyElement" data-clipboard-target="#' . $htid . '" style="height: 22px;" align="right" title="Copy to clipboard">' . "[$this->engine] $this->db_server.$this->selected_db" . ' :: Query #' . ($this->num_queries + 1) . '&nbsp;</th>
</tr> </tr>
<tr><td colspan="2">' . $this->explain_hold . '</td></tr> <tr><td colspan="2">' . $this->explain_hold . '</td></tr>

View file

@ -644,7 +644,11 @@ class Torrent
// Send torrent // Send torrent
$output = Bencode::encode($tor); $output = Bencode::encode($tor);
if ($bb_cfg['tracker']['use_old_torrent_name_format']) {
$dl_fname = '[' . $bb_cfg['server_name'] . '].t' . $topic_id . '.' . TORRENT_EXT;
} else {
$dl_fname = html_ent_decode($topic_title) . ' [' . $bb_cfg['server_name'] . '-' . $topic_id . ']' . '.' . TORRENT_EXT; $dl_fname = html_ent_decode($topic_title) . ' [' . $bb_cfg['server_name'] . '-' . $topic_id . ']' . '.' . TORRENT_EXT;
}
if (!empty($_COOKIE['explain'])) { if (!empty($_COOKIE['explain'])) {
$out = "attach path: $filename<br /><br />"; $out = "attach path: $filename<br /><br />";

View file

@ -37,13 +37,24 @@ class Sitemap
} }
$not_forums_id = $forums['not_auth_forums']['guest_view']; $not_forums_id = $forums['not_auth_forums']['guest_view'];
$ignore_forum_sql = $not_forums_id ? "WHERE forum_id NOT IN($not_forums_id)" : ''; $ignore_forum_sql = $not_forums_id ? "WHERE f.forum_id NOT IN($not_forums_id)" : '';
$sql = DB()->sql_query("SELECT forum_id, forum_name FROM " . BB_FORUMS . " " . $ignore_forum_sql . " ORDER BY forum_id ASC"); $sql = DB()->sql_query("
SELECT
f.forum_id,
f.forum_name,
MAX(t.topic_time) AS last_topic_time
FROM " . BB_FORUMS . " f
LEFT JOIN " . BB_TOPICS . " t ON f.forum_id = t.forum_id
" . $ignore_forum_sql . "
GROUP BY f.forum_id, f.forum_name
ORDER BY f.forum_id ASC
");
while ($row = DB()->sql_fetchrow($sql)) { while ($row = DB()->sql_fetchrow($sql)) {
$forumUrls[] = [ $forumUrls[] = [
'url' => FORUM_URL . $row['forum_id'], 'url' => FORUM_URL . $row['forum_id'],
'time' => $row['last_topic_time']
]; ];
} }
@ -69,12 +80,12 @@ class Sitemap
$not_forums_id = $forums['not_auth_forums']['guest_view']; $not_forums_id = $forums['not_auth_forums']['guest_view'];
$ignore_forum_sql = $not_forums_id ? "WHERE forum_id NOT IN($not_forums_id)" : ''; $ignore_forum_sql = $not_forums_id ? "WHERE forum_id NOT IN($not_forums_id)" : '';
$sql = DB()->sql_query("SELECT topic_id, topic_title, topic_time FROM " . BB_TOPICS . " " . $ignore_forum_sql . " ORDER BY topic_time ASC"); $sql = DB()->sql_query("SELECT topic_id, topic_title, topic_last_post_time FROM " . BB_TOPICS . " " . $ignore_forum_sql . " ORDER BY topic_last_post_time ASC");
while ($row = DB()->sql_fetchrow($sql)) { while ($row = DB()->sql_fetchrow($sql)) {
$topicUrls[] = [ $topicUrls[] = [
'url' => TOPIC_URL . $row['topic_id'], 'url' => TOPIC_URL . $row['topic_id'],
'time' => $row['topic_time'], 'time' => $row['topic_last_post_time'],
]; ];
} }
@ -120,7 +131,7 @@ class Sitemap
$sitemap = new STM(SITEMAP_DIR . '/sitemap_dynamic.xml'); $sitemap = new STM(SITEMAP_DIR . '/sitemap_dynamic.xml');
foreach ($this->getForumUrls() as $forum) { foreach ($this->getForumUrls() as $forum) {
$sitemap->addItem(make_url($forum['url']), time(), STM::HOURLY, 0.7); $sitemap->addItem(make_url($forum['url']), $forum['time'], STM::HOURLY, 0.7);
} }
foreach ($this->getTopicUrls() as $topic) { foreach ($this->getTopicUrls() as $topic) {

View file

@ -47,13 +47,6 @@ class TorrServerAPI
'extension' => '.m3u' 'extension' => '.m3u'
]; ];
/**
* Log filename
*
* @var string
*/
private string $logFile = 'torr_server';
/** /**
* TorrServer constructor * TorrServer constructor
*/ */
@ -92,7 +85,7 @@ class TorrServerAPI
]); ]);
$isSuccess = $curl->httpStatusCode === 200; $isSuccess = $curl->httpStatusCode === 200;
if (!$isSuccess) { if (!$isSuccess) {
bb_log("TorrServer (ERROR) [$this->url]: Response code: {$curl->httpStatusCode} | Content: {$curl->response}\n", $this->logFile); bb_log("TorrServer (ERROR) [$this->url]: Response code: {$curl->httpStatusCode} | Content: {$curl->response}" . LOG_LF);
} }
$curl->close(); $curl->close();
@ -147,7 +140,7 @@ class TorrServerAPI
file_put_contents($m3uFile, $curl->response); file_put_contents($m3uFile, $curl->response);
} }
} else { } else {
bb_log("TorrServer (ERROR) [$this->url]: Response code: {$curl->httpStatusCode} | Content: {$curl->response}\n", $this->logFile); bb_log("TorrServer (ERROR) [$this->url]: Response code: {$curl->httpStatusCode} | Content: {$curl->response}" . LOG_LF);
} }
$curl->close(); $curl->close();
@ -187,7 +180,7 @@ class TorrServerAPI
if (unlink($m3uFile)) { if (unlink($m3uFile)) {
return true; return true;
} else { } else {
bb_log("TorrServer (ERROR) [removeM3U()]: Can't unlink file '$m3uFile'\n", $this->logFile); bb_log("TorrServer (ERROR) [removeM3U()]: Can't unlink file '$m3uFile'" . LOG_LF);
} }
} }
@ -229,7 +222,7 @@ class TorrServerAPI
if ($curl->httpStatusCode === 200 && !empty($response->{$index})) { if ($curl->httpStatusCode === 200 && !empty($response->{$index})) {
CACHE('tr_cache')->set("ffprobe_m3u_$attach_id", $response, 3600); CACHE('tr_cache')->set("ffprobe_m3u_$attach_id", $response, 3600);
} else { } else {
bb_log("TorrServer (ERROR) [$this->url]: Response code: {$curl->httpStatusCode}\n", $this->logFile); bb_log("TorrServer (ERROR) [$this->url]: Response code: {$curl->httpStatusCode}" . LOG_LF);
} }
$curl->close(); $curl->close();
} }
@ -254,7 +247,7 @@ class TorrServerAPI
$curl->get($this->url . $this->endpoints['stream'], ['link' => $hash]); $curl->get($this->url . $this->endpoints['stream'], ['link' => $hash]);
$isSuccess = $curl->httpStatusCode === 200; $isSuccess = $curl->httpStatusCode === 200;
if (!$isSuccess) { if (!$isSuccess) {
bb_log("TorrServer (ERROR) [$this->url]: Response code: {$curl->httpStatusCode} | Content: {$curl->response}\n", $this->logFile); bb_log("TorrServer (ERROR) [$this->url]: Response code: {$curl->httpStatusCode} | Content: {$curl->response}" . LOG_LF);
} }
$curl->close(); $curl->close();

View file

@ -45,7 +45,7 @@ class Updater
*/ */
private const STREAM_CONTEXT = [ private const STREAM_CONTEXT = [
'http' => [ 'http' => [
'header' => 'User-Agent: ' . APP_NAME . '-' . TP_INSTANCE_HASH, 'header' => 'User-Agent: ' . APP_NAME . '-' . TIMENOW,
'timeout' => 10, 'timeout' => 10,
'ignore_errors' => true 'ignore_errors' => true
] ]
@ -130,14 +130,14 @@ class Updater
} }
/** /**
* Returns information of latest TorrentPier version * Returns information of latest TorrentPier version available
* *
* @param bool $allowRC * @param bool $allowPreReleases
* @return array * @return array
*/ */
public function getLastVersion(bool $allowRC = true): array public function getLastVersion(bool $allowPreReleases = true): array
{ {
if (!$allowRC) { if (!$allowPreReleases) {
foreach ($this->jsonResponse as $index) { foreach ($this->jsonResponse as $index) {
if (isset($index['prerelease']) && $index['prerelease']) { if (isset($index['prerelease']) && $index['prerelease']) {
continue; continue;

Some files were not shown because too many files have changed in this diff Show more