diff --git a/.github/ISSUE_TEMPLATE/bug_report_form.yaml b/.github/ISSUE_TEMPLATE/bug_report_form.yaml index 2bd744390..02e81216b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_form.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report_form.yaml @@ -44,7 +44,7 @@ body: attributes: label: System information description: Please complete the following information - value: "- Database version: [e.g. SQLite, PostgreSQL 17]\n- PHP version: [e.g. PHP 8.2]\n- Installation type: [e.g. Docker, Docker image source, git, Yunohost]\n- Web server type: [e.g. Apache, nginx]\n- Device: [e.g. iPhone13]\n- OS: [e.g. Ubuntu 24.04, Win11, MacOS14]\n- Browser: [e.g. Firefox 134]" + value: "- Database version: [e.g. PostgreSQL 18, MySQL 8.4, SQLite]\n- PHP version: [e.g. PHP 8.2]\n- Installation type: [e.g. Docker, Docker image source, git, YunoHost]\n- Web server type: [e.g. Apache, nginx]\n- Device: [e.g. iPhone13]\n- OS: [e.g. Ubuntu 24.04, Win11, macOS 27]\n- Browser: [e.g. Firefox 157]" validations: required: true - type: textarea diff --git a/.github/ISSUE_TEMPLATE/feed-report-form.yml b/.github/ISSUE_TEMPLATE/feed-report-form.yml index 65b88018d..bb5fcebfc 100644 --- a/.github/ISSUE_TEMPLATE/feed-report-form.yml +++ b/.github/ISSUE_TEMPLATE/feed-report-form.yml @@ -49,7 +49,7 @@ body: attributes: label: System information description: Please complete the following information - value: "Database version: [e.g. Mysql 5.7, SQLite]\n- PHP version: [e.g. PHP 8.1]\n- Installation type: [e.g. Docker, Docker image source, git, Yunohost]\n- Web server type: [e.g. Apache, nginx]\n- Device: [e.g. iPhone13]\n- OS: [e.g. Ubuntu 22.04, Win10, MacOS14]\n- Browser: [e.g. Firefox 124]" + value: "- Database version: [e.g. PostgreSQL 18, MySQL 8.4, SQLite]\n- PHP version: [e.g. PHP 8.2]\n- Installation type: [e.g. Docker, Docker image source, git, YunoHost]\n- Web server type: [e.g. Apache, nginx]\n- Device: [e.g. iPhone13]\n- OS: [e.g. Ubuntu 24.04, Win11, macOS 27]\n- Browser: [e.g. Firefox 157]" validations: required: true - type: textarea diff --git a/CHANGELOG.md b/CHANGELOG.md index e442c9d0d..ba93d3d96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,14 +4,19 @@ See also [the FreshRSS releases](https://github.com/FreshRSS/FreshRSS/releases). ## 2026-XX-XX FreshRSS 1.30.5-dev +* Compatibility + * 💥 Require PHP 8.2+ (drop PHP 8.1) [#9470](https://github.com/FreshRSS/FreshRSS/pull/9470) * Bug fixes * Fix 32-bit systems provide a string for SQL BIGINT [#9486](https://github.com/FreshRSS/FreshRSS/pull/9486) * Security * Fix escape labels during JSON import and render tag dropdown as text [#9504](https://github.com/FreshRSS/FreshRSS/pull/9504) +* Deployment + * Docker: dev image `freshrss/freshrss:oldest` updated to Alpine 3.18 with PHP 8.2.16 and Apache 2.4.62 [#9470](https://github.com/FreshRSS/FreshRSS/pull/9470) * I18n * Add Arabic [#9502](https://github.com/FreshRSS/FreshRSS/pull/9502) * CI/CD * Add a link checker workflow using lychee [#9209](https://github.com/FreshRSS/FreshRSS/pull/9209), [#9495](https://github.com/FreshRSS/FreshRSS/pull/9495), [#9507](https://github.com/FreshRSS/FreshRSS/pull/9507) + * Update to PHPUnit 11.x (PHP 8.2+) [#9470](https://github.com/FreshRSS/FreshRSS/pull/9470) * Group auto dependency updates into one PR per ecosystem [#9496](https://github.com/FreshRSS/FreshRSS/pull/9496) * Update dev dependencies [#9494](https://github.com/FreshRSS/FreshRSS/pull/9494), [#9497](https://github.com/FreshRSS/FreshRSS/pull/9497), [#9498](https://github.com/FreshRSS/FreshRSS/pull/9498), [#9499](https://github.com/FreshRSS/FreshRSS/pull/9499),[#9500](https://github.com/FreshRSS/FreshRSS/pull/9500),[#9501](https://github.com/FreshRSS/FreshRSS/pull/9501), @@ -79,7 +84,7 @@ See also [the FreshRSS releases](https://github.com/FreshRSS/FreshRSS/releases). * Accept a trusted proxy address given without a subnet [#9301](https://github.com/FreshRSS/FreshRSS/pull/9301) * Warn during session regenerate fail [#9311](https://github.com/FreshRSS/FreshRSS/pull/9311), [#9376](https://github.com/FreshRSS/FreshRSS/pull/9376) * CI/CD add zizmor workflow for action security checks [#9228](https://github.com/FreshRSS/FreshRSS/pull/9228), [#9331](https://github.com/FreshRSS/FreshRSS/pull/9331) - * Use PHP `#[\SensitiveParameter]` [#9322](https://github.com/FreshRSS/FreshRSS/pull/9322) + * Use PHP 8.2+ `#[\SensitiveParameter]` [#9322](https://github.com/FreshRSS/FreshRSS/pull/9322) * Reject token access (RSS/OPML export, feed refresh) for disabled accounts [#9336](https://github.com/FreshRSS/FreshRSS/pull/9336) * Require POST+CSRF for self-update mutations [#9335](https://github.com/FreshRSS/FreshRSS/pull/9335) * Make the login challenge nonce one-time [#9334](https://github.com/FreshRSS/FreshRSS/pull/9334) diff --git a/Docker/Dockerfile-Oldest b/Docker/Dockerfile-Oldest index 55c3b011f..ba710d0e8 100644 --- a/Docker/Dockerfile-Oldest +++ b/Docker/Dockerfile-Oldest @@ -1,15 +1,15 @@ # Test image for development -FROM alpine:3.16 +FROM alpine:3.18 ENV TZ=UTC SHELL ["/bin/ash", "-eo", "pipefail", "-c"] RUN apk add --no-cache \ tzdata \ - apache2 php81-apache2 \ - php81 php81-curl php81-gmp php81-intl php81-mbstring php81-xml php81-zip \ - php81-ctype php81-dom php81-fileinfo php81-iconv php81-json php81-opcache php81-openssl php81-phar php81-session php81-simplexml php81-xmlreader php81-xmlwriter php81-xml php81-tokenizer php81-zlib \ - php81-pdo_sqlite php81-pdo_mysql php81-pdo_pgsql + apache2 php82-apache2 \ + php82 php82-curl php82-gmp php82-intl php82-mbstring php82-xml php82-zip \ + php82-ctype php82-dom php82-fileinfo php82-iconv php82-json php82-opcache php82-openssl php82-phar php82-session php82-simplexml php82-xmlreader php82-xmlwriter php82-xml php82-tokenizer php82-zlib \ + php82-pdo_sqlite php82-pdo_mysql php82-pdo_pgsql RUN mkdir -p /var/www/FreshRSS /run/apache2/ WORKDIR /var/www/FreshRSS @@ -43,8 +43,8 @@ RUN \ sed -r -i "/^\s*#\s*LoadModule .*mod_(deflate|expires|filter|headers|mime|remoteip|setenvif).so$/s/^\s*#//" \ /etc/apache2/httpd.conf && \ # PHP configuration - if [ ! -f /usr/bin/php ]; then ln -s /usr/bin/php81 /usr/bin/php; else true; fi && \ - echo 'memory_limit = 256M' > /etc/php81/conf.d/10_memory.ini && \ + if [ ! -f /usr/bin/php ]; then ln -s /usr/bin/php82 /usr/bin/php; else true; fi && \ + echo 'memory_limit = 256M' > /etc/php82/conf.d/10_memory.ini && \ # Disable built-in FreshRSS updates when using Docker, as the full image is supposed to be updated instead. sed -r -i "\\#disable_update#s#^.*#\t'disable_update' => true,#" ./config.default.php && \ # Configure cron job diff --git a/README.fr.md b/README.fr.md index 5d8e7bc5b..8de07aab0 100644 --- a/README.fr.md +++ b/README.fr.md @@ -63,7 +63,7 @@ FreshRSS n’est fourni avec aucune garantie. * Serveur modeste, par exemple sous Linux ou Windows * Fonctionne même sur un Raspberry Pi 1 avec des temps de réponse < 1s (testé sur 150 flux, 22k articles) * Serveur Web Apache2.4+ (recommandé), ou nginx, lighttpd (non testé sur les autres) -* PHP 8.1+ +* PHP 8.2+ * Extensions requises : [cURL](https://www.php.net/curl), [DOM](https://www.php.net/dom), [JSON](https://www.php.net/json), [XML](https://www.php.net/xml), [session](https://www.php.net/features.sessions), [ctype](https://www.php.net/ctype) * Extensions recommandées : [PDO_SQLite](https://www.php.net/pdo-sqlite) (pour l’export/import), [GMP](https://www.php.net/gmp) (pour accès API sur plateformes < 64 bits), [IDN](https://www.php.net/intl.idn) (pour les noms de domaines internationalisés), [mbstring](https://www.php.net/mbstring) (pour le texte Unicode), [iconv](https://www.php.net/iconv) (pour conversion d’encodages), [ZIP](https://www.php.net/zip) (pour import/export), [zlib](https://www.php.net/zlib) (pour les flux compressés) * Extension pour base de données : [PDO_PGSQL](https://www.php.net/pdo-pgsql) ou [PDO_SQLite](https://www.php.net/pdo-sqlite) ou [PDO_MySQL](https://www.php.net/pdo-mysql) diff --git a/README.md b/README.md index 4db491913..667e32ac9 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ FreshRSS comes with absolutely no warranty. * Light server running Linux or Windows * It even works on Raspberry Pi 1 with response time under a second (tested with 150 feeds, 22k articles) * A Web server: Apache2.4+ (recommended), nginx, lighttpd (not tested on others) -* PHP 8.1+ +* PHP 8.2+ * Required extensions: [cURL](https://www.php.net/curl), [DOM](https://www.php.net/dom), [JSON](https://www.php.net/json), [XML](https://www.php.net/xml), [session](https://www.php.net/features.sessions), [ctype](https://www.php.net/ctype) * Recommended extensions: [PDO_SQLite](https://www.php.net/pdo-sqlite) (for export/import), [GMP](https://www.php.net/gmp) (for API access on 32-bit platforms), [IDN](https://www.php.net/intl.idn) (for Internationalized Domain Names), [mbstring](https://www.php.net/mbstring) (for Unicode strings), [iconv](https://www.php.net/iconv) (for charset conversion), [ZIP](https://www.php.net/zip) (for import/export), [zlib](https://www.php.net/zlib) (for compressed feeds) * Extension for database: [PDO_PGSQL](https://www.php.net/pdo-pgsql) or [PDO_SQLite](https://www.php.net/pdo-sqlite) or [PDO_MySQL](https://www.php.net/pdo-mysql) diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 0ed4f0508..f8fa6ba22 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -80,19 +80,11 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController { $this->listSqliteArchives(); } - private static function megabytes(string $size_str): float|int|string { - return match (substr($size_str, -1)) { - 'M', 'm' => (int)$size_str, - 'K', 'k' => (int)$size_str / 1024, - 'G', 'g' => (int)$size_str * 1024, - default => $size_str, - }; - } - private static function minimumMemory(int|string $mb): void { $mb = (int)$mb; - $ini = self::megabytes(ini_get('memory_limit') ?: '0'); - if ($ini < $mb) { + // `ini_get('memory_limit')` returns e.g. `128M`, or `-1` for unlimited + $ini = (int)(ini_parse_quantity(ini_get('memory_limit') ?: '0') / 1048576); + if ($ini >= 0 && $ini < $mb) { ini_set('memory_limit', $mb . 'M'); } } diff --git a/app/Models/SimplePieFetch.php b/app/Models/SimplePieFetch.php index 113799de6..eb5cf98a2 100644 --- a/app/Models/SimplePieFetch.php +++ b/app/Models/SimplePieFetch.php @@ -25,10 +25,10 @@ final class FreshRSS_SimplePieFetch extends \SimplePie\File } } - $redirects = $curl_options[CURLOPT_MAXREDIRS] ?? $redirects; - if (!is_int($redirects)) { - $redirects = 4; - } elseif ($redirects < 0) { + if (is_int($curl_options[CURLOPT_MAXREDIRS] ?? null)) { + $redirects = $curl_options[CURLOPT_MAXREDIRS]; + } + if ($redirects < 0) { $redirects = -1; // infinite redirects } if (isset($curl_options[CURLOPT_FOLLOWLOCATION])) { diff --git a/app/Models/ViewMode.php b/app/Models/ViewMode.php index fde073097..5fe4d2870 100644 --- a/app/Models/ViewMode.php +++ b/app/Models/ViewMode.php @@ -4,7 +4,7 @@ declare(strict_types=1); /** * Represents a view mode option for the reading configuration */ -final class FreshRSS_ViewMode { +final readonly class FreshRSS_ViewMode { private string $id; private string $name; private string $controller; diff --git a/app/Utils/httpUtil.php b/app/Utils/httpUtil.php index c29d07f2c..2872faa79 100644 --- a/app/Utils/httpUtil.php +++ b/app/Utils/httpUtil.php @@ -4,23 +4,8 @@ declare(strict_types=1); final class FreshRSS_http_Util { private const RETRY_AFTER_PATH = DATA_PATH . '/Retry-After/'; - private const PRIVATE_SUBNETS = [ - '127.0.0.0/8', // RFC1700 (Loopback) - '10.0.0.0/8', // RFC1918 - '192.168.0.0/16', // RFC1918 - '172.16.0.0/12', // RFC1918 - '169.254.0.0/16', // RFC3927 - '0.0.0.0/8', // RFC5735 - '240.0.0.0/4', // RFC1112 - '100.64.0.0/10', // RFC6598 (Shared Address Space of Carrier-Grade NAT) - '::1/128', // Loopback - 'fc00::/7', // Unique Local Address - 'fe80::/10', // Link Local Address - '::ffff:0:0/96', // IPv4 translations - '64:ff9b::/96', // RFC6052 (IPv6 Addressing of IPv4/IPv6 Translators, NAT64) - '64:ff9b:1::/48', // RFC8215 (Local-Use IPv4/IPv6 Translation Prefix) - '::/128', // Unspecified address - ]; + private const NAT64_PREFIX_RFC6052 = '64:ff9b::/96'; + private const NAT64_PREFIX_RFC8215 = '64:ff9b:1::/48'; /** @var array $resolve_ok */ private static array $resolve_ok = []; /** @var array $retry_after_domain_wide */ @@ -398,7 +383,7 @@ final class FreshRSS_http_Util { // NAT64 addresses use the RFC 6052 well-known prefix. // Validate the embedded IPv4 address because the NAT64 IPv6 address itself // is globally routable even when it maps to a private/reserved IPv4 address. - if (self::checkCIDR($ip, '64:ff9b::/96')) { + if (self::checkCIDR($ip, self::NAT64_PREFIX_RFC6052)) { $packed = @inet_pton($ip); if ($packed === false || strlen($packed) !== 16) { continue; @@ -409,31 +394,19 @@ final class FreshRSS_http_Util { continue; } - if (filter_var($embedded_ipv4, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) { + if (filter_var($embedded_ipv4, FILTER_VALIDATE_IP, FILTER_FLAG_GLOBAL_RANGE) === false) { continue; } - // Extra check because the above one might not be enough: https://github.com/php/php-src/issues/16944 - foreach (self::PRIVATE_SUBNETS as $cidr) { - if (self::checkCIDR($embedded_ipv4, $cidr)) { - continue 2; - } - } - $ips_ok[] = $add_ip; continue; } - if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) { + // `FILTER_FLAG_GLOBAL_RANGE` does not reject the NAT64 prefixes + if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_GLOBAL_RANGE) === false || + self::checkCIDR($ip, self::NAT64_PREFIX_RFC8215)) { continue; } - // Extra check because the above one might not be enough: https://github.com/php/php-src/issues/16944 - // Workaround is available by using `FILTER_FLAG_GLOBAL_RANGE` instead, but that was only added in PHP 8.2, and we need to support PHP 8.1+ - foreach (self::PRIVATE_SUBNETS as $cidr) { - if (self::checkCIDR($ip, $cidr)) { - continue 2; - } - } $ips_ok[] = $add_ip; } diff --git a/composer.json b/composer.json index 82210cf8c..521981786 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "WebSub" ], "require": { - "php": ">=8.1", + "php": ">=8.2", "ext-ctype": "*", "ext-curl": "*", "ext-dom": "*", @@ -49,11 +49,11 @@ "phpstan/extension-installer": false }, "platform": { - "php": "8.1" + "php": "8.2" } }, "require-dev": { - "php": ">=8.1", + "php": ">=8.2", "ext-phar": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", @@ -61,7 +61,7 @@ "phpstan/phpstan-deprecation-rules": "^2.0", "phpstan/phpstan-phpunit": "^2.0", "phpstan/phpstan-strict-rules": "^2.0", - "phpunit/phpunit": "^10", + "phpunit/phpunit": "^11", "squizlabs/php_codesniffer": "^4.0" }, "scripts": { diff --git a/composer.lock b/composer.lock index 8223ae9dd..3e1c33e69 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d9c253337f8342684f2f8f37c331a81f", + "content-hash": "a98d34205a998ade47ad94d4e7c2ed09", "packages": [], "packages-dev": [ { @@ -469,35 +469,35 @@ }, { "name": "phpunit/php-code-coverage", - "version": "10.1.16", + "version": "11.0.12", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "7e308268858ed6baedc8704a304727d20bc07c77" + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77", - "reference": "7e308268858ed6baedc8704a304727d20bc07c77", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2c1ed04922802c15e1de5d7447b4856de949cf56", + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.19.1 || ^5.1.0", - "php": ">=8.1", - "phpunit/php-file-iterator": "^4.1.0", - "phpunit/php-text-template": "^3.0.1", - "sebastian/code-unit-reverse-lookup": "^3.0.0", - "sebastian/complexity": "^3.2.0", - "sebastian/environment": "^6.1.0", - "sebastian/lines-of-code": "^2.0.2", - "sebastian/version": "^4.0.1", - "theseer/tokenizer": "^1.2.3" + "nikic/php-parser": "^5.7.0", + "php": ">=8.2", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-text-template": "^4.0.1", + "sebastian/code-unit-reverse-lookup": "^4.0.1", + "sebastian/complexity": "^4.0.1", + "sebastian/environment": "^7.2.1", + "sebastian/lines-of-code": "^3.0.1", + "sebastian/version": "^5.0.2", + "theseer/tokenizer": "^1.3.1" }, "require-dev": { - "phpunit/phpunit": "^10.1" + "phpunit/phpunit": "^11.5.46" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -506,7 +506,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "10.1.x-dev" + "dev-main": "11.0.x-dev" } }, "autoload": { @@ -535,40 +535,52 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.12" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", + "type": "tidelift" } ], - "time": "2024-08-22T04:31:57+00:00" + "time": "2025-12-24T07:01:01+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "4.1.0", + "version": "5.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c" + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c", - "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/2f3a64888c814fc235386b7387dd5b5ed92ad903", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -596,36 +608,48 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator", + "type": "tidelift" } ], - "time": "2023-08-31T06:24:48+00:00" + "time": "2026-02-02T13:52:54+00:00" }, { "name": "phpunit/php-invoker", - "version": "4.0.0", + "version": "5.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7" + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", - "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { "ext-pcntl": "*", - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "suggest": { "ext-pcntl": "*" @@ -633,7 +657,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -659,7 +683,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0" + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" }, "funding": [ { @@ -667,32 +692,32 @@ "type": "github" } ], - "time": "2023-02-03T06:56:09+00:00" + "time": "2024-07-03T05:07:44+00:00" }, { "name": "phpunit/php-text-template", - "version": "3.0.1", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748" + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748", - "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -719,7 +744,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-text-template/issues", "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1" + "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" }, "funding": [ { @@ -727,32 +752,32 @@ "type": "github" } ], - "time": "2023-08-31T14:07:24+00:00" + "time": "2024-07-03T05:08:43+00:00" }, { "name": "phpunit/php-timer", - "version": "6.0.0", + "version": "7.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d" + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d", - "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -778,7 +803,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0" + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" }, "funding": [ { @@ -786,20 +812,20 @@ "type": "github" } ], - "time": "2023-02-03T06:57:52+00:00" + "time": "2024-07-03T05:09:35+00:00" }, { "name": "phpunit/phpunit", - "version": "10.5.65", + "version": "11.5.57", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "b4f678d4ebb686d6d3bd6a7c193e8a067d1a7f01" + "reference": "36b75bf56a8535623f5b3e24b27ea1823759da1a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b4f678d4ebb686d6d3bd6a7c193e8a067d1a7f01", - "reference": "b4f678d4ebb686d6d3bd6a7c193e8a067d1a7f01", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/36b75bf56a8535623f5b3e24b27ea1823759da1a", + "reference": "36b75bf56a8535623f5b3e24b27ea1823759da1a", "shasum": "" }, "require": { @@ -812,23 +838,24 @@ "myclabs/deep-copy": "^1.14.0", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", - "php": ">=8.1", - "phpunit/php-code-coverage": "^10.1.16", - "phpunit/php-file-iterator": "^4.1.0", - "phpunit/php-invoker": "^4.0.0", - "phpunit/php-text-template": "^3.0.1", - "phpunit/php-timer": "^6.0.0", - "sebastian/cli-parser": "^2.0.1", - "sebastian/code-unit": "^2.0.0", - "sebastian/comparator": "^5.0.5", - "sebastian/diff": "^5.1.1", - "sebastian/environment": "^6.1.0", - "sebastian/exporter": "^5.1.4", - "sebastian/global-state": "^6.0.2", - "sebastian/object-enumerator": "^5.0.0", - "sebastian/recursion-context": "^5.0.2", - "sebastian/type": "^4.0.0", - "sebastian/version": "^4.0.1" + "php": ">=8.2", + "phpunit/php-code-coverage": "^11.0.12", + "phpunit/php-file-iterator": "^5.1.1", + "phpunit/php-invoker": "^5.0.1", + "phpunit/php-text-template": "^4.0.1", + "phpunit/php-timer": "^7.0.1", + "sebastian/cli-parser": "^3.0.2", + "sebastian/code-unit": "^3.0.3", + "sebastian/comparator": "^6.3.3", + "sebastian/diff": "^6.0.2", + "sebastian/environment": "^7.2.1", + "sebastian/exporter": "^6.3.2", + "sebastian/global-state": "^7.0.2", + "sebastian/object-enumerator": "^6.0.1", + "sebastian/recursion-context": "^6.0.3", + "sebastian/type": "^5.1.3", + "sebastian/version": "^5.0.2", + "staabm/side-effects-detector": "^1.0.5" }, "suggest": { "ext-soap": "To be able to generate mocks based on WSDL files" @@ -839,7 +866,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "10.5-dev" + "dev-main": "11.5-dev" } }, "autoload": { @@ -871,7 +898,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.65" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.57" }, "funding": [ { @@ -879,32 +906,32 @@ "type": "other" } ], - "time": "2026-09-23T10:01:12+00:00" + "time": "2026-10-05T05:47:54+00:00" }, { "name": "sebastian/cli-parser", - "version": "2.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084" + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084", - "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -928,7 +955,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" }, "funding": [ { @@ -936,32 +963,32 @@ "type": "github" } ], - "time": "2024-03-02T07:12:49+00:00" + "time": "2024-07-03T04:41:36+00:00" }, { "name": "sebastian/code-unit", - "version": "2.0.0", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "a81fee9eef0b7a76af11d121767abc44c104e503" + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503", - "reference": "a81fee9eef0b7a76af11d121767abc44c104e503", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.5" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -984,7 +1011,8 @@ "homepage": "https://github.com/sebastianbergmann/code-unit", "support": { "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0" + "security": "https://github.com/sebastianbergmann/code-unit/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3" }, "funding": [ { @@ -992,32 +1020,32 @@ "type": "github" } ], - "time": "2023-02-03T06:58:43+00:00" + "time": "2025-03-19T07:56:08+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", - "version": "3.0.0", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d" + "reference": "183a9b2632194febd219bb9246eee421dad8d45e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", - "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -1039,7 +1067,8 @@ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "support": { "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0" + "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" }, "funding": [ { @@ -1047,36 +1076,39 @@ "type": "github" } ], - "time": "2023-02-03T06:59:15+00:00" + "time": "2024-07-03T04:45:54+00:00" }, { "name": "sebastian/comparator", - "version": "5.0.5", + "version": "6.3.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d" + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55dfef806eb7dfeb6e7a6935601fef866f8ca48d", - "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", "shasum": "" }, "require": { "ext-dom": "*", "ext-mbstring": "*", - "php": ">=8.1", - "sebastian/diff": "^5.0", - "sebastian/exporter": "^5.0" + "php": ">=8.2", + "sebastian/diff": "^6.0", + "sebastian/exporter": "^6.0" }, "require-dev": { - "phpunit/phpunit": "^10.5" + "phpunit/phpunit": "^11.4" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "6.3-dev" } }, "autoload": { @@ -1116,7 +1148,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.5" + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.3" }, "funding": [ { @@ -1136,33 +1168,33 @@ "type": "tidelift" } ], - "time": "2026-01-24T09:25:16+00:00" + "time": "2026-01-24T09:26:40+00:00" }, { "name": "sebastian/complexity", - "version": "3.2.0", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "68ff824baeae169ec9f2137158ee529584553799" + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799", - "reference": "68ff824baeae169ec9f2137158ee529584553799", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", "shasum": "" }, "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=8.1" + "nikic/php-parser": "^5.0", + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.2-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -1186,7 +1218,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", "security": "https://github.com/sebastianbergmann/complexity/security/policy", - "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0" + "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" }, "funding": [ { @@ -1194,33 +1226,33 @@ "type": "github" } ], - "time": "2023-12-21T08:37:17+00:00" + "time": "2024-07-03T04:49:50+00:00" }, { "name": "sebastian/diff", - "version": "5.1.1", + "version": "6.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e" + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e", - "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0", - "symfony/process": "^6.4" + "phpunit/phpunit": "^11.0", + "symfony/process": "^4.2 || ^5" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.1-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -1253,7 +1285,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1" + "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" }, "funding": [ { @@ -1261,27 +1293,27 @@ "type": "github" } ], - "time": "2024-03-02T07:15:17+00:00" + "time": "2024-07-03T04:53:05+00:00" }, { "name": "sebastian/environment", - "version": "6.1.0", + "version": "7.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "8074dbcd93529b357029f5cc5058fd3e43666984" + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984", - "reference": "8074dbcd93529b357029f5cc5058fd3e43666984", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.3" }, "suggest": { "ext-posix": "*" @@ -1289,7 +1321,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "6.1-dev" + "dev-main": "7.2-dev" } }, "autoload": { @@ -1317,42 +1349,54 @@ "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", "security": "https://github.com/sebastianbergmann/environment/security/policy", - "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0" + "source": "https://github.com/sebastianbergmann/environment/tree/7.2.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "type": "tidelift" } ], - "time": "2024-03-23T08:47:14+00:00" + "time": "2025-05-21T11:55:47+00:00" }, { "name": "sebastian/exporter", - "version": "5.1.4", + "version": "6.3.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "0735b90f4da94969541dac1da743446e276defa6" + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/0735b90f4da94969541dac1da743446e276defa6", - "reference": "0735b90f4da94969541dac1da743446e276defa6", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/70a298763b40b213ec087c51c739efcaa90bcd74", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74", "shasum": "" }, "require": { "ext-mbstring": "*", - "php": ">=8.1", - "sebastian/recursion-context": "^5.0" + "php": ">=8.2", + "sebastian/recursion-context": "^6.0" }, "require-dev": { - "phpunit/phpunit": "^10.5" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.1-dev" + "dev-main": "6.3-dev" } }, "autoload": { @@ -1395,7 +1439,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", "security": "https://github.com/sebastianbergmann/exporter/security/policy", - "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.4" + "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.2" }, "funding": [ { @@ -1415,35 +1459,35 @@ "type": "tidelift" } ], - "time": "2025-09-24T06:09:11+00:00" + "time": "2025-09-24T06:12:51+00:00" }, { "name": "sebastian/global-state", - "version": "6.0.2", + "version": "7.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9" + "reference": "3be331570a721f9a4b5917f4209773de17f747d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", - "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7", "shasum": "" }, "require": { - "php": ">=8.1", - "sebastian/object-reflector": "^3.0", - "sebastian/recursion-context": "^5.0" + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -1469,7 +1513,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", "security": "https://github.com/sebastianbergmann/global-state/security/policy", - "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2" + "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" }, "funding": [ { @@ -1477,33 +1521,33 @@ "type": "github" } ], - "time": "2024-03-02T07:19:19+00:00" + "time": "2024-07-03T04:57:36+00:00" }, { "name": "sebastian/lines-of-code", - "version": "2.0.2", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0" + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0", - "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", "shasum": "" }, "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=8.1" + "nikic/php-parser": "^5.0", + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -1527,7 +1571,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" }, "funding": [ { @@ -1535,34 +1579,34 @@ "type": "github" } ], - "time": "2023-12-21T08:38:20+00:00" + "time": "2024-07-03T04:58:38+00:00" }, { "name": "sebastian/object-enumerator", - "version": "5.0.0", + "version": "6.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906" + "reference": "f5b498e631a74204185071eb41f33f38d64608aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906", - "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa", "shasum": "" }, "require": { - "php": ">=8.1", - "sebastian/object-reflector": "^3.0", - "sebastian/recursion-context": "^5.0" + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -1584,7 +1628,8 @@ "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0" + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" }, "funding": [ { @@ -1592,32 +1637,32 @@ "type": "github" } ], - "time": "2023-02-03T07:08:32+00:00" + "time": "2024-07-03T05:00:13+00:00" }, { "name": "sebastian/object-reflector", - "version": "3.0.0", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "24ed13d98130f0e7122df55d06c5c4942a577957" + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957", - "reference": "24ed13d98130f0e7122df55d06c5c4942a577957", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -1639,7 +1684,8 @@ "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0" + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" }, "funding": [ { @@ -1647,32 +1693,32 @@ "type": "github" } ], - "time": "2023-02-03T07:06:18+00:00" + "time": "2024-07-03T05:01:32+00:00" }, { "name": "sebastian/recursion-context", - "version": "5.0.2", + "version": "6.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "5d32fe257a9b39cb63146924d6b4e32a22d4502a" + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5d32fe257a9b39cb63146924d6b4e32a22d4502a", - "reference": "5d32fe257a9b39cb63146924d6b4e32a22d4502a", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.5" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -1703,7 +1749,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.2" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.3" }, "funding": [ { @@ -1723,32 +1769,32 @@ "type": "tidelift" } ], - "time": "2026-08-11T05:27:39+00:00" + "time": "2025-08-13T04:42:22+00:00" }, { "name": "sebastian/type", - "version": "4.0.0", + "version": "5.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "462699a16464c3944eefc02ebdd77882bd3925bf" + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf", - "reference": "462699a16464c3944eefc02ebdd77882bd3925bf", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -1771,37 +1817,50 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/4.0.0" + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/5.1.3" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/type", + "type": "tidelift" } ], - "time": "2023-02-03T07:10:45+00:00" + "time": "2025-08-09T06:55:48+00:00" }, { "name": "sebastian/version", - "version": "4.0.1", + "version": "5.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17" + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17", - "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -1824,7 +1883,8 @@ "homepage": "https://github.com/sebastianbergmann/version", "support": { "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/4.0.1" + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" }, "funding": [ { @@ -1832,7 +1892,7 @@ "type": "github" } ], - "time": "2023-02-07T11:34:05+00:00" + "time": "2024-10-09T05:16:32+00:00" }, { "name": "squizlabs/php_codesniffer", @@ -1918,6 +1978,58 @@ ], "time": "2026-08-06T02:45:27+00:00" }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" + }, { "name": "theseer/tokenizer", "version": "1.3.1", @@ -1975,7 +2087,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=8.1", + "php": ">=8.2", "ext-ctype": "*", "ext-curl": "*", "ext-dom": "*", @@ -1998,13 +2110,13 @@ "ext-zlib": "*" }, "platform-dev": { - "php": ">=8.1", + "php": ">=8.2", "ext-phar": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*" }, "platform-overrides": { - "php": "8.1" + "php": "8.2" }, "plugin-api-version": "2.9.0" } diff --git a/constants.php b/constants.php index fca08c0a4..8bd6b9f9c 100644 --- a/constants.php +++ b/constants.php @@ -4,7 +4,7 @@ declare(strict_types=1); // /** @var string */ -const FRESHRSS_MIN_PHP_VERSION = '8.1.0'; +const FRESHRSS_MIN_PHP_VERSION = '8.2.0'; /** @var string */ const FRESHRSS_VERSION = '1.30.5-dev'; /** @var string */ diff --git a/docs/en/admins/02_Prerequisites.md b/docs/en/admins/02_Prerequisites.md index 0fe8793df..864a316b9 100644 --- a/docs/en/admins/02_Prerequisites.md +++ b/docs/en/admins/02_Prerequisites.md @@ -7,7 +7,7 @@ You need to verify that your server can run FreshRSS before installing it. If yo | Software | Recommended | Also Works With | | ------------- | ----------------------- | ----------------------- | | Web server | **Apache 2.4** | nginx, lighttpd | -| PHP | **PHP 8.1+** | FreshRSS 1.24.3: PHP 7.4+
FreshRSS 1.22.1: PHP 7.2+ | +| PHP | **PHP 8.2+** | FreshRSS 1.30.4: PHP 8.1+ | | PHP modules | Required: libxml, cURL, JSON, PDO_MySQL, PCRE and ctype.
Required (32-bit only): GMP
Recommended: Zlib, mbstring, iconv, ZipArchive
*For the whole modules list see [Dockerfile](https://github.com/FreshRSS/FreshRSS/blob/edge/Docker/Dockerfile-Alpine#L9-L11)* | | | Database | **PostgreSQL 10+** | SQLite, MariaDB 10.6+, MySQL 8.0+ | | Browser | **Firefox** | Chrome, Opera, Safari, or Edge | diff --git a/docs/en/admins/10_ServerConfig.md b/docs/en/admins/10_ServerConfig.md index 1ca99883c..f90d336f8 100644 --- a/docs/en/admins/10_ServerConfig.md +++ b/docs/en/admins/10_ServerConfig.md @@ -95,7 +95,7 @@ server { # php files handling # this regex is mandatory because of the API location ~ ^.+?\.php(/.*)?$ { - fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; + fastcgi_pass unix:/var/run/php/php8.2-fpm.sock; fastcgi_split_path_info ^(.+\.php)(/.*)$; # By default, the variable PATH_INFO is not set under PHP-FPM # But FreshRSS APIs greader.php and misc.php need it. If you have a “Bad Request” error, double check this var! diff --git a/docs/fr/users/01_Installation.md b/docs/fr/users/01_Installation.md index 6880e0059..a6b09be93 100644 --- a/docs/fr/users/01_Installation.md +++ b/docs/fr/users/01_Installation.md @@ -7,7 +7,7 @@ Il est toutefois de votre responsabilité de vérifier que votre hébergement pe | Logiciel | Recommandé | Fonctionne aussi avec | | -------- | ----------- | --------------------- | | Serveur web | **Apache 2.4+** | nginx, lighttpd | -| PHP | **PHP 8.1+** | FreshRSS 1.24.3 : PHP 7.4+
FreshRSS 1.22.1 : PHP 7.2+ | +| PHP | **PHP 8.2+** | FreshRSS 1.30.4 : PHP 8.1+ | | Modules PHP | Requis : libxml, cURL, JSON, PDO_MySQL, PCRE et ctype
Requis (32 bits seulement) : GMP
Recommandé : Zlib, mbstring et iconv, ZipArchive
*Pour une liste complète des modules nécessaires voir le [Dockerfile](https://github.com/FreshRSS/FreshRSS/blob/edge/Docker/Dockerfile-Alpine#L9-L11)* | | | Base de données | **PostgreSQL 10+** | SQLite, MariaDB 10.6+, MySQL 8.0+ | | Navigateur | **Firefox** | Chrome, Opera, Safari, or Edge | @@ -118,7 +118,7 @@ server { # gestion des fichiers php # il est nécessaire d’utiliser cette expression régulière pour le bon fonctionnement de l’API location ~ ^.+?\.php(/.*)?$ { - fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; + fastcgi_pass unix:/var/run/php/php8.2-fpm.sock; fastcgi_split_path_info ^(.+\.php)(/.*)$; # Par défaut la variable PATH_INFO n’est pas définie sous PHP-FPM # mais les APIs FreshRSS greader.php et misc.php en ont besoin. Si vous avez un “Bad Request”, vérifiez bien cette dernière ! diff --git a/lib/Minz/Hook.php b/lib/Minz/Hook.php index cd56de646..fb21fd83a 100644 --- a/lib/Minz/Hook.php +++ b/lib/Minz/Hook.php @@ -1,7 +1,7 @@ */ public static function provideTooLongOrTooDeepSearches(): array { + if (!FreshRSS_Context::hasSystemConf()) { + FreshRSS_Context::initSystem(); + } $tooLong = str_repeat('a', FreshRSS_Context::systemConf()->limits['max_search_length'] + 1); $tooDeep = str_repeat('(', FreshRSS_Context::systemConf()->limits['max_search_parentheses_depth'] + 1) . 'ab' . str_repeat(')', FreshRSS_Context::systemConf()->limits['max_search_parentheses_depth'] + 1); diff --git a/tests/app/Models/EntryTest.php b/tests/app/Models/EntryTest.php index 7dcaa2850..37874a909 100644 --- a/tests/app/Models/EntryTest.php +++ b/tests/app/Models/EntryTest.php @@ -3,8 +3,8 @@ declare(strict_types=1); final class EntryTest extends \PHPUnit\Framework\TestCase { - public function __construct(string $name) { - parent::__construct($name); + #[\Override] + protected function setUp(): void { if (!FreshRSS_Context::hasSystemConf()) { FreshRSS_Context::initSystem(); } diff --git a/tests/app/Models/SearchTest.php b/tests/app/Models/SearchTest.php index 1daa460c8..a376fda31 100644 --- a/tests/app/Models/SearchTest.php +++ b/tests/app/Models/SearchTest.php @@ -7,8 +7,8 @@ require_once LIB_PATH . '/lib_date.php'; final class SearchTest extends \PHPUnit\Framework\TestCase { - public function __construct(string $name) { - parent::__construct($name); + #[\Override] + protected function setUp(): void { if (!FreshRSS_Context::hasSystemConf()) { FreshRSS_Context::initSystem(); } @@ -866,10 +866,8 @@ final class SearchTest extends \PHPUnit\Framework\TestCase { ]; } - /** - * @dataProvider provideRegexPostreSQL - * @param array $values - */ + /** @param array $values */ + #[DataProvider('provideRegexPostreSQL')] public function test__regex_postgresql(string $input, string $sql, array $values): void { [$filterValues, $filterSearch] = FreshRSS_EntryDAOPGSQL::sqlBooleanSearch('e.', new FreshRSS_BooleanSearch($input)); self::assertSame(trim($sql), trim($filterSearch)); @@ -977,10 +975,8 @@ final class SearchTest extends \PHPUnit\Framework\TestCase { ]; } - /** - * @dataProvider provideRegexMariaDB - * @param array $values - */ + /** @param array $values */ + #[DataProvider('provideRegexMariaDB')] public function test__regex_mariadb(string $input, string $sql, array $values): void { FreshRSS_DatabaseDAO::$dummyConnection = true; FreshRSS_DatabaseDAO::setStaticVersion('11.4.3-MariaDB-ubu2404'); @@ -1030,10 +1026,8 @@ final class SearchTest extends \PHPUnit\Framework\TestCase { ]; } - /** - * @dataProvider provideRegexMySQL - * @param array $values - */ + /** @param array $values */ + #[DataProvider('provideRegexMySQL')] public function test__regex_mysql(string $input, string $sql, array $values): void { FreshRSS_DatabaseDAO::$dummyConnection = true; FreshRSS_DatabaseDAO::setStaticVersion('9.0.1'); @@ -1078,10 +1072,8 @@ final class SearchTest extends \PHPUnit\Framework\TestCase { ]; } - /** - * @dataProvider provideRegexSQLite - * @param array $values - */ + /** @param array $values */ + #[DataProvider('provideRegexSQLite')] public function test__regex_sqlite(string $input, string $sql, array $values): void { [$filterValues, $filterSearch] = FreshRSS_EntryDAOSQLite::sqlBooleanSearch('e.', new FreshRSS_BooleanSearch($input)); self::assertSame(trim($sql), trim($filterSearch)); diff --git a/tests/app/Models/SimplePieCustomTest.php b/tests/app/Models/SimplePieCustomTest.php index 7b7b13ba9..764cfc965 100644 --- a/tests/app/Models/SimplePieCustomTest.php +++ b/tests/app/Models/SimplePieCustomTest.php @@ -9,8 +9,8 @@ use PHPUnit\Framework\Attributes\DataProvider; */ final class SimplePieCustomTest extends \PHPUnit\Framework\TestCase { - public function __construct(string $name) { - parent::__construct($name); + #[\Override] + protected function setUp(): void { if (!FreshRSS_Context::hasSystemConf()) { FreshRSS_Context::initSystem(); } diff --git a/tests/app/Models/UserQueryTest.php b/tests/app/Models/UserQueryTest.php index fb6d12e0a..93f2d1a61 100644 --- a/tests/app/Models/UserQueryTest.php +++ b/tests/app/Models/UserQueryTest.php @@ -8,8 +8,8 @@ use PHPUnit\Framework\TestCase; */ class UserQueryTest extends TestCase { - public function __construct(string $name) { - parent::__construct($name); + #[\Override] + protected function setUp(): void { if (!FreshRSS_Context::hasSystemConf()) { FreshRSS_Context::initSystem(); } diff --git a/tests/app/Utils/httpUtilTest.php b/tests/app/Utils/httpUtilTest.php index 5284a75e5..471703ed9 100644 --- a/tests/app/Utils/httpUtilTest.php +++ b/tests/app/Utils/httpUtilTest.php @@ -114,33 +114,34 @@ final class httpUtilTest extends \PHPUnit\Framework\TestCase { ); } - public function test_getCurlResolveInfoRejectsPrivateNat64Address(): void { + #[DataProvider('providePrivateSubnets')] + public function test_getCurlResolveInfoRejectsPrivateSubnets(string $ip): void { FreshRSS_Context::initSystem(); $resolveOk = new ReflectionProperty(FreshRSS_http_Util::class, 'resolve_ok'); - $resolveOk->setValue(null, [ - 'example.test' => [ - '64:ff9b::a9fe:a9fe', - ], - ]); - - self::assertNull( - FreshRSS_http_Util::getCurlResolveInfo('https://example.test/feed') - ); + $resolveOk->setValue(null, ['example.test' => [$ip]]); + self::assertNull(FreshRSS_http_Util::getCurlResolveInfo('https://example.test/feed')); } - public function test_getCurlResolveInfoRejectsLocalUseNat64Address(): void { - FreshRSS_Context::initSystem(); - $resolveOk = new ReflectionProperty(FreshRSS_http_Util::class, 'resolve_ok'); - $resolveOk->setValue(null, [ - 'example.test' => [ - '64:ff9b:1::c000:4260', - '64:ff9b:1::a9fe:a9fe', - ], - ]); - - self::assertNull( - FreshRSS_http_Util::getCurlResolveInfo('https://example.test/feed') - ); + /** @return array */ + public static function providePrivateSubnets(): array { + return [ + // One example per range, ensuring FILTER_FLAG_GLOBAL_RANGE and custom checks are sufficient + '127.0.0.0/8' => ['127.0.0.1'], // RFC1700 (Loopback) + '10.0.0.0/8' => ['10.0.0.5'], // RFC1918 + '192.168.0.0/16' => ['192.168.1.5'], // RFC1918 + '172.16.0.0/12' => ['172.16.5.5'], // RFC1918 + '169.254.0.0/16' => ['169.254.5.5'], // RFC3927 + '0.0.0.0/8' => ['0.0.0.5'], // RFC5735 + '240.0.0.0/4' => ['240.0.0.5'], // RFC1112 + '100.64.0.0/10' => ['100.64.5.5'], // RFC6598 (Shared Address Space of Carrier-Grade NAT) + '::1/128' => ['::1'], // Loopback + 'fc00::/7' => ['fc00::5'], // Unique Local Address + 'fe80::/10' => ['fe80::5'], // Link Local Address + '::ffff:0:0/96' => ['::ffff:10.0.0.5'], // IPv4 translations + '64:ff9b::/96' => ['64:ff9b::a9fe:a9fe'], // RFC6052 (IPv4/IPv6 Translator, NAT64) + '64:ff9b:1::/48' => ['64:ff9b:1::c000:4260'], // RFC8215 (Local-Use IPv4/IPv6 Translation Prefix) + '::/128' => ['::'], // Unspecified address + ]; } /** Socks schemes default to port 1080, and an IP address proxy produces no resolve entry */ @@ -171,11 +172,16 @@ final class httpUtilTest extends \PHPUnit\Framework\TestCase { FreshRSS_http_Util::getCurlResolveInfo('socks5h://proxy.example.test:1080') ); - // An entry is still produced without allowlisting, because the address is public + // Applications must not emit resolve entries for an address that is not guaranteed public. + // TEST-NET-2 is a reserved range, so without an allowlist entry, no entry is produced. FreshRSS_Context::systemConf()->internal_host_allowlist = []; + self::assertNull(FreshRSS_http_Util::getCurlResolveInfo('socks5h://proxy.example.test:1080')); + + // A genuinely public address produces an entry without allowlisting + $resolveOk->setValue(null, ['public-proxy.example.test' => ['8.8.8.8']]); self::assertSame( - ['proxy.example.test:1080:198.51.100.7'], - FreshRSS_http_Util::getCurlResolveInfo('socks5h://proxy.example.test:1080') + ['public-proxy.example.test:1080:8.8.8.8'], + FreshRSS_http_Util::getCurlResolveInfo('socks5h://public-proxy.example.test:1080') ); // A proxy resolving to a private address is rejected unless allowlisted