1
1
Fork 0
mirror of https://code.mensbeam.com/MensBeam/Arsse.git synced 2024-12-22 21:22:40 +00:00

Merge branch 'master' into redup

This commit is contained in:
J. King 2023-01-28 15:08:54 -05:00
commit 9d391469ad
28 changed files with 337 additions and 363 deletions

View file

@ -1,3 +1,9 @@
Version 0.??.? (????-??-??)
===========================
Changes:
- Require PHP 7.3
Version 0.10.4 (2023-01-24)
===========================

View file

@ -11,6 +11,12 @@ usually prudent:
`composer install -o --no-dev`
Upgrading from 0.10.2 to 0.10.3
=============================
- PHP 7.3 is now required
Upgrading from 0.10.2 to 0.10.3
=============================

View file

@ -13,7 +13,7 @@ require_once BASE."vendor".DIRECTORY_SEPARATOR."autoload.php";
ignore_user_abort(true);
ini_set("memory_limit", "-1");
ini_set("max_execution_time", "0");
// FIXME: This is required because various dependencies have yet to adjust to PHP 8.1
// NOTE: While running in the wild we don't want to spew deprecation warnings if users are ahead of us in PHP versions
error_reporting(\E_ALL & ~\E_DEPRECATED);
if (\PHP_SAPI === "cli") {

View file

@ -26,7 +26,7 @@
"ext-dom": "*",
"nicolus/picofeed": "dev-bugfix",
"hosteurope/password-generator": "1.*",
"docopt/docopt": "1.*",
"docopt/docopt": "dev-master",
"jkingweb/druuid": "3.*",
"guzzlehttp/psr7": "1.*",
"laminas/laminas-httphandlerrunner": "1.*"
@ -39,7 +39,7 @@
},
"config": {
"platform": {
"php": "7.1.33"
"php": "7.3.33"
},
"allow-plugins": {
"bamarni/composer-bin-plugin": true
@ -64,6 +64,10 @@
{
"type": "vcs",
"url": "https://github.com/rhukster/picoFeed"
},
{
"type": "vcs",
"url": "https://github.com/docopt/docopt.php"
}
]
}

427
composer.lock generated
View file

@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "21a116823c3335992910966f31861811",
"content-hash": "2e8ad0d4821fdfc0d975e98f2e2c3efe",
"packages": [
{
"name": "docopt/docopt",
"version": "1.0.4",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/docopt/docopt.php.git",
"reference": "bf3683a16e09fa1665e493eb4d5a29469e132a4f"
"reference": "5ad491cb9fc072e8bb0497061a09b0efcf25cbcf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/docopt/docopt.php/zipball/bf3683a16e09fa1665e493eb4d5a29469e132a4f",
"reference": "bf3683a16e09fa1665e493eb4d5a29469e132a4f",
"url": "https://api.github.com/repos/docopt/docopt.php/zipball/5ad491cb9fc072e8bb0497061a09b0efcf25cbcf",
"reference": "5ad491cb9fc072e8bb0497061a09b0efcf25cbcf",
"shasum": ""
},
"require": {
@ -26,13 +26,13 @@
"require-dev": {
"phpunit/phpunit": "4.1.*"
},
"default-branch": true,
"type": "library",
"autoload": {
"classmap": [
"src/docopt.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@ -51,44 +51,56 @@
"docs"
],
"support": {
"issues": "https://github.com/docopt/docopt.php/issues",
"source": "https://github.com/docopt/docopt.php/tree/1.0.4"
"source": "https://github.com/docopt/docopt.php/tree/master",
"issues": "https://github.com/docopt/docopt.php/issues"
},
"time": "2019-12-03T02:48:46+00:00"
"time": "2022-05-11T23:52:25+00:00"
},
{
"name": "guzzlehttp/guzzle",
"version": "6.5.8",
"version": "7.5.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "a52f0440530b54fa079ce76e8c5d196a42cad981"
"reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981",
"reference": "a52f0440530b54fa079ce76e8c5d196a42cad981",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/b50a2a1251152e43f6a37f0fa053e730a67d25ba",
"reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^1.0",
"guzzlehttp/psr7": "^1.9",
"php": ">=5.5",
"symfony/polyfill-intl-idn": "^1.17"
"guzzlehttp/promises": "^1.5",
"guzzlehttp/psr7": "^1.9 || ^2.4",
"php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
},
"provide": {
"psr/http-client-implementation": "1.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.1",
"ext-curl": "*",
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
"psr/log": "^1.1"
"php-http/client-integration-tests": "^3.0",
"phpunit/phpunit": "^8.5.29 || ^9.5.23",
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
"suggest": {
"ext-curl": "Required for CURL handler support",
"ext-intl": "Required for Internationalized Domain Name (IDN) support",
"psr/log": "Required for using the Log middleware"
},
"type": "library",
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
},
"branch-alias": {
"dev-master": "6.5-dev"
"dev-master": "7.5-dev"
}
},
"autoload": {
@ -141,19 +153,20 @@
}
],
"description": "Guzzle is a PHP HTTP client library",
"homepage": "http://guzzlephp.org/",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"psr-18",
"psr-7",
"rest",
"web service"
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/6.5.8"
"source": "https://github.com/guzzle/guzzle/tree/7.5.0"
},
"funding": [
{
@ -169,7 +182,7 @@
"type": "tidelift"
}
],
"time": "2022-06-20T22:16:07+00:00"
"time": "2022-08-28T15:39:27+00:00"
},
{
"name": "guzzlehttp/promises",
@ -539,21 +552,21 @@
},
{
"name": "laminas/laminas-httphandlerrunner",
"version": "1.2.0",
"version": "1.5.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-httphandlerrunner.git",
"reference": "e1a5dad040e0043135e8095ee27d1fbf6fb640e1"
"reference": "5f94e55d93f756e8ad07b9049aeb3d6d84582d0e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-httphandlerrunner/zipball/e1a5dad040e0043135e8095ee27d1fbf6fb640e1",
"reference": "e1a5dad040e0043135e8095ee27d1fbf6fb640e1",
"url": "https://api.github.com/repos/laminas/laminas-httphandlerrunner/zipball/5f94e55d93f756e8ad07b9049aeb3d6d84582d0e",
"reference": "5f94e55d93f756e8ad07b9049aeb3d6d84582d0e",
"shasum": ""
},
"require": {
"laminas/laminas-zendframework-bridge": "^1.0",
"php": "^7.1",
"php": "^7.3 || ~8.0.0 || ~8.1.0",
"psr/http-message": "^1.0",
"psr/http-message-implementation": "^1.0",
"psr/http-server-handler": "^1.0"
@ -563,15 +576,13 @@
},
"require-dev": {
"laminas/laminas-coding-standard": "~1.0.0",
"laminas/laminas-diactoros": "^1.7 || ^2.1.1",
"phpunit/phpunit": "^7.0.2"
"laminas/laminas-diactoros": "^2.8.0",
"phpunit/phpunit": "^9.5.9",
"psalm/plugin-phpunit": "^0.16.1",
"vimeo/psalm": "^4.10.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev",
"dev-develop": "1.3.x-dev"
},
"laminas": {
"config-provider": "Laminas\\HttpHandlerRunner\\ConfigProvider"
}
@ -608,40 +619,37 @@
"type": "community_bridge"
}
],
"time": "2020-06-03T15:52:17+00:00"
"time": "2021-09-22T09:17:54+00:00"
},
{
"name": "laminas/laminas-xml",
"version": "1.2.0",
"version": "1.4.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-xml.git",
"reference": "879cc66d1bba6a37705e98074f52a6960c220020"
"reference": "dcadeefdb6d7ed6b39d772b47e3845003d6ea60f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-xml/zipball/879cc66d1bba6a37705e98074f52a6960c220020",
"reference": "879cc66d1bba6a37705e98074f52a6960c220020",
"url": "https://api.github.com/repos/laminas/laminas-xml/zipball/dcadeefdb6d7ed6b39d772b47e3845003d6ea60f",
"reference": "dcadeefdb6d7ed6b39d772b47e3845003d6ea60f",
"shasum": ""
},
"require": {
"laminas/laminas-zendframework-bridge": "^1.0",
"php": "^5.6 || ^7.0"
"ext-dom": "*",
"ext-simplexml": "*",
"php": "^7.3 || ~8.0.0 || ~8.1.0"
},
"replace": {
"zendframework/zendxml": "self.version"
"conflict": {
"zendframework/zendxml": "*"
},
"require-dev": {
"ext-iconv": "*",
"laminas/laminas-coding-standard": "~1.0.0",
"phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.4"
"phpunit/phpunit": "^9.5.8",
"squizlabs/php_codesniffer": "3.6.1 as 2.9999999.9999999"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev",
"dev-develop": "1.3.x-dev"
}
},
"autoload": {
"psr-4": {
"Laminas\\Xml\\": "src/"
@ -660,34 +668,41 @@
],
"support": {
"chat": "https://laminas.dev/chat",
"docs": "https://docs.laminas.dev/laminas-xml/",
"forum": "https://discourse.laminas.dev",
"issues": "https://github.com/laminas/laminas-xml/issues",
"rss": "https://github.com/laminas/laminas-xml/releases.atom",
"source": "https://github.com/laminas/laminas-xml"
},
"time": "2019-12-31T18:05:42+00:00"
"funding": [
{
"url": "https://funding.communitybridge.org/projects/laminas-project",
"type": "community_bridge"
}
],
"time": "2021-11-30T02:16:35+00:00"
},
{
"name": "laminas/laminas-zendframework-bridge",
"version": "1.1.1",
"version": "1.4.1",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-zendframework-bridge.git",
"reference": "6ede70583e101030bcace4dcddd648f760ddf642"
"reference": "88bf037259869891afce6504cacc4f8a07b24d0f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/6ede70583e101030bcace4dcddd648f760ddf642",
"reference": "6ede70583e101030bcace4dcddd648f760ddf642",
"url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/88bf037259869891afce6504cacc4f8a07b24d0f",
"reference": "88bf037259869891afce6504cacc4f8a07b24d0f",
"shasum": ""
},
"require": {
"php": "^5.6 || ^7.0 || ^8.0"
"php": "^7.3 || ~8.0.0 || ~8.1.0"
},
"require-dev": {
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1 || ^9.3",
"squizlabs/php_codesniffer": "^3.5"
"phpunit/phpunit": "^9.3",
"psalm/plugin-phpunit": "^0.15.1",
"squizlabs/php_codesniffer": "^3.5",
"vimeo/psalm": "^4.6"
},
"type": "library",
"extra": {
@ -726,7 +741,7 @@
"type": "community_bridge"
}
],
"time": "2020-09-14T14:23:00+00:00"
"time": "2021-12-21T14:34:37+00:00"
},
{
"name": "nicolus/picofeed",
@ -792,6 +807,58 @@
},
"time": "2022-09-23T17:42:18+00:00"
},
{
"name": "psr/http-client",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-client.git",
"reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
"reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
"shasum": ""
},
"require": {
"php": "^7.0 || ^8.0",
"psr/http-message": "^1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Client\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP clients",
"homepage": "https://github.com/php-fig/http-client",
"keywords": [
"http",
"http-client",
"psr",
"psr-18"
],
"support": {
"source": "https://github.com/php-fig/http-client/tree/master"
},
"time": "2020-06-29T06:28:15+00:00"
},
{
"name": "psr/http-message",
"version": "1.0.1",
@ -997,131 +1064,35 @@
"time": "2019-03-08T08:55:37+00:00"
},
{
"name": "symfony/polyfill-intl-idn",
"version": "v1.27.0",
"name": "symfony/deprecation-contracts",
"version": "v2.5.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
"reference": "639084e360537a19f9ee352433b84ce831f3d2da"
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/639084e360537a19f9ee352433b84ce831f3d2da",
"reference": "639084e360537a19f9ee352433b84ce831f3d2da",
"shasum": ""
},
"require": {
"php": ">=7.1",
"symfony/polyfill-intl-normalizer": "^1.10",
"symfony/polyfill-php72": "^1.10"
},
"suggest": {
"ext-intl": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Intl\\Idn\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Laurent Bassin",
"email": "laurent@bassin.info"
},
{
"name": "Trevor Rowbotham",
"email": "trevor.rowbotham@pm.me"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"idn",
"intl",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.27.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"suggest": {
"ext-intl": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Intl\\Normalizer\\": ""
},
"classmap": [
"Resources/stubs"
"function.php"
]
},
"notification-url": "https://packagist.org/downloads/",
@ -1138,18 +1109,10 @@
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for intl's Normalizer class and related functions",
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"intl",
"normalizer",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0"
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2"
},
"funding": [
{
@ -1165,111 +1128,42 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/polyfill-php72",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
"reference": "869329b1e9894268a8a61dabb69153029b7a8c97"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97",
"reference": "869329b1e9894268a8a61dabb69153029b7a8c97",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php72\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php72/tree/v1.27.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2022-01-02T09:53:40+00:00"
}
],
"packages-dev": [
{
"name": "bamarni/composer-bin-plugin",
"version": "v1.5.0",
"version": "1.8.2",
"source": {
"type": "git",
"url": "https://github.com/bamarni/composer-bin-plugin.git",
"reference": "49934ffea764864788334c1485fbb08a4b852031"
"reference": "92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/bamarni/composer-bin-plugin/zipball/49934ffea764864788334c1485fbb08a4b852031",
"reference": "49934ffea764864788334c1485fbb08a4b852031",
"url": "https://api.github.com/repos/bamarni/composer-bin-plugin/zipball/92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880",
"reference": "92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.0 || ^2.0",
"php": "^5.5.9 || ^7.0 || ^8.0"
"composer-plugin-api": "^2.0",
"php": "^7.2.5 || ^8.0"
},
"require-dev": {
"composer/composer": "^1.0 || ^2.0",
"symfony/console": "^2.5 || ^3.0 || ^4.0"
"composer/composer": "^2.0",
"ext-json": "*",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-phpunit": "^1.1",
"phpunit/phpunit": "^8.5 || ^9.5",
"symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0",
"symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0",
"symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0"
},
"type": "composer-plugin",
"extra": {
"class": "Bamarni\\Composer\\Bin\\Plugin"
"class": "Bamarni\\Composer\\Bin\\BamarniBinPlugin"
},
"autoload": {
"psr-4": {
@ -1291,15 +1185,16 @@
],
"support": {
"issues": "https://github.com/bamarni/composer-bin-plugin/issues",
"source": "https://github.com/bamarni/composer-bin-plugin/tree/v1.5.0"
"source": "https://github.com/bamarni/composer-bin-plugin/tree/1.8.2"
},
"time": "2022-02-22T21:01:25+00:00"
"time": "2022-10-31T08:38:03+00:00"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"nicolus/picofeed": 20
"nicolus/picofeed": 20,
"docopt/docopt": 20
},
"prefer-stable": false,
"prefer-lowest": false,
@ -1313,7 +1208,7 @@
},
"platform-dev": [],
"platform-overrides": {
"php": "7.1.33"
"php": "7.3.33"
},
"plugin-api-version": "2.3.0"
}

8
dist/arch/PKGBUILD vendored
View file

@ -1,6 +1,6 @@
# Maintainer: J. King <jking@jkingweb.ca>
pkgname="arsse"
pkgver=0.9.2
pkgver=0.10.4
pkgrel=1
epoch=
pkgdesc="Multi-protocol RSS/Atom newsfeed synchronization server"
@ -14,7 +14,7 @@ optdepends=("nginx: HTTP server"
"apache>=2.4: HTTP server"
"percona-server: Alternate database"
"postgresql>=10: Alternate database"
"php-pgsql>=7.1: PostgreSQL database support")
"php-pgsql>=7.3: PostgreSQL database support")
backup=("etc/webapps/arsse/config.php"
"etc/php/php-fpm.d/arsse.conf"
"etc/webapps/arsse/nginx/example.conf"
@ -24,12 +24,12 @@ backup=("etc/webapps/arsse/config.php"
"etc/webapps/arsse/apache/example.conf"
"etc/webapps/arsse/apache/arsse.conf"
"etc/webapps/arsse/apache/arsse-loc.conf")
source=("arsse-0.9.2.tar.gz")
source=("arsse-0.10.4.tar.gz")
md5sums=("SKIP")
package() {
# define runtime dependencies
depends=("php>=7.1" "php-intl>=7.1" "php-sqlite>=7.1" "php-fpm>=7.1")
depends=("php>=7.3" "php-intl>=7.3" "php-sqlite>=7.3" "php-fpm>=7.3")
# create most directories necessary for the final package
cd "$pkgdir"
mkdir -p "usr/share/webapps/arsse" "usr/share/doc/arsse" "usr/share/licenses/arsse" "usr/lib/systemd/system" "usr/lib/sysusers.d" "usr/lib/tmpfiles.d" "etc/php/php-fpm.d" "etc/webapps/arsse"

View file

@ -1,6 +1,6 @@
# Maintainer: J. King <jking@jkingweb.ca>
pkgname="arsse-git"
pkgver=0.9.2
pkgver=0.10.4
pkgrel=1
epoch=
pkgdesc="Multi-protocol RSS/Atom newsfeed synchronization server, bugfix-testing version"
@ -9,14 +9,14 @@ url="https://thearsse.com/"
license=("MIT")
provides=("arsse")
conflicts=("arsse")
depends=("php>=7.1" "php-intl>=7.1" "php-sqlite>=7.1")
depends=("php>=7.3" "php-intl>=7.3" "php-sqlite>=7.3")
makedepends=("composer" "pandoc")
checkdepends=()
optdepends=("nginx: HTTP server"
"apache>=2.4: HTTP server"
"percona-server: Alternate database"
"postgresql>=10: Alternate database"
"php-pgsql>=7.1: PostgreSQL database support")
"php-pgsql>=7.3: PostgreSQL database support")
backup=("etc/webapps/arsse/config.php"
"etc/php/php-fpm.d/arsse.conf"
"etc/webapps/arsse/nginx/example.conf"
@ -46,7 +46,7 @@ build() {
package() {
# define runtime dependencies
depends=("php>=7.1" "php-intl>=7.1" "php-sqlite>=7.1" "php-fpm>=7.1")
depends=("php>=7.3" "php-intl>=7.3" "php-sqlite>=7.3" "php-fpm>=7.3")
# create most directories necessary for the final package
cd "$pkgdir"
mkdir -p "usr/share/webapps/arsse" "usr/share/doc/arsse" "usr/share/licenses/arsse" "usr/lib/systemd/system" "usr/lib/sysusers.d" "usr/lib/tmpfiles.d" "etc/php/php-fpm.d" "etc/webapps/arsse"

2
dist/debian/control vendored
View file

@ -20,7 +20,7 @@ Description: Multi-protocol RSS/Atom newsfeed synchronization server
server.
Depends: ${misc:Depends},
dbconfig-sqlite3 | dbconfig-pgsql | dbconfig-mysql | dbconfig-no-thanks,
php (>= 7.1.0),
php (>= 7.3.0),
php-cli,
php-intl,
php-json,

View file

@ -11,7 +11,7 @@ The Arsse has the following requirements:
- A Web server such as:
- [Nginx](https://nginx.org)
- [Apache HTTP server](https://httpd.apache.org) 2.4 or later
- PHP 7.1.0 or later with the following extensions:
- PHP 7.3.0 or later with the following extensions:
- [intl](https://php.net/manual/en/book.intl.php), [json](https://php.net/manual/en/book.json.php), [hash](https://php.net/manual/en/book.hash.php), [filter](https://php.net/manual/en/book.filter.php), and [dom](https://php.net/manual/en/book.dom.php)
- [simplexml](https://php.net/manual/en/book.simplexml.php), and [iconv](https://php.net/manual/en/book.iconv.php)
- One of:

View file

@ -7,13 +7,15 @@
declare(strict_types=1);
namespace JKingWeb\Arsse;
use AllowDynamicProperties;
use JKingWeb\Arsse\Misc\ValueInfo as Value;
/** Class for loading, saving, and querying configuration
*
* The Conf class serves both as a means of importing and querying configuration information, as well as a source for default parameters when a configuration file does not specify a value.
* All public properties are configuration parameters that may be set by the server administrator. */
class Conf {
#[AllowDynamicProperties]
class Conf {
/** @var string Default language to use for logging and errors */
public $lang = "en";

View file

@ -1362,12 +1362,12 @@ class Database {
"UPDATE arsse_subscriptions SET feed_title = ?, source = ?, updated = CURRENT_TIMESTAMP, last_mod = ?, etag = ?, err_count = 0, err_msg = '', next_fetch = ?, size = ?, icon = ? WHERE id = ?",
["str", "str", "datetime", "strict str", "datetime", "int", "int", "int"]
)->run(
$feed->data->title,
$feed->data->siteUrl,
$feed->title,
$feed->siteUrl,
$feed->lastModified,
$feed->resource->getEtag(),
$feed->etag,
$feed->nextFetch,
sizeof($feed->data->items),
sizeof($feed->items),
$icon,
$subID
);

View file

@ -20,6 +20,7 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
public const SQLITE_MISMATCH = 20;
protected $db;
protected $collator;
public function __construct() {
// check to make sure required extension is loaded

View file

@ -6,6 +6,7 @@
declare(strict_types=1);
namespace JKingWeb\Arsse;
use JKingWeb\Arsse\Feed\Item;
use JKingWeb\Arsse\Misc\Date;
use JKingWeb\Arsse\Rule\Rule;
use PicoFeed\PicoFeedException;
@ -15,63 +16,63 @@ use PicoFeed\Reader\Reader;
use PicoFeed\Reader\Favicon;
use PicoFeed\Scraper\Scraper;
class Feed {
public $data = null;
class Feed {
public $title;
public $siteUrl;
public $iconUrl;
public $iconType;
public $iconData;
public $resource;
public $modified = false;
public $lastModified;
public $etag;
public $nextFetch;
public $items = [];
public $newItems = [];
public $changedItems = [];
public $filteredItems = [];
public static function discover(string $url, string $username = '', string $password = ''): string {
// fetch the candidate feed
$f = self::download($url, "", "", $username, $password);
if ($f->reader->detectFormat($f->getContent())) {
[$client, $reader] = self::download($url, "", "", $username, $password);
if ($reader->detectFormat($client->getContent())) {
// if the prospective URL is a feed, use it
$out = $url;
} else {
$links = $f->reader->find($f->getUrl(), $f->getContent());
$links = $reader->find($client->getUrl(), $client->getContent());
if (!$links) {
// work around a PicoFeed memory leak
libxml_use_internal_errors(false);
throw new Feed\Exception("", ['url' => $url], new \PicoFeed\Reader\SubscriptionNotFoundException('Unable to find a subscription'));
} else {
$out = $links[0];
}
}
// work around a PicoFeed memory leak
libxml_use_internal_errors(false);
return $out;
}
public static function discoverAll(string $url, string $username = '', string $password = ''): array {
// fetch the candidate feed
$f = self::download($url, "", "", $username, $password);
if ($f->reader->detectFormat($f->getContent())) {
[$client, $reader] = self::download($url, "", "", $username, $password);
if ($reader->detectFormat($client->getContent())) {
// if the prospective URL is a feed, use it
return [$url];
} else {
return $f->reader->find($f->getUrl(), $f->getContent());
return $reader->find($client->getUrl(), $client->getContent());
}
}
public function __construct(int $feedID = null, string $url, string $lastModified = '', string $etag = '', string $username = '', string $password = '', bool $scrape = false) {
// fetch the feed
$this->resource = self::download($url, $lastModified, $etag, $username, $password);
[$client, $reader] = self::download($url, $lastModified, $etag, $username, $password);
// format the HTTP Last-Modified date returned
$lastMod = $this->resource->getLastModified();
$lastMod = $client->getLastModified();
if (strlen($lastMod ?? "")) {
$this->lastModified = Date::normalize($lastMod, "http");
}
$this->modified = $this->resource->isModified();
//parse the feed, if it has been modified
$this->modified = $client->isModified();
// get the ETag
$this->etag = $client->getEtag();
// parse the feed, if it has been modified
if ($this->modified) {
$this->parse();
$this->parse($client, $reader);
// ascertain whether there are any articles not in the database
$this->matchToDatabase($feedID);
// if caching header fields are not sent by the server, try to ascertain a last-modified date from the feed contents
@ -112,12 +113,11 @@ class Feed {
return $config;
}
protected static function download(string $url, string $lastModified, string $etag, string $username, string $password): Client {
protected static function download(string $url, string $lastModified, string $etag, string $username, string $password): array {
try {
$reader = new Reader(self::configure());
$client = $reader->download($url, $lastModified, $etag, $username, $password);
$client->reader = $reader;
return $client;
return [$client, $reader];
} catch (PicoFeedException $e) {
throw new Feed\Exception("", ['url' => $url], $e); // @codeCoverageIgnore
} catch (\GuzzleHttp\Exception\GuzzleException $e) {
@ -125,17 +125,17 @@ class Feed {
}
}
protected function parse(): void {
protected function parse(Client $client, Reader $reader): void {
try {
$feed = $this->resource->reader->getParser(
$this->resource->getUrl(),
$this->resource->getContent(),
$this->resource->getEncoding()
$feed = $reader->getParser(
$client->getUrl(),
$client->getContent(),
$client->getEncoding()
)->execute();
} catch (PicoFeedException $e) {
throw new Feed\Exception("", ['url' => $this->resource->getUrl()], $e);
throw new Feed\Exception("", ['url' => $client->getUrl()], $e);
} catch (\GuzzleHttp\Exception\GuzzleException $e) { // @codeCoverageIgnore
throw new Feed\Exception("", ['url' => $this->resource->getUrl()], $e); // @codeCoverageIgnore
throw new Feed\Exception("", ['url' => $client->getUrl()], $e); // @codeCoverageIgnore
}
// Grab the favicon for the feed, or null if no valid icon is found
@ -150,6 +150,10 @@ class Feed {
$this->iconUrl = $this->iconData = null;
}
// Next gather all other feed-level information we want out of the feed
$this->siteUrl = $feed->siteUrl;
$this->title = $feed->title;
// PicoFeed does not provide valid ids when there is no id element. Its solution
// of hashing the url, title, and content together for the id if there is no id
// element is stupid. Many feeds are frankenstein mixtures of Atom and RSS, but
@ -158,29 +162,38 @@ class Feed {
// only be reserved for severely broken feeds.
foreach ($feed->items as $f) {
// Hashes used for comparison to check for updates and also to identify when an
// copy the basic information of an article
$i = new Item;
$i->url = $f->url;
$i->title = $f->title;
$i->content = $f->content;
$i->author = $f->author;
$i->publishedDate = $f->publishedDate;
$i->updatedDate = $f->updatedDate;
$i->enclosureType = $f->enclosureType;
$i->enclosureUrl = $f->enclosureUrl;
// add hashes used for comparison to check for updates and also to identify when an
// id doesn't exist.
$content = $f->content.$f->enclosureUrl.$f->enclosureType;
// if the item link URL and item title are both equal to the feed link URL, then the item has neither a link URL nor a title
if ($f->url === $feed->siteUrl && $f->title === $feed->siteUrl) {
$f->urlTitleHash = "";
$i->urlTitleHash = "";
} else {
$f->urlTitleHash = hash('sha256', $f->url.$f->title);
$i->urlTitleHash = hash('sha256', $f->url.$f->title);
}
// if the item link URL is equal to the feed link URL, it has no link URL; if there is additionally no content, these should not be hashed
if (!strlen($content) && $f->url === $feed->siteUrl) {
$f->urlContentHash = "";
$i->urlContentHash = "";
} else {
$f->urlContentHash = hash('sha256', $f->url.$content);
$i->urlContentHash = hash('sha256', $f->url.$content);
}
// if the item's title is the same as its link URL, it has no title; if there is additionally no content, these should not be hashed
if (!strlen($content) && $f->title === $f->url) {
$f->titleContentHash = "";
$i->titleContentHash = "";
} else {
$f->titleContentHash = hash('sha256', $f->title.$content);
$i->titleContentHash = hash('sha256', $f->title.$content);
}
$f->id = null;
// prefer an Atom ID as the item's ID
// next add an id; prefer an Atom ID as the item's ID
$id = (string) $f->xml->children('http://www.w3.org/2005/Atom')->id;
// otherwise use the RSS2 guid element
if (!strlen($id)) {
@ -192,11 +205,10 @@ class Feed {
}
// otherwise there is no ID; if there is one, hash it
if (strlen($id)) {
$f->id = hash('sha256', $id);
$i->id = hash('sha256', $id);
}
// PicoFeed also doesn't gather up categories, so we do this as well
$f->categories = [];
// first add Atom categories
foreach ($f->xml->children('http://www.w3.org/2005/Atom')->category as $c) {
// if the category has a label, use that
@ -207,27 +219,28 @@ class Feed {
}
// ... assuming it has that much
if (strlen($name)) {
$f->categories[] = $name;
$i->categories[] = $name;
}
}
// next add RSS2 categories
foreach ($f->xml->children()->category as $c) {
$name = (string) $c;
if (strlen($name)) {
$f->categories[] = $name;
$i->categories[] = $name;
}
}
// and finally try Dublin Core subjects
foreach ($f->xml->children('http://purl.org/dc/elements/1.1/')->subject as $c) {
$name = (string) $c;
if (strlen($name)) {
$f->categories[] = $name;
$i->categories[] = $name;
}
}
//sort the results
sort($f->categories);
sort($i->categories);
// add the item to the feed's list of items
$this->items[] = $i;
}
$this->data = $feed;
}
protected function deduplicateItems(array $items): array {
@ -251,7 +264,7 @@ class Feed {
($item->urlContentHash && $item->urlContentHash === $check->urlContentHash) ||
($item->titleContentHash && $item->titleContentHash === $check->titleContentHash)
) {
if (// because newsfeeds are usually order newest-first, the later item should only be used if...
if (// because newsfeeds are usually ordered newest-first, the later item should only be used if...
// the later item has an update date and the existing item does not
($item->updatedDate && !$check->updatedDate) ||
// the later item has an update date newer than the existing item's
@ -276,7 +289,7 @@ class Feed {
protected function matchToDatabase(int $feedID = null): void {
// first perform deduplication on items
$items = $this->deduplicateItems($this->data->items);
$items = $this->deduplicateItems($this->items);
// if we haven't been given a database feed ID to check against, all items are new
if (is_null($feedID)) {
$this->newItems = $items;
@ -429,7 +442,7 @@ class Feed {
protected function gatherDates(): array {
$dates = [];
foreach ($this->data->items as $item) {
foreach ($this->items as $item) {
if ($item->updatedDate) {
$dates[] = $item->updatedDate->getTimestamp();
}

24
lib/Feed/Item.php Normal file
View file

@ -0,0 +1,24 @@
<?php
/** @license MIT
* Copyright 2017 J. King, Dustin Wilson et al.
* See LICENSE and AUTHORS files for details */
declare(strict_types=1);
namespace JKingWeb\Arsse\Feed;
class Item {
public $id;
public $url;
public $title;
public $author;
public $publishedDate;
public $updatedDate;
public $urlContentHash;
public $urlTitleHash;
public $titleContentHash;
public $content;
public $scrapedContent;
public $enclosureUrl;
public $enclosureType;
public $categories = [];
}

View file

@ -12,8 +12,7 @@ const DOCROOT = BASE."tests".DIRECTORY_SEPARATOR."docroot".DIRECTORY_SEPARATOR;
ini_set("memory_limit", "-1");
ini_set("zend.assertions", "1");
ini_set("assert.exception", "true");
// FIXME: This is required because various dependencies have yet to adjust to PHP 8.1
error_reporting(\E_ALL & ~\E_DEPRECATED);
error_reporting(\E_ALL);
require_once BASE."vendor".DIRECTORY_SEPARATOR."autoload.php";
if (function_exists("xdebug_set_filter")) {

View file

@ -21,6 +21,8 @@ use JKingWeb\Arsse\Service\Daemon;
/** @covers \JKingWeb\Arsse\CLI */
class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
protected $cli;
public function setUp(): void {
parent::setUp();
$this->cli = $this->partialMock(CLI::class);

View file

@ -29,6 +29,10 @@ abstract class AbstractTest extends \JKingWeb\Arsse\Test\AbstractTest {
protected static $drv;
protected static $failureReason = "";
protected $primed = false;
protected $data;
protected $user;
protected $checkTables;
protected $series;
abstract protected function nextID(string $table): int;

View file

@ -15,6 +15,8 @@ use JKingWeb\Arsse\Misc\Date;
use JKingWeb\Arsse\Misc\ValueInfo;
trait SeriesArticle {
protected $fields;
protected function setUpSeriesArticle(): void {
$this->data = [
'arsse_users' => [

View file

@ -10,6 +10,8 @@ use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\Test\Result;
trait SeriesFeed {
protected $matches;
protected function setUpSeriesFeed(): void {
// set up the test data
$past = gmdate("Y-m-d H:i:s", strtotime("now - 1 minute"));

View file

@ -11,6 +11,8 @@ use JKingWeb\Arsse\Database;
use JKingWeb\Arsse\Context\Context;
trait SeriesLabel {
protected $checkLabels;
protected function setUpSeriesLabel(): void {
$this->data = [
'arsse_users' => [

View file

@ -10,6 +10,9 @@ use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\Database;
trait SeriesTag {
protected $checkMembers;
protected $checkTags;
protected function setUpSeriesTag(): void {
$this->data = [
'arsse_users' => [

View file

@ -17,6 +17,8 @@ class TestCreation extends \JKingWeb\Arsse\Test\AbstractTest {
protected $data;
protected $drv;
protected $ch;
protected $files;
protected $path;
public function setUp(): void {
if (!Driver::requirementsMet()) {

View file

@ -19,6 +19,8 @@ class TestCreation extends \JKingWeb\Arsse\Test\AbstractTest {
protected $data;
protected $drv;
protected $ch;
protected $files;
protected $path;
public function setUp(): void {
if (!Driver::requirementsMet()) {

View file

@ -113,26 +113,26 @@ class TestFeed extends \JKingWeb\Arsse\Test\AbstractTest {
$h0 = "0a4f0e3768c8a5e9d8d9a16545ae4ff5b097f6dac3ad49555a94a7cace68ba73"; // hash of Atom ID
$h1 = "a135beced0236b723d12f845ff20ec22d4fc3afe1130012618f027170d57cb4e"; // hash of RSS2 GUID
$h2 = "205e986f4f8b3acfa281227beadb14f5e8c32c8dae4737f888c94c0df49c56f8"; // hash of Dublin Core identifier
$this->assertSame($h0, $f->data->items[0]->id);
$this->assertSame($h1, $f->data->items[1]->id);
$this->assertSame($h2, $f->data->items[2]->id);
$this->assertSame($h0, $f->items[0]->id);
$this->assertSame($h1, $f->items[1]->id);
$this->assertSame($h2, $f->items[2]->id);
// check null hashes
$h3 = "6287ba30f534e404e68356237e809683e311285d8b9f47d046ac58784eece052"; // URL hash
$h4 = "6cbb5d2dcb11610a99eb3f633dc246690c0acf33327bf7534f95542caa8f27c4"; // title hash
$h5 = "2b7c57ffa9adde92ccd1884fa1153a5bcd3211e48d99e27be5414cb078e6891c"; // content/enclosure hash
$this->assertNotEquals("", $f->data->items[3]->urlTitleHash);
$this->assertSame($h3, $f->data->items[3]->urlContentHash);
$this->assertSame("", $f->data->items[3]->titleContentHash);
$this->assertNotEquals("", $f->data->items[4]->urlTitleHash);
$this->assertSame("", $f->data->items[4]->urlContentHash);
$this->assertSame($h4, $f->data->items[4]->titleContentHash);
$this->assertSame("", $f->data->items[5]->urlTitleHash);
$this->assertNotEquals("", $f->data->items[5]->urlContentHash);
$this->assertNotEquals("", $f->data->items[5]->titleContentHash);
$this->assertNotEquals("", $f->items[3]->urlTitleHash);
$this->assertSame($h3, $f->items[3]->urlContentHash);
$this->assertSame("", $f->items[3]->titleContentHash);
$this->assertNotEquals("", $f->items[4]->urlTitleHash);
$this->assertSame("", $f->items[4]->urlContentHash);
$this->assertSame($h4, $f->items[4]->titleContentHash);
$this->assertSame("", $f->items[5]->urlTitleHash);
$this->assertNotEquals("", $f->items[5]->urlContentHash);
$this->assertNotEquals("", $f->items[5]->titleContentHash);
// check null IDs
$this->assertSame(null, $f->data->items[3]->id);
$this->assertSame(null, $f->data->items[4]->id);
$this->assertSame(null, $f->data->items[5]->id);
$this->assertSame(null, $f->items[3]->id);
$this->assertSame(null, $f->items[4]->id);
$this->assertSame(null, $f->items[5]->id);
// check categories
$categories = [
"Aniki!",
@ -140,11 +140,11 @@ class TestFeed extends \JKingWeb\Arsse\Test\AbstractTest {
"Bodybuilders",
"Men",
];
$this->assertSame([], $f->data->items[0]->categories);
$this->assertSame([], $f->data->items[1]->categories);
$this->assertSame([], $f->data->items[3]->categories);
$this->assertSame([], $f->data->items[4]->categories);
$this->assertSame($categories, $f->data->items[5]->categories);
$this->assertSame([], $f->items[0]->categories);
$this->assertSame([], $f->items[1]->categories);
$this->assertSame([], $f->items[3]->categories);
$this->assertSame([], $f->items[4]->categories);
$this->assertSame($categories, $f->items[5]->categories);
}
public function testDiscoverAFeedSuccessfully(): void {
@ -232,7 +232,7 @@ class TestFeed extends \JKingWeb\Arsse\Test\AbstractTest {
$e = "78567a";
$f = new Feed(null, $this->base.$url."?t=$t&e=$e", Date::transform($t, "http"), $e);
$this->assertTime($t, $f->lastModified);
$this->assertSame($e, $f->resource->getETag());
$this->assertSame($e, $f->etag);
}
public function provide304ResponseURLs() {
@ -250,15 +250,15 @@ class TestFeed extends \JKingWeb\Arsse\Test\AbstractTest {
$t = time() - 2000;
$f = new Feed(null, $this->base."Caching/200Past");
$this->assertTime($t, $f->lastModified);
$this->assertNotEmpty($f->resource->getETag());
$this->assertNotEmpty($f->etag);
$t = time() - 2000;
$f = new Feed(null, $this->base."Caching/200Past", Date::transform(time(), "http"));
$this->assertTime($t, $f->lastModified);
$this->assertNotEmpty($f->resource->getETag());
$this->assertNotEmpty($f->etag);
$t = time() + 2000;
$f = new Feed(null, $this->base."Caching/200Future");
$this->assertTime($t, $f->lastModified);
$this->assertNotEmpty($f->resource->getETag());
$this->assertNotEmpty($f->etag);
// these tests have no HTTP headers and rely on article dates
$t = strtotime("2002-05-19T15:21:36Z");
$f = new Feed(null, $this->base."Caching/200PubDateOnly");

View file

@ -15,6 +15,8 @@ use JKingWeb\Arsse\Test\Database;
class TestImportExport extends \JKingWeb\Arsse\Test\AbstractTest {
protected $drv;
protected $proc;
protected $data;
protected $primed;
protected $checkTables = [
'arsse_folders' => ["id", "owner", "parent", "name"],
'arsse_feeds' => ["id", "url", "title"],

View file

@ -39,6 +39,7 @@ class TestDaemon extends \JKingWeb\Arsse\Test\AbstractTest {
'unwritable' => "", // this file will be chmodded by the test
],
];
protected $daemon;
public function setUp(): void {
parent::setUp();

View file

@ -17,6 +17,8 @@ use JKingWeb\Arsse\User\Driver;
/** @covers \JKingWeb\Arsse\User */
class TestUser extends \JKingWeb\Arsse\Test\AbstractTest {
protected $drv;
public function setUp(): void {
parent::setUp();
self::setConf();

View file

@ -615,16 +615,16 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.23",
"version": "9.2.24",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c"
"reference": "2cf940ebc6355a9d430462811b5aaa308b174bed"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c",
"reference": "9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2cf940ebc6355a9d430462811b5aaa308b174bed",
"reference": "2cf940ebc6355a9d430462811b5aaa308b174bed",
"shasum": ""
},
"require": {
@ -680,7 +680,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.23"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.24"
},
"funding": [
{
@ -688,7 +688,7 @@
"type": "github"
}
],
"time": "2022-12-28T12:41:10+00:00"
"time": "2023-01-26T08:26:55+00:00"
},
{
"name": "phpunit/php-file-iterator",