From 51fcbda978e90419e1a230bfe8823af5fe30c21a Mon Sep 17 00:00:00 2001
From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Date: Mon, 11 Aug 2025 20:35:07 -0300
Subject: [PATCH 01/17] feat: add psalm
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
---
composer.json | 8 +-
psalm.xml | 25 +
tests/psalm-baseline.xml | 2 +
vendor-bin/psalm/composer.json | 11 +
vendor-bin/psalm/composer.lock | 3229 ++++++++++++++++++++++++++++++++
5 files changed, 3272 insertions(+), 3 deletions(-)
create mode 100644 psalm.xml
create mode 100644 tests/psalm-baseline.xml
create mode 100644 vendor-bin/psalm/composer.json
create mode 100644 vendor-bin/psalm/composer.lock
diff --git a/composer.json b/composer.json
index ce8105b..e3c3ccd 100644
--- a/composer.json
+++ b/composer.json
@@ -37,15 +37,17 @@
}
},
"scripts": {
+ "test:unit": "vendor/bin/phpunit --no-coverage --colors=always --fail-on-warning --fail-on-risky --display-deprecations --display-phpunit-deprecations",
+ "test:coverage": "XDEBUG_MODE=coverage vendor/bin/phpunit",
+ "psalm": "psalm --no-cache --threads=$(nproc)",
+ "psalm:update-baseline": "psalm --threads=$(nproc) --update-baseline --set-baseline=tests/psalm-baseline.xml",
"post-install-cmd": [
"@composer bin all install --ansi",
"composer dump-autoload"
],
"post-update-cmd": [
"composer dump-autoload"
- ],
- "test:unit": "vendor/bin/phpunit --no-coverage --colors=always --fail-on-warning --fail-on-risky --display-deprecations --display-phpunit-deprecations",
- "test:coverage": "XDEBUG_MODE=coverage vendor/bin/phpunit"
+ ]
},
"extra": {
"bamarni-bin": {
diff --git a/psalm.xml b/psalm.xml
new file mode 100644
index 0000000..1dac25a
--- /dev/null
+++ b/psalm.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/psalm-baseline.xml b/tests/psalm-baseline.xml
new file mode 100644
index 0000000..69e54f6
--- /dev/null
+++ b/tests/psalm-baseline.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/vendor-bin/psalm/composer.json b/vendor-bin/psalm/composer.json
new file mode 100644
index 0000000..7a37dc6
--- /dev/null
+++ b/vendor-bin/psalm/composer.json
@@ -0,0 +1,11 @@
+{
+ "config": {
+ "platform": {
+ "php": "8.1.17"
+ },
+ "sort-packages": true
+ },
+ "require-dev": {
+ "vimeo/psalm": "^6.5.0"
+ }
+}
diff --git a/vendor-bin/psalm/composer.lock b/vendor-bin/psalm/composer.lock
new file mode 100644
index 0000000..e4b0669
--- /dev/null
+++ b/vendor-bin/psalm/composer.lock
@@ -0,0 +1,3229 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+ "This file is @generated automatically"
+ ],
+ "content-hash": "849f50992eca8ce2edc0696361e7a45b",
+ "packages": [],
+ "packages-dev": [
+ {
+ "name": "amphp/amp",
+ "version": "v3.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/amphp/amp.git",
+ "reference": "7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/amphp/amp/zipball/7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9",
+ "reference": "7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "revolt/event-loop": "^1 || ^0.2"
+ },
+ "require-dev": {
+ "amphp/php-cs-fixer-config": "^2",
+ "phpunit/phpunit": "^9",
+ "psalm/phar": "5.23.1"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions.php",
+ "src/Future/functions.php",
+ "src/Internal/functions.php"
+ ],
+ "psr-4": {
+ "Amp\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
+ },
+ {
+ "name": "Bob Weinand",
+ "email": "bobwei9@hotmail.com"
+ },
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ },
+ {
+ "name": "Daniel Lowrey",
+ "email": "rdlowrey@php.net"
+ }
+ ],
+ "description": "A non-blocking concurrency framework for PHP applications.",
+ "homepage": "https://amphp.org/amp",
+ "keywords": [
+ "async",
+ "asynchronous",
+ "awaitable",
+ "concurrency",
+ "event",
+ "event-loop",
+ "future",
+ "non-blocking",
+ "promise"
+ ],
+ "support": {
+ "issues": "https://github.com/amphp/amp/issues",
+ "source": "https://github.com/amphp/amp/tree/v3.1.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/amphp",
+ "type": "github"
+ }
+ ],
+ "time": "2025-01-26T16:07:39+00:00"
+ },
+ {
+ "name": "amphp/byte-stream",
+ "version": "v2.1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/amphp/byte-stream.git",
+ "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/amphp/byte-stream/zipball/55a6bd071aec26fa2a3e002618c20c35e3df1b46",
+ "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46",
+ "shasum": ""
+ },
+ "require": {
+ "amphp/amp": "^3",
+ "amphp/parser": "^1.1",
+ "amphp/pipeline": "^1",
+ "amphp/serialization": "^1",
+ "amphp/sync": "^2",
+ "php": ">=8.1",
+ "revolt/event-loop": "^1 || ^0.2.3"
+ },
+ "require-dev": {
+ "amphp/php-cs-fixer-config": "^2",
+ "amphp/phpunit-util": "^3",
+ "phpunit/phpunit": "^9",
+ "psalm/phar": "5.22.1"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions.php",
+ "src/Internal/functions.php"
+ ],
+ "psr-4": {
+ "Amp\\ByteStream\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
+ },
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ }
+ ],
+ "description": "A stream abstraction to make working with non-blocking I/O simple.",
+ "homepage": "https://amphp.org/byte-stream",
+ "keywords": [
+ "amp",
+ "amphp",
+ "async",
+ "io",
+ "non-blocking",
+ "stream"
+ ],
+ "support": {
+ "issues": "https://github.com/amphp/byte-stream/issues",
+ "source": "https://github.com/amphp/byte-stream/tree/v2.1.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/amphp",
+ "type": "github"
+ }
+ ],
+ "time": "2025-03-16T17:10:27+00:00"
+ },
+ {
+ "name": "amphp/cache",
+ "version": "v2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/amphp/cache.git",
+ "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/amphp/cache/zipball/46912e387e6aa94933b61ea1ead9cf7540b7797c",
+ "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c",
+ "shasum": ""
+ },
+ "require": {
+ "amphp/amp": "^3",
+ "amphp/serialization": "^1",
+ "amphp/sync": "^2",
+ "php": ">=8.1",
+ "revolt/event-loop": "^1 || ^0.2"
+ },
+ "require-dev": {
+ "amphp/php-cs-fixer-config": "^2",
+ "amphp/phpunit-util": "^3",
+ "phpunit/phpunit": "^9",
+ "psalm/phar": "^5.4"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Amp\\Cache\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ },
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
+ },
+ {
+ "name": "Daniel Lowrey",
+ "email": "rdlowrey@php.net"
+ }
+ ],
+ "description": "A fiber-aware cache API based on Amp and Revolt.",
+ "homepage": "https://amphp.org/cache",
+ "support": {
+ "issues": "https://github.com/amphp/cache/issues",
+ "source": "https://github.com/amphp/cache/tree/v2.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/amphp",
+ "type": "github"
+ }
+ ],
+ "time": "2024-04-19T03:38:06+00:00"
+ },
+ {
+ "name": "amphp/dns",
+ "version": "v2.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/amphp/dns.git",
+ "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/amphp/dns/zipball/78eb3db5fc69bf2fc0cb503c4fcba667bc223c71",
+ "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71",
+ "shasum": ""
+ },
+ "require": {
+ "amphp/amp": "^3",
+ "amphp/byte-stream": "^2",
+ "amphp/cache": "^2",
+ "amphp/parser": "^1",
+ "amphp/process": "^2",
+ "daverandom/libdns": "^2.0.2",
+ "ext-filter": "*",
+ "ext-json": "*",
+ "php": ">=8.1",
+ "revolt/event-loop": "^1 || ^0.2"
+ },
+ "require-dev": {
+ "amphp/php-cs-fixer-config": "^2",
+ "amphp/phpunit-util": "^3",
+ "phpunit/phpunit": "^9",
+ "psalm/phar": "5.20"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions.php"
+ ],
+ "psr-4": {
+ "Amp\\Dns\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Chris Wright",
+ "email": "addr@daverandom.com"
+ },
+ {
+ "name": "Daniel Lowrey",
+ "email": "rdlowrey@php.net"
+ },
+ {
+ "name": "Bob Weinand",
+ "email": "bobwei9@hotmail.com"
+ },
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ },
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
+ }
+ ],
+ "description": "Async DNS resolution for Amp.",
+ "homepage": "https://github.com/amphp/dns",
+ "keywords": [
+ "amp",
+ "amphp",
+ "async",
+ "client",
+ "dns",
+ "resolve"
+ ],
+ "support": {
+ "issues": "https://github.com/amphp/dns/issues",
+ "source": "https://github.com/amphp/dns/tree/v2.4.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/amphp",
+ "type": "github"
+ }
+ ],
+ "time": "2025-01-19T15:43:40+00:00"
+ },
+ {
+ "name": "amphp/parallel",
+ "version": "v2.3.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/amphp/parallel.git",
+ "reference": "5113111de02796a782f5d90767455e7391cca190"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/amphp/parallel/zipball/5113111de02796a782f5d90767455e7391cca190",
+ "reference": "5113111de02796a782f5d90767455e7391cca190",
+ "shasum": ""
+ },
+ "require": {
+ "amphp/amp": "^3",
+ "amphp/byte-stream": "^2",
+ "amphp/cache": "^2",
+ "amphp/parser": "^1",
+ "amphp/pipeline": "^1",
+ "amphp/process": "^2",
+ "amphp/serialization": "^1",
+ "amphp/socket": "^2",
+ "amphp/sync": "^2",
+ "php": ">=8.1",
+ "revolt/event-loop": "^1"
+ },
+ "require-dev": {
+ "amphp/php-cs-fixer-config": "^2",
+ "amphp/phpunit-util": "^3",
+ "phpunit/phpunit": "^9",
+ "psalm/phar": "^5.18"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/Context/functions.php",
+ "src/Context/Internal/functions.php",
+ "src/Ipc/functions.php",
+ "src/Worker/functions.php"
+ ],
+ "psr-4": {
+ "Amp\\Parallel\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
+ },
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ },
+ {
+ "name": "Stephen Coakley",
+ "email": "me@stephencoakley.com"
+ }
+ ],
+ "description": "Parallel processing component for Amp.",
+ "homepage": "https://github.com/amphp/parallel",
+ "keywords": [
+ "async",
+ "asynchronous",
+ "concurrent",
+ "multi-processing",
+ "multi-threading"
+ ],
+ "support": {
+ "issues": "https://github.com/amphp/parallel/issues",
+ "source": "https://github.com/amphp/parallel/tree/v2.3.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/amphp",
+ "type": "github"
+ }
+ ],
+ "time": "2024-12-21T01:56:09+00:00"
+ },
+ {
+ "name": "amphp/parser",
+ "version": "v1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/amphp/parser.git",
+ "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/amphp/parser/zipball/3cf1f8b32a0171d4b1bed93d25617637a77cded7",
+ "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.4"
+ },
+ "require-dev": {
+ "amphp/php-cs-fixer-config": "^2",
+ "phpunit/phpunit": "^9",
+ "psalm/phar": "^5.4"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Amp\\Parser\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
+ },
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ }
+ ],
+ "description": "A generator parser to make streaming parsers simple.",
+ "homepage": "https://github.com/amphp/parser",
+ "keywords": [
+ "async",
+ "non-blocking",
+ "parser",
+ "stream"
+ ],
+ "support": {
+ "issues": "https://github.com/amphp/parser/issues",
+ "source": "https://github.com/amphp/parser/tree/v1.1.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/amphp",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-21T19:16:53+00:00"
+ },
+ {
+ "name": "amphp/pipeline",
+ "version": "v1.2.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/amphp/pipeline.git",
+ "reference": "7b52598c2e9105ebcddf247fc523161581930367"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/amphp/pipeline/zipball/7b52598c2e9105ebcddf247fc523161581930367",
+ "reference": "7b52598c2e9105ebcddf247fc523161581930367",
+ "shasum": ""
+ },
+ "require": {
+ "amphp/amp": "^3",
+ "php": ">=8.1",
+ "revolt/event-loop": "^1"
+ },
+ "require-dev": {
+ "amphp/php-cs-fixer-config": "^2",
+ "amphp/phpunit-util": "^3",
+ "phpunit/phpunit": "^9",
+ "psalm/phar": "^5.18"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Amp\\Pipeline\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
+ },
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ }
+ ],
+ "description": "Asynchronous iterators and operators.",
+ "homepage": "https://amphp.org/pipeline",
+ "keywords": [
+ "amp",
+ "amphp",
+ "async",
+ "io",
+ "iterator",
+ "non-blocking"
+ ],
+ "support": {
+ "issues": "https://github.com/amphp/pipeline/issues",
+ "source": "https://github.com/amphp/pipeline/tree/v1.2.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/amphp",
+ "type": "github"
+ }
+ ],
+ "time": "2025-03-16T16:33:53+00:00"
+ },
+ {
+ "name": "amphp/process",
+ "version": "v2.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/amphp/process.git",
+ "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/amphp/process/zipball/52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d",
+ "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d",
+ "shasum": ""
+ },
+ "require": {
+ "amphp/amp": "^3",
+ "amphp/byte-stream": "^2",
+ "amphp/sync": "^2",
+ "php": ">=8.1",
+ "revolt/event-loop": "^1 || ^0.2"
+ },
+ "require-dev": {
+ "amphp/php-cs-fixer-config": "^2",
+ "amphp/phpunit-util": "^3",
+ "phpunit/phpunit": "^9",
+ "psalm/phar": "^5.4"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions.php"
+ ],
+ "psr-4": {
+ "Amp\\Process\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Bob Weinand",
+ "email": "bobwei9@hotmail.com"
+ },
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
+ },
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ }
+ ],
+ "description": "A fiber-aware process manager based on Amp and Revolt.",
+ "homepage": "https://amphp.org/process",
+ "support": {
+ "issues": "https://github.com/amphp/process/issues",
+ "source": "https://github.com/amphp/process/tree/v2.0.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/amphp",
+ "type": "github"
+ }
+ ],
+ "time": "2024-04-19T03:13:44+00:00"
+ },
+ {
+ "name": "amphp/serialization",
+ "version": "v1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/amphp/serialization.git",
+ "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/amphp/serialization/zipball/693e77b2fb0b266c3c7d622317f881de44ae94a1",
+ "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "require-dev": {
+ "amphp/php-cs-fixer-config": "dev-master",
+ "phpunit/phpunit": "^9 || ^8 || ^7"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions.php"
+ ],
+ "psr-4": {
+ "Amp\\Serialization\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
+ },
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ }
+ ],
+ "description": "Serialization tools for IPC and data storage in PHP.",
+ "homepage": "https://github.com/amphp/serialization",
+ "keywords": [
+ "async",
+ "asynchronous",
+ "serialization",
+ "serialize"
+ ],
+ "support": {
+ "issues": "https://github.com/amphp/serialization/issues",
+ "source": "https://github.com/amphp/serialization/tree/master"
+ },
+ "time": "2020-03-25T21:39:07+00:00"
+ },
+ {
+ "name": "amphp/socket",
+ "version": "v2.3.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/amphp/socket.git",
+ "reference": "58e0422221825b79681b72c50c47a930be7bf1e1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/amphp/socket/zipball/58e0422221825b79681b72c50c47a930be7bf1e1",
+ "reference": "58e0422221825b79681b72c50c47a930be7bf1e1",
+ "shasum": ""
+ },
+ "require": {
+ "amphp/amp": "^3",
+ "amphp/byte-stream": "^2",
+ "amphp/dns": "^2",
+ "ext-openssl": "*",
+ "kelunik/certificate": "^1.1",
+ "league/uri": "^6.5 | ^7",
+ "league/uri-interfaces": "^2.3 | ^7",
+ "php": ">=8.1",
+ "revolt/event-loop": "^1 || ^0.2"
+ },
+ "require-dev": {
+ "amphp/php-cs-fixer-config": "^2",
+ "amphp/phpunit-util": "^3",
+ "amphp/process": "^2",
+ "phpunit/phpunit": "^9",
+ "psalm/phar": "5.20"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions.php",
+ "src/Internal/functions.php",
+ "src/SocketAddress/functions.php"
+ ],
+ "psr-4": {
+ "Amp\\Socket\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Daniel Lowrey",
+ "email": "rdlowrey@gmail.com"
+ },
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
+ },
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ }
+ ],
+ "description": "Non-blocking socket connection / server implementations based on Amp and Revolt.",
+ "homepage": "https://github.com/amphp/socket",
+ "keywords": [
+ "amp",
+ "async",
+ "encryption",
+ "non-blocking",
+ "sockets",
+ "tcp",
+ "tls"
+ ],
+ "support": {
+ "issues": "https://github.com/amphp/socket/issues",
+ "source": "https://github.com/amphp/socket/tree/v2.3.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/amphp",
+ "type": "github"
+ }
+ ],
+ "time": "2024-04-21T14:33:03+00:00"
+ },
+ {
+ "name": "amphp/sync",
+ "version": "v2.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/amphp/sync.git",
+ "reference": "217097b785130d77cfcc58ff583cf26cd1770bf1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/amphp/sync/zipball/217097b785130d77cfcc58ff583cf26cd1770bf1",
+ "reference": "217097b785130d77cfcc58ff583cf26cd1770bf1",
+ "shasum": ""
+ },
+ "require": {
+ "amphp/amp": "^3",
+ "amphp/pipeline": "^1",
+ "amphp/serialization": "^1",
+ "php": ">=8.1",
+ "revolt/event-loop": "^1 || ^0.2"
+ },
+ "require-dev": {
+ "amphp/php-cs-fixer-config": "^2",
+ "amphp/phpunit-util": "^3",
+ "phpunit/phpunit": "^9",
+ "psalm/phar": "5.23"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions.php"
+ ],
+ "psr-4": {
+ "Amp\\Sync\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
+ },
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ },
+ {
+ "name": "Stephen Coakley",
+ "email": "me@stephencoakley.com"
+ }
+ ],
+ "description": "Non-blocking synchronization primitives for PHP based on Amp and Revolt.",
+ "homepage": "https://github.com/amphp/sync",
+ "keywords": [
+ "async",
+ "asynchronous",
+ "mutex",
+ "semaphore",
+ "synchronization"
+ ],
+ "support": {
+ "issues": "https://github.com/amphp/sync/issues",
+ "source": "https://github.com/amphp/sync/tree/v2.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/amphp",
+ "type": "github"
+ }
+ ],
+ "time": "2024-08-03T19:31:26+00:00"
+ },
+ {
+ "name": "composer/pcre",
+ "version": "3.3.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/pcre.git",
+ "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
+ "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.4 || ^8.0"
+ },
+ "conflict": {
+ "phpstan/phpstan": "<1.11.10"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.12 || ^2",
+ "phpstan/phpstan-strict-rules": "^1 || ^2",
+ "phpunit/phpunit": "^8 || ^9"
+ },
+ "type": "library",
+ "extra": {
+ "phpstan": {
+ "includes": [
+ "extension.neon"
+ ]
+ },
+ "branch-alias": {
+ "dev-main": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Pcre\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "PCRE wrapping library that offers type-safe preg_* replacements.",
+ "keywords": [
+ "PCRE",
+ "preg",
+ "regex",
+ "regular expression"
+ ],
+ "support": {
+ "issues": "https://github.com/composer/pcre/issues",
+ "source": "https://github.com/composer/pcre/tree/3.3.2"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-11-12T16:29:46+00:00"
+ },
+ {
+ "name": "composer/semver",
+ "version": "3.4.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/semver.git",
+ "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12",
+ "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.2 || ^7.0 || ^8.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.11",
+ "symfony/phpunit-bridge": "^3 || ^7"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Semver\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nils Adermann",
+ "email": "naderman@naderman.de",
+ "homepage": "http://www.naderman.de"
+ },
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ },
+ {
+ "name": "Rob Bast",
+ "email": "rob.bast@gmail.com",
+ "homepage": "http://robbast.nl"
+ }
+ ],
+ "description": "Semver library that offers utilities, version constraint parsing and validation.",
+ "keywords": [
+ "semantic",
+ "semver",
+ "validation",
+ "versioning"
+ ],
+ "support": {
+ "irc": "ircs://irc.libera.chat:6697/composer",
+ "issues": "https://github.com/composer/semver/issues",
+ "source": "https://github.com/composer/semver/tree/3.4.3"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-19T14:15:21+00:00"
+ },
+ {
+ "name": "composer/xdebug-handler",
+ "version": "3.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/xdebug-handler.git",
+ "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef",
+ "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef",
+ "shasum": ""
+ },
+ "require": {
+ "composer/pcre": "^1 || ^2 || ^3",
+ "php": "^7.2.5 || ^8.0",
+ "psr/log": "^1 || ^2 || ^3"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.0",
+ "phpstan/phpstan-strict-rules": "^1.1",
+ "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Composer\\XdebugHandler\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "John Stevenson",
+ "email": "john-stevenson@blueyonder.co.uk"
+ }
+ ],
+ "description": "Restarts a process without Xdebug.",
+ "keywords": [
+ "Xdebug",
+ "performance"
+ ],
+ "support": {
+ "irc": "ircs://irc.libera.chat:6697/composer",
+ "issues": "https://github.com/composer/xdebug-handler/issues",
+ "source": "https://github.com/composer/xdebug-handler/tree/3.0.5"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-05-06T16:37:16+00:00"
+ },
+ {
+ "name": "daverandom/libdns",
+ "version": "v2.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/DaveRandom/LibDNS.git",
+ "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/DaveRandom/LibDNS/zipball/b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a",
+ "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a",
+ "shasum": ""
+ },
+ "require": {
+ "ext-ctype": "*",
+ "php": ">=7.1"
+ },
+ "suggest": {
+ "ext-intl": "Required for IDN support"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions.php"
+ ],
+ "psr-4": {
+ "LibDNS\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "DNS protocol implementation written in pure PHP",
+ "keywords": [
+ "dns"
+ ],
+ "support": {
+ "issues": "https://github.com/DaveRandom/LibDNS/issues",
+ "source": "https://github.com/DaveRandom/LibDNS/tree/v2.1.0"
+ },
+ "time": "2024-04-12T12:12:48+00:00"
+ },
+ {
+ "name": "dnoegel/php-xdg-base-dir",
+ "version": "v0.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/dnoegel/php-xdg-base-dir.git",
+ "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd",
+ "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~7.0|~6.0|~5.0|~4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "XdgBaseDir\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "implementation of xdg base directory specification for php",
+ "support": {
+ "issues": "https://github.com/dnoegel/php-xdg-base-dir/issues",
+ "source": "https://github.com/dnoegel/php-xdg-base-dir/tree/v0.1.1"
+ },
+ "time": "2019-12-04T15:06:13+00:00"
+ },
+ {
+ "name": "doctrine/deprecations",
+ "version": "1.1.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/deprecations.git",
+ "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
+ "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "conflict": {
+ "phpunit/phpunit": "<=7.5 || >=13"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^9 || ^12 || ^13",
+ "phpstan/phpstan": "1.4.10 || 2.1.11",
+ "phpstan/phpstan-phpunit": "^1.0 || ^2",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12",
+ "psr/log": "^1 || ^2 || ^3"
+ },
+ "suggest": {
+ "psr/log": "Allows logging deprecations via PSR-3 logger implementation"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Deprecations\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
+ "homepage": "https://www.doctrine-project.org/",
+ "support": {
+ "issues": "https://github.com/doctrine/deprecations/issues",
+ "source": "https://github.com/doctrine/deprecations/tree/1.1.5"
+ },
+ "time": "2025-04-07T20:06:18+00:00"
+ },
+ {
+ "name": "felixfbecker/advanced-json-rpc",
+ "version": "v3.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git",
+ "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/b5f37dbff9a8ad360ca341f3240dc1c168b45447",
+ "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447",
+ "shasum": ""
+ },
+ "require": {
+ "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0",
+ "php": "^7.1 || ^8.0",
+ "phpdocumentor/reflection-docblock": "^4.3.4 || ^5.0.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.0 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "AdvancedJsonRpc\\": "lib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "ISC"
+ ],
+ "authors": [
+ {
+ "name": "Felix Becker",
+ "email": "felix.b@outlook.com"
+ }
+ ],
+ "description": "A more advanced JSONRPC implementation",
+ "support": {
+ "issues": "https://github.com/felixfbecker/php-advanced-json-rpc/issues",
+ "source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/v3.2.1"
+ },
+ "time": "2021-06-11T22:34:44+00:00"
+ },
+ {
+ "name": "felixfbecker/language-server-protocol",
+ "version": "v1.5.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/felixfbecker/php-language-server-protocol.git",
+ "reference": "a9e113dbc7d849e35b8776da39edaf4313b7b6c9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/a9e113dbc7d849e35b8776da39edaf4313b7b6c9",
+ "reference": "a9e113dbc7d849e35b8776da39edaf4313b7b6c9",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "*",
+ "squizlabs/php_codesniffer": "^3.1",
+ "vimeo/psalm": "^4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "LanguageServerProtocol\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "ISC"
+ ],
+ "authors": [
+ {
+ "name": "Felix Becker",
+ "email": "felix.b@outlook.com"
+ }
+ ],
+ "description": "PHP classes for the Language Server Protocol",
+ "keywords": [
+ "language",
+ "microsoft",
+ "php",
+ "server"
+ ],
+ "support": {
+ "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues",
+ "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.3"
+ },
+ "time": "2024-04-30T00:40:11+00:00"
+ },
+ {
+ "name": "fidry/cpu-core-counter",
+ "version": "1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/theofidry/cpu-core-counter.git",
+ "reference": "8520451a140d3f46ac33042715115e290cf5785f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f",
+ "reference": "8520451a140d3f46ac33042715115e290cf5785f",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "require-dev": {
+ "fidry/makefile": "^0.2.0",
+ "fidry/php-cs-fixer-config": "^1.1.2",
+ "phpstan/extension-installer": "^1.2.0",
+ "phpstan/phpstan": "^1.9.2",
+ "phpstan/phpstan-deprecation-rules": "^1.0.0",
+ "phpstan/phpstan-phpunit": "^1.2.2",
+ "phpstan/phpstan-strict-rules": "^1.4.4",
+ "phpunit/phpunit": "^8.5.31 || ^9.5.26",
+ "webmozarts/strict-phpunit": "^7.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Fidry\\CpuCoreCounter\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Théo FIDRY",
+ "email": "theo.fidry@gmail.com"
+ }
+ ],
+ "description": "Tiny utility to get the number of CPU cores.",
+ "keywords": [
+ "CPU",
+ "core"
+ ],
+ "support": {
+ "issues": "https://github.com/theofidry/cpu-core-counter/issues",
+ "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theofidry",
+ "type": "github"
+ }
+ ],
+ "time": "2024-08-06T10:04:20+00:00"
+ },
+ {
+ "name": "kelunik/certificate",
+ "version": "v1.1.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/kelunik/certificate.git",
+ "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/kelunik/certificate/zipball/7e00d498c264d5eb4f78c69f41c8bd6719c0199e",
+ "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e",
+ "shasum": ""
+ },
+ "require": {
+ "ext-openssl": "*",
+ "php": ">=7.0"
+ },
+ "require-dev": {
+ "amphp/php-cs-fixer-config": "^2",
+ "phpunit/phpunit": "^6 | 7 | ^8 | ^9"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Kelunik\\Certificate\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ }
+ ],
+ "description": "Access certificate details and transform between different formats.",
+ "keywords": [
+ "DER",
+ "certificate",
+ "certificates",
+ "openssl",
+ "pem",
+ "x509"
+ ],
+ "support": {
+ "issues": "https://github.com/kelunik/certificate/issues",
+ "source": "https://github.com/kelunik/certificate/tree/v1.1.3"
+ },
+ "time": "2023-02-03T21:26:53+00:00"
+ },
+ {
+ "name": "league/uri",
+ "version": "7.5.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/thephpleague/uri.git",
+ "reference": "81fb5145d2644324614cc532b28efd0215bda430"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430",
+ "reference": "81fb5145d2644324614cc532b28efd0215bda430",
+ "shasum": ""
+ },
+ "require": {
+ "league/uri-interfaces": "^7.5",
+ "php": "^8.1"
+ },
+ "conflict": {
+ "league/uri-schemes": "^1.0"
+ },
+ "suggest": {
+ "ext-bcmath": "to improve IPV4 host parsing",
+ "ext-fileinfo": "to create Data URI from file contennts",
+ "ext-gmp": "to improve IPV4 host parsing",
+ "ext-intl": "to handle IDN host with the best performance",
+ "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain",
+ "league/uri-components": "Needed to easily manipulate URI objects components",
+ "php-64bit": "to improve IPV4 host parsing",
+ "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "7.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "League\\Uri\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ignace Nyamagana Butera",
+ "email": "nyamsprod@gmail.com",
+ "homepage": "https://nyamsprod.com"
+ }
+ ],
+ "description": "URI manipulation library",
+ "homepage": "https://uri.thephpleague.com",
+ "keywords": [
+ "data-uri",
+ "file-uri",
+ "ftp",
+ "hostname",
+ "http",
+ "https",
+ "middleware",
+ "parse_str",
+ "parse_url",
+ "psr-7",
+ "query-string",
+ "querystring",
+ "rfc3986",
+ "rfc3987",
+ "rfc6570",
+ "uri",
+ "uri-template",
+ "url",
+ "ws"
+ ],
+ "support": {
+ "docs": "https://uri.thephpleague.com",
+ "forum": "https://thephpleague.slack.com",
+ "issues": "https://github.com/thephpleague/uri-src/issues",
+ "source": "https://github.com/thephpleague/uri/tree/7.5.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sponsors/nyamsprod",
+ "type": "github"
+ }
+ ],
+ "time": "2024-12-08T08:40:02+00:00"
+ },
+ {
+ "name": "league/uri-interfaces",
+ "version": "7.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/thephpleague/uri-interfaces.git",
+ "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742",
+ "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742",
+ "shasum": ""
+ },
+ "require": {
+ "ext-filter": "*",
+ "php": "^8.1",
+ "psr/http-factory": "^1",
+ "psr/http-message": "^1.1 || ^2.0"
+ },
+ "suggest": {
+ "ext-bcmath": "to improve IPV4 host parsing",
+ "ext-gmp": "to improve IPV4 host parsing",
+ "ext-intl": "to handle IDN host with the best performance",
+ "php-64bit": "to improve IPV4 host parsing",
+ "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "7.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "League\\Uri\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ignace Nyamagana Butera",
+ "email": "nyamsprod@gmail.com",
+ "homepage": "https://nyamsprod.com"
+ }
+ ],
+ "description": "Common interfaces and classes for URI representation and interaction",
+ "homepage": "https://uri.thephpleague.com",
+ "keywords": [
+ "data-uri",
+ "file-uri",
+ "ftp",
+ "hostname",
+ "http",
+ "https",
+ "parse_str",
+ "parse_url",
+ "psr-7",
+ "query-string",
+ "querystring",
+ "rfc3986",
+ "rfc3987",
+ "rfc6570",
+ "uri",
+ "url",
+ "ws"
+ ],
+ "support": {
+ "docs": "https://uri.thephpleague.com",
+ "forum": "https://thephpleague.slack.com",
+ "issues": "https://github.com/thephpleague/uri-src/issues",
+ "source": "https://github.com/thephpleague/uri-interfaces/tree/7.5.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sponsors/nyamsprod",
+ "type": "github"
+ }
+ ],
+ "time": "2024-12-08T08:18:47+00:00"
+ },
+ {
+ "name": "netresearch/jsonmapper",
+ "version": "v4.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/cweiske/jsonmapper.git",
+ "reference": "8e76efb98ee8b6afc54687045e1b8dba55ac76e5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8e76efb98ee8b6afc54687045e1b8dba55ac76e5",
+ "reference": "8e76efb98ee8b6afc54687045e1b8dba55ac76e5",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "ext-pcre": "*",
+ "ext-reflection": "*",
+ "ext-spl": "*",
+ "php": ">=7.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0",
+ "squizlabs/php_codesniffer": "~3.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "JsonMapper": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "OSL-3.0"
+ ],
+ "authors": [
+ {
+ "name": "Christian Weiske",
+ "email": "cweiske@cweiske.de",
+ "homepage": "http://github.com/cweiske/jsonmapper/",
+ "role": "Developer"
+ }
+ ],
+ "description": "Map nested JSON structures onto PHP classes",
+ "support": {
+ "email": "cweiske@cweiske.de",
+ "issues": "https://github.com/cweiske/jsonmapper/issues",
+ "source": "https://github.com/cweiske/jsonmapper/tree/v4.5.0"
+ },
+ "time": "2024-09-08T10:13:13+00:00"
+ },
+ {
+ "name": "nikic/php-parser",
+ "version": "v5.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nikic/PHP-Parser.git",
+ "reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/221b0d0fdf1369c71047ad1d18bb5880017bbc56",
+ "reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56",
+ "shasum": ""
+ },
+ "require": {
+ "ext-ctype": "*",
+ "ext-json": "*",
+ "ext-tokenizer": "*",
+ "php": ">=7.4"
+ },
+ "require-dev": {
+ "ircmaxell/php-yacc": "^0.0.7",
+ "phpunit/phpunit": "^9.0"
+ },
+ "bin": [
+ "bin/php-parse"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PhpParser\\": "lib/PhpParser"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Nikita Popov"
+ }
+ ],
+ "description": "A PHP parser written in PHP",
+ "keywords": [
+ "parser",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/nikic/PHP-Parser/issues",
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.0"
+ },
+ "time": "2025-07-27T20:03:57+00:00"
+ },
+ {
+ "name": "phpdocumentor/reflection-common",
+ "version": "2.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
+ "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
+ "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-2.x": "2.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jaap van Otterdijk",
+ "email": "opensource@ijaap.nl"
+ }
+ ],
+ "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
+ "homepage": "http://www.phpdoc.org",
+ "keywords": [
+ "FQSEN",
+ "phpDocumentor",
+ "phpdoc",
+ "reflection",
+ "static analysis"
+ ],
+ "support": {
+ "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
+ "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x"
+ },
+ "time": "2020-06-27T09:03:43+00:00"
+ },
+ {
+ "name": "phpdocumentor/reflection-docblock",
+ "version": "5.6.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
+ "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/92dde6a5919e34835c506ac8c523ef095a95ed62",
+ "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/deprecations": "^1.1",
+ "ext-filter": "*",
+ "php": "^7.4 || ^8.0",
+ "phpdocumentor/reflection-common": "^2.2",
+ "phpdocumentor/type-resolver": "^1.7",
+ "phpstan/phpdoc-parser": "^1.7|^2.0",
+ "webmozart/assert": "^1.9.1"
+ },
+ "require-dev": {
+ "mockery/mockery": "~1.3.5 || ~1.6.0",
+ "phpstan/extension-installer": "^1.1",
+ "phpstan/phpstan": "^1.8",
+ "phpstan/phpstan-mockery": "^1.1",
+ "phpstan/phpstan-webmozart-assert": "^1.2",
+ "phpunit/phpunit": "^9.5",
+ "psalm/phar": "^5.26"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "me@mikevanriel.com"
+ },
+ {
+ "name": "Jaap van Otterdijk",
+ "email": "opensource@ijaap.nl"
+ }
+ ],
+ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
+ "support": {
+ "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
+ "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.2"
+ },
+ "time": "2025-04-13T19:20:35+00:00"
+ },
+ {
+ "name": "phpdocumentor/type-resolver",
+ "version": "1.10.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/TypeResolver.git",
+ "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a",
+ "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/deprecations": "^1.0",
+ "php": "^7.3 || ^8.0",
+ "phpdocumentor/reflection-common": "^2.0",
+ "phpstan/phpdoc-parser": "^1.18|^2.0"
+ },
+ "require-dev": {
+ "ext-tokenizer": "*",
+ "phpbench/phpbench": "^1.2",
+ "phpstan/extension-installer": "^1.1",
+ "phpstan/phpstan": "^1.8",
+ "phpstan/phpstan-phpunit": "^1.1",
+ "phpunit/phpunit": "^9.5",
+ "rector/rector": "^0.13.9",
+ "vimeo/psalm": "^4.25"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-1.x": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "me@mikevanriel.com"
+ }
+ ],
+ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
+ "support": {
+ "issues": "https://github.com/phpDocumentor/TypeResolver/issues",
+ "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0"
+ },
+ "time": "2024-11-09T15:12:26+00:00"
+ },
+ {
+ "name": "phpstan/phpdoc-parser",
+ "version": "2.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpstan/phpdoc-parser.git",
+ "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/b9e61a61e39e02dd90944e9115241c7f7e76bfd8",
+ "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.4 || ^8.0"
+ },
+ "require-dev": {
+ "doctrine/annotations": "^2.0",
+ "nikic/php-parser": "^5.3.0",
+ "php-parallel-lint/php-parallel-lint": "^1.2",
+ "phpstan/extension-installer": "^1.0",
+ "phpstan/phpstan": "^2.0",
+ "phpstan/phpstan-phpunit": "^2.0",
+ "phpstan/phpstan-strict-rules": "^2.0",
+ "phpunit/phpunit": "^9.6",
+ "symfony/process": "^5.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "PHPStan\\PhpDocParser\\": [
+ "src/"
+ ]
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "PHPDoc parser with support for nullable, intersection and generic types",
+ "support": {
+ "issues": "https://github.com/phpstan/phpdoc-parser/issues",
+ "source": "https://github.com/phpstan/phpdoc-parser/tree/2.2.0"
+ },
+ "time": "2025-07-13T07:04:09+00:00"
+ },
+ {
+ "name": "psr/container",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/container.git",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Container\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common Container Interface (PHP FIG PSR-11)",
+ "homepage": "https://github.com/php-fig/container",
+ "keywords": [
+ "PSR-11",
+ "container",
+ "container-interface",
+ "container-interop",
+ "psr"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/container/issues",
+ "source": "https://github.com/php-fig/container/tree/2.0.2"
+ },
+ "time": "2021-11-05T16:47:00+00:00"
+ },
+ {
+ "name": "psr/http-factory",
+ "version": "1.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-factory.git",
+ "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
+ "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1",
+ "psr/http-message": "^1.0 || ^2.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
+ "keywords": [
+ "factory",
+ "http",
+ "message",
+ "psr",
+ "psr-17",
+ "psr-7",
+ "request",
+ "response"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/http-factory"
+ },
+ "time": "2024-04-15T12:06:14+00:00"
+ },
+ {
+ "name": "psr/http-message",
+ "version": "2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-message.git",
+ "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
+ "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for HTTP messages",
+ "homepage": "https://github.com/php-fig/http-message",
+ "keywords": [
+ "http",
+ "http-message",
+ "psr",
+ "psr-7",
+ "request",
+ "response"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/http-message/tree/2.0"
+ },
+ "time": "2023-04-04T09:54:51+00:00"
+ },
+ {
+ "name": "psr/log",
+ "version": "3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Log\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for logging libraries",
+ "homepage": "https://github.com/php-fig/log",
+ "keywords": [
+ "log",
+ "psr",
+ "psr-3"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/log/tree/3.0.2"
+ },
+ "time": "2024-09-11T13:17:53+00:00"
+ },
+ {
+ "name": "revolt/event-loop",
+ "version": "v1.0.7",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/revoltphp/event-loop.git",
+ "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/09bf1bf7f7f574453efe43044b06fafe12216eb3",
+ "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "ext-json": "*",
+ "jetbrains/phpstorm-stubs": "^2019.3",
+ "phpunit/phpunit": "^9",
+ "psalm/phar": "^5.15"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Revolt\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "ceesjank@gmail.com"
+ },
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ },
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ }
+ ],
+ "description": "Rock-solid event loop for concurrent PHP applications.",
+ "keywords": [
+ "async",
+ "asynchronous",
+ "concurrency",
+ "event",
+ "event-loop",
+ "non-blocking",
+ "scheduler"
+ ],
+ "support": {
+ "issues": "https://github.com/revoltphp/event-loop/issues",
+ "source": "https://github.com/revoltphp/event-loop/tree/v1.0.7"
+ },
+ "time": "2025-01-25T19:27:39+00:00"
+ },
+ {
+ "name": "sebastian/diff",
+ "version": "5.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/diff.git",
+ "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e",
+ "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0",
+ "symfony/process": "^6.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Kore Nordmann",
+ "email": "mail@kore-nordmann.de"
+ }
+ ],
+ "description": "Diff implementation",
+ "homepage": "https://github.com/sebastianbergmann/diff",
+ "keywords": [
+ "diff",
+ "udiff",
+ "unidiff",
+ "unified diff"
+ ],
+ "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"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-02T07:15:17+00:00"
+ },
+ {
+ "name": "spatie/array-to-xml",
+ "version": "3.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/spatie/array-to-xml.git",
+ "reference": "7dcfc67d60b0272926dabad1ec01f6b8a5fb5e67"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/7dcfc67d60b0272926dabad1ec01f6b8a5fb5e67",
+ "reference": "7dcfc67d60b0272926dabad1ec01f6b8a5fb5e67",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "php": "^8.0"
+ },
+ "require-dev": {
+ "mockery/mockery": "^1.2",
+ "pestphp/pest": "^1.21",
+ "spatie/pest-plugin-snapshots": "^1.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Spatie\\ArrayToXml\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Freek Van der Herten",
+ "email": "freek@spatie.be",
+ "homepage": "https://freek.dev",
+ "role": "Developer"
+ }
+ ],
+ "description": "Convert an array to xml",
+ "homepage": "https://github.com/spatie/array-to-xml",
+ "keywords": [
+ "array",
+ "convert",
+ "xml"
+ ],
+ "support": {
+ "source": "https://github.com/spatie/array-to-xml/tree/3.4.0"
+ },
+ "funding": [
+ {
+ "url": "https://spatie.be/open-source/support-us",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/spatie",
+ "type": "github"
+ }
+ ],
+ "time": "2024-12-16T12:45:15+00:00"
+ },
+ {
+ "name": "symfony/console",
+ "version": "v6.4.24",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/console.git",
+ "reference": "59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/console/zipball/59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350",
+ "reference": "59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/polyfill-mbstring": "~1.0",
+ "symfony/service-contracts": "^2.5|^3",
+ "symfony/string": "^5.4|^6.0|^7.0"
+ },
+ "conflict": {
+ "symfony/dependency-injection": "<5.4",
+ "symfony/dotenv": "<5.4",
+ "symfony/event-dispatcher": "<5.4",
+ "symfony/lock": "<5.4",
+ "symfony/process": "<5.4"
+ },
+ "provide": {
+ "psr/log-implementation": "1.0|2.0|3.0"
+ },
+ "require-dev": {
+ "psr/log": "^1|^2|^3",
+ "symfony/config": "^5.4|^6.0|^7.0",
+ "symfony/dependency-injection": "^5.4|^6.0|^7.0",
+ "symfony/event-dispatcher": "^5.4|^6.0|^7.0",
+ "symfony/http-foundation": "^6.4|^7.0",
+ "symfony/http-kernel": "^6.4|^7.0",
+ "symfony/lock": "^5.4|^6.0|^7.0",
+ "symfony/messenger": "^5.4|^6.0|^7.0",
+ "symfony/process": "^5.4|^6.0|^7.0",
+ "symfony/stopwatch": "^5.4|^6.0|^7.0",
+ "symfony/var-dumper": "^5.4|^6.0|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Console\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Eases the creation of beautiful and testable command line interfaces",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "cli",
+ "command-line",
+ "console",
+ "terminal"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/console/tree/v6.4.24"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-07-30T10:38:54+00:00"
+ },
+ {
+ "name": "symfony/deprecation-contracts",
+ "version": "v3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/deprecation-contracts.git",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "function.php"
+ ]
+ },
+ "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": "A generic function and convention to trigger deprecation notices",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-25T14:21:43+00:00"
+ },
+ {
+ "name": "symfony/filesystem",
+ "version": "v6.4.24",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/filesystem.git",
+ "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/75ae2edb7cdcc0c53766c30b0a2512b8df574bd8",
+ "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-mbstring": "~1.8"
+ },
+ "require-dev": {
+ "symfony/process": "^5.4|^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Filesystem\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides basic utilities for the filesystem",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/filesystem/tree/v6.4.24"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-07-10T08:14:14+00:00"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.32.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-ctype": "*"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for ctype functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-09T11:45:10+00:00"
+ },
+ {
+ "name": "symfony/polyfill-intl-grapheme",
+ "version": "v1.32.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
+ "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
+ "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
+ }
+ },
+ "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 for intl's grapheme_* functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "grapheme",
+ "intl",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-09T11:45:10+00:00"
+ },
+ {
+ "name": "symfony/polyfill-intl-normalizer",
+ "version": "v1.32.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
+ "reference": "3833d7255cc303546435cb650316bff708a1c75c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
+ "reference": "3833d7255cc303546435cb650316bff708a1c75c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "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 for intl's Normalizer class and related functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "intl",
+ "normalizer",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-09T11:45:10+00:00"
+ },
+ {
+ "name": "symfony/polyfill-mbstring",
+ "version": "v1.32.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "shasum": ""
+ },
+ "require": {
+ "ext-iconv": "*",
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-mbstring": "*"
+ },
+ "suggest": {
+ "ext-mbstring": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Mbstring\\": ""
+ }
+ },
+ "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 for the Mbstring extension",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "mbstring",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-12-23T08:48:59+00:00"
+ },
+ {
+ "name": "symfony/service-contracts",
+ "version": "v3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/service-contracts.git",
+ "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
+ "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "psr/container": "^1.1|^2.0",
+ "symfony/deprecation-contracts": "^2.5|^3"
+ },
+ "conflict": {
+ "ext-psr": "<1.1|>=2"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\Service\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Test/"
+ ]
+ },
+ "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": "Generic abstractions related to writing services",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/service-contracts/tree/v3.6.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": "2025-04-25T09:37:31+00:00"
+ },
+ {
+ "name": "symfony/string",
+ "version": "v6.4.24",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/string.git",
+ "reference": "f0ce0bd36a3accb4a225435be077b4b4875587f4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/string/zipball/f0ce0bd36a3accb4a225435be077b4b4875587f4",
+ "reference": "f0ce0bd36a3accb4a225435be077b4b4875587f4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-intl-grapheme": "~1.0",
+ "symfony/polyfill-intl-normalizer": "~1.0",
+ "symfony/polyfill-mbstring": "~1.0"
+ },
+ "conflict": {
+ "symfony/translation-contracts": "<2.5"
+ },
+ "require-dev": {
+ "symfony/error-handler": "^5.4|^6.0|^7.0",
+ "symfony/http-client": "^5.4|^6.0|^7.0",
+ "symfony/intl": "^6.2|^7.0",
+ "symfony/translation-contracts": "^2.5|^3.0",
+ "symfony/var-exporter": "^5.4|^6.0|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "Resources/functions.php"
+ ],
+ "psr-4": {
+ "Symfony\\Component\\String\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "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": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "grapheme",
+ "i18n",
+ "string",
+ "unicode",
+ "utf-8",
+ "utf8"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/string/tree/v6.4.24"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-07-10T08:14:14+00:00"
+ },
+ {
+ "name": "vimeo/psalm",
+ "version": "6.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/vimeo/psalm.git",
+ "reference": "38fc8444edf0cebc9205296ee6e30e906ade783b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/vimeo/psalm/zipball/38fc8444edf0cebc9205296ee6e30e906ade783b",
+ "reference": "38fc8444edf0cebc9205296ee6e30e906ade783b",
+ "shasum": ""
+ },
+ "require": {
+ "amphp/amp": "^3",
+ "amphp/byte-stream": "^2",
+ "amphp/parallel": "^2.3",
+ "composer-runtime-api": "^2",
+ "composer/semver": "^1.4 || ^2.0 || ^3.0",
+ "composer/xdebug-handler": "^2.0 || ^3.0",
+ "dnoegel/php-xdg-base-dir": "^0.1.1",
+ "ext-ctype": "*",
+ "ext-dom": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-simplexml": "*",
+ "ext-tokenizer": "*",
+ "felixfbecker/advanced-json-rpc": "^3.1",
+ "felixfbecker/language-server-protocol": "^1.5.3",
+ "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1 || ^1.0.0",
+ "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0",
+ "nikic/php-parser": "^5.0.0",
+ "php": "~8.1.17 || ~8.2.4 || ~8.3.0 || ~8.4.0",
+ "sebastian/diff": "^4.0 || ^5.0 || ^6.0 || ^7.0",
+ "spatie/array-to-xml": "^2.17.0 || ^3.0",
+ "symfony/console": "^6.0 || ^7.0",
+ "symfony/filesystem": "^6.0 || ^7.0"
+ },
+ "provide": {
+ "psalm/psalm": "self.version"
+ },
+ "require-dev": {
+ "amphp/phpunit-util": "^3",
+ "bamarni/composer-bin-plugin": "^1.4",
+ "brianium/paratest": "^6.9",
+ "dg/bypass-finals": "^1.5",
+ "ext-curl": "*",
+ "mockery/mockery": "^1.5",
+ "nunomaduro/mock-final-classes": "^1.1",
+ "php-parallel-lint/php-parallel-lint": "^1.2",
+ "phpstan/phpdoc-parser": "^1.6",
+ "phpunit/phpunit": "^9.6",
+ "psalm/plugin-mockery": "^1.1",
+ "psalm/plugin-phpunit": "^0.19",
+ "slevomat/coding-standard": "^8.4",
+ "squizlabs/php_codesniffer": "^3.6",
+ "symfony/process": "^6.0 || ^7.0"
+ },
+ "suggest": {
+ "ext-curl": "In order to send data to shepherd",
+ "ext-igbinary": "^2.0.5 is required, used to serialize caching data"
+ },
+ "bin": [
+ "psalm",
+ "psalm-language-server",
+ "psalm-plugin",
+ "psalm-refactor",
+ "psalm-review",
+ "psalter"
+ ],
+ "type": "project",
+ "extra": {
+ "branch-alias": {
+ "dev-1.x": "1.x-dev",
+ "dev-2.x": "2.x-dev",
+ "dev-3.x": "3.x-dev",
+ "dev-4.x": "4.x-dev",
+ "dev-5.x": "5.x-dev",
+ "dev-6.x": "6.x-dev",
+ "dev-master": "7.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psalm\\": "src/Psalm/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Matthew Brown"
+ },
+ {
+ "name": "Daniil Gentili",
+ "email": "daniil@daniil.it"
+ }
+ ],
+ "description": "A static analysis tool for finding errors in PHP applications",
+ "keywords": [
+ "code",
+ "inspection",
+ "php",
+ "static analysis"
+ ],
+ "support": {
+ "docs": "https://psalm.dev/docs",
+ "issues": "https://github.com/vimeo/psalm/issues",
+ "source": "https://github.com/vimeo/psalm"
+ },
+ "time": "2025-02-07T20:42:25+00:00"
+ },
+ {
+ "name": "webmozart/assert",
+ "version": "1.11.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/webmozarts/assert.git",
+ "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991",
+ "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991",
+ "shasum": ""
+ },
+ "require": {
+ "ext-ctype": "*",
+ "php": "^7.2 || ^8.0"
+ },
+ "conflict": {
+ "phpstan/phpstan": "<0.12.20",
+ "vimeo/psalm": "<4.6.1 || 4.6.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^8.5.13"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.10-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Webmozart\\Assert\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "Assertions to validate method input/output with nice error messages.",
+ "keywords": [
+ "assert",
+ "check",
+ "validate"
+ ],
+ "support": {
+ "issues": "https://github.com/webmozarts/assert/issues",
+ "source": "https://github.com/webmozarts/assert/tree/1.11.0"
+ },
+ "time": "2022-06-03T18:03:27+00:00"
+ }
+ ],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": {},
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": {},
+ "platform-dev": {},
+ "platform-overrides": {
+ "php": "8.1.17"
+ },
+ "plugin-api-version": "2.6.0"
+}
From 49b671fbf9c8b71639ec059e43c6f2d07eaf913c Mon Sep 17 00:00:00 2001
From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Date: Mon, 11 Aug 2025 20:37:57 -0300
Subject: [PATCH 02/17] fix: apply fixes repported by psalm
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
---
src/JSignFileService.php | 13 ++++---
src/JSignPDF.php | 4 +-
src/Runtime/JavaRuntimeService.php | 3 +-
src/Sign/JSignParam.php | 60 +++++++++++++++---------------
src/Sign/JSignService.php | 25 +++++++------
5 files changed, 56 insertions(+), 49 deletions(-)
diff --git a/src/JSignFileService.php b/src/JSignFileService.php
index f2304c5..607a2ef 100644
--- a/src/JSignFileService.php
+++ b/src/JSignFileService.php
@@ -8,31 +8,34 @@
class JSignFileService
{
- public static function instance()
+ public static function instance(): self
{
return new self();
}
- public function contentFile($path, $isInBase64 = false)
+ public function contentFile($path, $isInBase64 = false): string
{
$content = file_get_contents($path);
+ if ($content === false) {
+ return '';
+ }
return $isInBase64 ? base64_encode($content) : $content;
}
- public function storeFile($path, $name, $content)
+ public function storeFile($path, $name, $content): string
{
$filename = $path . $name;
file_put_contents($filename, $content);
return $filename;
}
- public function deleteFile(string $path)
+ public function deleteFile(string $path): void
{
if (is_file($path))
unlink($path);
}
- public function deleteTempFiles(string $pathTemp, string $name)
+ public function deleteTempFiles(string $pathTemp, string $name): void
{
$pathPfxFile = "$pathTemp$name.pfx";
$pathPdfFile = "$pathTemp$name.pdf";
diff --git a/src/JSignPDF.php b/src/JSignPDF.php
index 11b12ae..63a1552 100644
--- a/src/JSignPDF.php
+++ b/src/JSignPDF.php
@@ -19,7 +19,7 @@ public function __construct(?JSignParam $param = null)
$this->param = $param;
}
- public static function instance(?JSignParam $param = null)
+ public static function instance(?JSignParam $param = null): self
{
return new self($param);
}
@@ -34,7 +34,7 @@ public function getVersion()
return $this->service->getVersion($this->param);
}
- public function setParam(JSignParam $param)
+ public function setParam(JSignParam $param): void
{
$this->param = $param;
}
diff --git a/src/Runtime/JavaRuntimeService.php b/src/Runtime/JavaRuntimeService.php
index 15c6283..aa2a6a2 100644
--- a/src/Runtime/JavaRuntimeService.php
+++ b/src/Runtime/JavaRuntimeService.php
@@ -91,7 +91,7 @@ private function downloadAndExtract(string $url, string $baseDir): void
chmod($baseDir . '/bin/java', 0700);
}
- private function findRootDir(PharData $phar, $rootDir) {
+ private function findRootDir(PharData $phar, string $rootDir): ?string {
$files = new \RecursiveIteratorIterator($phar, \RecursiveIteratorIterator::CHILD_FIRST);
$rootDir = realpath($rootDir);
@@ -104,6 +104,7 @@ private function findRootDir(PharData $phar, $rootDir) {
return trim($parts[0], '/');
}
}
+ return null;
}
private function chunkDownload(string $url, string $destination): void
diff --git a/src/Sign/JSignParam.php b/src/Sign/JSignParam.php
index 692dc6d..915b8ce 100644
--- a/src/Sign/JSignParam.php
+++ b/src/Sign/JSignParam.php
@@ -7,16 +7,16 @@
*/
class JSignParam
{
- private $pdf;
- private $certificate;
- private $password;
- private $pathPdfSigned;
- private $JSignParameters = "-a -kst PKCS12";
- private $isUseJavaInstalled = false;
+ private ?string $pdf = null;
+ private ?string $certificate = null;
+ private ?string $password = null;
+ private string $pathPdfSigned = '';
+ private string $JSignParameters = "-a -kst PKCS12";
+ private bool $isUseJavaInstalled = false;
private string $javaPath = '';
- private $tempPath;
- private $tempName;
- private $isOutputTypeBase64 = false;
+ private ?string $tempPath = null;
+ private string $tempName = '';
+ private bool $isOutputTypeBase64 = false;
private string $jSignPdfJarPath;
private string $javaDownloadUrl = 'https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.8%2B9/OpenJDK21U-jre_x64_linux_hotspot_21.0.8_9.tar.gz';
private string $jSignPdfDownloadUrl = 'https://github.com/intoolswetrust/jsignpdf/releases/download/JSignPdf_2_3_0/jsignpdf-2.3.0.zip';
@@ -29,50 +29,50 @@ public function __construct()
$this->jSignPdfJarPath = $this->tempPath . 'jsignpdf' . DIRECTORY_SEPARATOR . 'JSignPdf.jar';
}
- public static function instance()
+ public static function instance(): self
{
return new self();
}
- public function getPdf()
+ public function getPdf(): ?string
{
return $this->pdf;
}
- public function setPdf($pdf)
+ public function setPdf(?string $pdf): self
{
$this->pdf = $pdf;
return $this;
}
- public function getCertificate()
+ public function getCertificate(): ?string
{
return $this->certificate;
}
- public function setCertificate($certificate)
+ public function setCertificate(?string $certificate): self
{
$this->certificate = $certificate;
return $this;
}
- public function getPassword()
+ public function getPassword(): ?string
{
return $this->password;
}
- public function setPassword($password)
+ public function setPassword(?string $password): self
{
$this->password = $password;
return $this;
}
- public function getPathPdfSigned()
+ public function getPathPdfSigned(): string
{
return $this->pathPdfSigned != null ? $this->pathPdfSigned : $this->getTempPath();
}
- public function setPathPdfSigned($pathPdfSigned)
+ public function setPathPdfSigned($pathPdfSigned): self
{
$this->pathPdfSigned = $pathPdfSigned;
return $this;
@@ -83,24 +83,24 @@ public function getJSignParameters(): string
return $this->JSignParameters;
}
- public function setJSignParameters(string $JSignParameters)
+ public function setJSignParameters(string $JSignParameters): self
{
$this->JSignParameters = $JSignParameters;
return $this;
}
- public function getTempPath()
+ public function getTempPath(): ?string
{
return $this->tempPath;
}
- public function setTempPath($tempPath)
+ public function setTempPath(?string $tempPath): self
{
$this->tempPath = $tempPath;
return $this;
}
- public function getTempName($extension = null)
+ public function getTempName(string|null $extension = null): string
{
return $this->tempName.$extension;
}
@@ -110,13 +110,13 @@ public function isUseJavaInstalled(): bool
return $this->isUseJavaInstalled;
}
- public function setIsUseJavaInstalled(bool $isUseJavaInstalled)
+ public function setIsUseJavaInstalled(bool $isUseJavaInstalled): self
{
$this->isUseJavaInstalled = $isUseJavaInstalled;
return $this;
}
- public function setJavaPath($javaPath): self {
+ public function setJavaPath(string $javaPath): self {
$this->javaPath = $javaPath;
return $this;
}
@@ -125,13 +125,13 @@ public function getJavaPath(): string {
return $this->javaPath;
}
- public function setjSignPdfJarPath($jSignPdfJarPath)
+ public function setjSignPdfJarPath($jSignPdfJarPath): self
{
$this->jSignPdfJarPath = $jSignPdfJarPath;
return $this;
}
- public function getjSignPdfJarPath()
+ public function getjSignPdfJarPath(): string
{
return $this->jSignPdfJarPath;
}
@@ -141,23 +141,23 @@ public function isOutputTypeBase64(): bool
return $this->isOutputTypeBase64;
}
- public function setIsOutputTypeBase64(bool $isOutputTypeBase64)
+ public function setIsOutputTypeBase64(bool $isOutputTypeBase64): self
{
$this->isOutputTypeBase64 = $isOutputTypeBase64;
return $this;
}
- public function getTempPdfPath()
+ public function getTempPdfPath(): string
{
return $this->getTempPath() . $this->getTempName('.pdf');
}
- public function getTempPdfSignedPath()
+ public function getTempPdfSignedPath(): string
{
return $this->getPathPdfSigned() . $this->getTempName('_signed.pdf');
}
- public function getTempCertificatePath()
+ public function getTempCertificatePath(): string
{
return $this->getTempPath() . $this->getTempName('.pfx');
}
diff --git a/src/Sign/JSignService.php b/src/Sign/JSignService.php
index 27eaeae..1d6109e 100644
--- a/src/Sign/JSignService.php
+++ b/src/Sign/JSignService.php
@@ -58,7 +58,7 @@ public function sign(JSignParam $params)
* unicode chars. As workaround, I changed the password certificate in
* memory.
*/
- private function repackCertificateIfPasswordIsUnicode(JSignParam $params, $cert, $pkey)
+ private function repackCertificateIfPasswordIsUnicode(JSignParam $params, $cert, $pkey): void
{
if (!mb_detect_encoding($params->getPassword(), 'ASCII', true)) {
$password = md5(microtime());
@@ -68,7 +68,7 @@ private function repackCertificateIfPasswordIsUnicode(JSignParam $params, $cert,
}
}
- public function getVersion(JSignParam $params)
+ public function getVersion(JSignParam $params): string
{
$java = $this->javaCommand($params);
$jSignPdf = $this->getjSignPdfJarPath($params);
@@ -83,7 +83,7 @@ public function getVersion(JSignParam $params)
return explode('version ', $lastRow)[1];
}
- private function validation(JSignParam $params)
+ private function validation(JSignParam $params): void
{
$this->throwIf(empty($params->getTempPath()) || !is_writable($params->getTempPath()), 'Temp Path is invalid or has not permission to writable.');
$this->throwIf(empty($params->getPdf()), 'PDF is Empty or Invalid.');
@@ -98,7 +98,10 @@ private function validation(JSignParam $params)
}
}
- private function storeTempFiles(JSignParam $params)
+ /**
+ * @psalm-return list{mixed, mixed}
+ */
+ private function storeTempFiles(JSignParam $params): array
{
$pdf = $this->fileService->storeFile(
$params->getTempPath(),
@@ -115,7 +118,7 @@ private function storeTempFiles(JSignParam $params)
return [$pdf, $certificate];
}
- private function commandSign(JSignParam $params)
+ private function commandSign(JSignParam $params): string
{
list ($pdf, $certificate) = $this->storeTempFiles($params);
$java = $this->javaCommand($params);
@@ -137,15 +140,15 @@ private function getjSignPdfJarPath(JSignParam $params): string
return $JsignPdfRuntimeService->getPath($params);
}
- private function throwIf($condition, $message)
+ private function throwIf(bool $condition, string $message): void
{
if ($condition)
throw new Exception($message);
}
- private function isPasswordCertificateValid(JSignParam $params)
+ private function isPasswordCertificateValid(JSignParam $params): bool
{
- return $this->pkcs12Read($params);
+ return $this->pkcs12Read($params) ? true : false;
}
/**
@@ -161,7 +164,7 @@ private function isPasswordCertificateValid(JSignParam $params)
* https://github.com/php/php-src/issues/12128
* https://www.php.net/manual/en/function.openssl-pkcs12-read.php#128992
*/
- private function pkcs12Read(JSignParam $params)
+ private function pkcs12Read(JSignParam $params): array
{
$certificate = $params->getCertificate();
$password = $params->getPassword();
@@ -198,7 +201,7 @@ private function pkcs12Read(JSignParam $params)
return [];
}
- private function exportToPkcs12(\OpenSSLCertificate|string $certificate, \OpenSSLAsymmetricKey|\OpenSSLCertificate|string $privateKey, string $password)
+ private function exportToPkcs12(\OpenSSLCertificate|string $certificate, \OpenSSLAsymmetricKey|\OpenSSLCertificate|string $privateKey, string $password): string
{
$certContent = null;
openssl_pkcs12_export(
@@ -210,7 +213,7 @@ private function exportToPkcs12(\OpenSSLCertificate|string $certificate, \OpenSS
return $certContent;
}
- private function isExpiredCertificate(JSignParam $params)
+ private function isExpiredCertificate(JSignParam $params): bool
{
$certInfo = $this->pkcs12Read($params);
$certificate = openssl_x509_parse($certInfo['cert']);
From ba2eec918f509419d87e0f7016904f9310326f4e Mon Sep 17 00:00:00 2001
From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Date: Mon, 11 Aug 2025 20:43:31 -0300
Subject: [PATCH 03/17] fix: prevent error when use date_create
The function date_create could return false.
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
---
src/Sign/JSignService.php | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/Sign/JSignService.php b/src/Sign/JSignService.php
index 1d6109e..e7d47e9 100644
--- a/src/Sign/JSignService.php
+++ b/src/Sign/JSignService.php
@@ -2,6 +2,7 @@
namespace Jeidison\JSignPDF\Sign;
+use DateTime;
use Exception;
use Jeidison\JSignPDF\JSignFileService;
use Jeidison\JSignPDF\Runtime\JavaRuntimeService;
@@ -217,7 +218,11 @@ private function isExpiredCertificate(JSignParam $params): bool
{
$certInfo = $this->pkcs12Read($params);
$certificate = openssl_x509_parse($certInfo['cert']);
- $dateCert = date_create()->setTimestamp($certificate['validTo_time_t']);
- return $dateCert <= date_create();
+ if (!is_array($certificate)) {
+ throw new Exception('Invalid certificate');
+ }
+ $currentDate = new DateTime();
+ $dateCert = (clone $currentDate)->setTimestamp($certificate['validTo_time_t']);
+ return $dateCert <= $currentDate;
}
}
From 422adbd69a78855defc4b606fff8e7f2fb0c24cb Mon Sep 17 00:00:00 2001
From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Date: Mon, 11 Aug 2025 20:45:19 -0300
Subject: [PATCH 04/17] fix: cast password always to string
The password value could be nullable
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
---
src/Sign/JSignService.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Sign/JSignService.php b/src/Sign/JSignService.php
index e7d47e9..c0fdabc 100644
--- a/src/Sign/JSignService.php
+++ b/src/Sign/JSignService.php
@@ -168,7 +168,7 @@ private function isPasswordCertificateValid(JSignParam $params): bool
private function pkcs12Read(JSignParam $params): array
{
$certificate = $params->getCertificate();
- $password = $params->getPassword();
+ $password = (string) $params->getPassword();
if (openssl_pkcs12_read($certificate, $certInfo, $password)) {
$this->repackCertificateIfPasswordIsUnicode($params, $certInfo['cert'], $certInfo['pkey']);
return $certInfo;
From db83c522c4f1e96ecaf394cc3728471646b7c9c8 Mon Sep 17 00:00:00 2001
From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Date: Mon, 11 Aug 2025 20:46:50 -0300
Subject: [PATCH 05/17] fix: the function file_get_contents could return false
prevent to go ahead if got error to read the temp file
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
---
src/Sign/JSignService.php | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/Sign/JSignService.php b/src/Sign/JSignService.php
index c0fdabc..2e9c747 100644
--- a/src/Sign/JSignService.php
+++ b/src/Sign/JSignService.php
@@ -190,6 +190,9 @@ private function pkcs12Read(JSignParam $params): array
REPACK_COMMAND
);
$certificateRepacked = file_get_contents($tempEncriptedRepacked);
+ if ($certificateRepacked === false) {
+ return [];
+ }
$params->setCertificate($certificateRepacked);
unlink($tempPassword);
unlink($tempEncriptedOriginal);
From fcca74f79c9d543dd71b98ba34f27d595e8f77cc Mon Sep 17 00:00:00 2001
From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Date: Mon, 11 Aug 2025 20:48:41 -0300
Subject: [PATCH 06/17] fix: the function tempnam could return false
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
---
src/Sign/JSignService.php | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/Sign/JSignService.php b/src/Sign/JSignService.php
index 2e9c747..10f028f 100644
--- a/src/Sign/JSignService.php
+++ b/src/Sign/JSignService.php
@@ -182,6 +182,9 @@ private function pkcs12Read(JSignParam $params): array
$tempEncriptedOriginal = tempnam(sys_get_temp_dir(), 'original');
$tempEncriptedRepacked = tempnam(sys_get_temp_dir(), 'repacked');
$tempDecrypted = tempnam(sys_get_temp_dir(), 'decripted');
+ if ($tempDecrypted === false || $tempPassword === false || $tempEncriptedOriginal === false || $tempEncriptedRepacked === false) {
+ return [];
+ }
file_put_contents($tempPassword, $password);
file_put_contents($tempEncriptedOriginal, $certificate);
shell_exec(<<
Date: Mon, 11 Aug 2025 20:56:32 -0300
Subject: [PATCH 07/17] chore: safe shell_exec
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
---
src/Sign/JSignService.php | 25 ++++++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/src/Sign/JSignService.php b/src/Sign/JSignService.php
index 10f028f..c9775de 100644
--- a/src/Sign/JSignService.php
+++ b/src/Sign/JSignService.php
@@ -187,11 +187,7 @@ private function pkcs12Read(JSignParam $params): array
}
file_put_contents($tempPassword, $password);
file_put_contents($tempEncriptedOriginal, $certificate);
- shell_exec(<<safeShellExec($tempPassword, $tempEncriptedOriginal, $tempDecrypted, $tempEncriptedRepacked);
$certificateRepacked = file_get_contents($tempEncriptedRepacked);
if ($certificateRepacked === false) {
return [];
@@ -208,6 +204,25 @@ private function pkcs12Read(JSignParam $params): array
return [];
}
+ private function safeShellExec(
+ string $tempPassword,
+ string $tempEncriptedOriginal,
+ string $tempDecrypted,
+ string $tempEncriptedRepacked,
+ ): void
+ {
+ $tempPassword = escapeshellarg($tempPassword);
+ $tempEncriptedOriginal = escapeshellarg($tempEncriptedOriginal);
+ $tempDecrypted = escapeshellarg($tempDecrypted);
+ $tempEncriptedRepacked = escapeshellarg($tempEncriptedRepacked);
+
+ shell_exec(<<
Date: Mon, 11 Aug 2025 20:57:33 -0300
Subject: [PATCH 08/17] fix: cast certificate content
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
---
src/Sign/JSignService.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Sign/JSignService.php b/src/Sign/JSignService.php
index c9775de..c2577d6 100644
--- a/src/Sign/JSignService.php
+++ b/src/Sign/JSignService.php
@@ -167,7 +167,7 @@ private function isPasswordCertificateValid(JSignParam $params): bool
*/
private function pkcs12Read(JSignParam $params): array
{
- $certificate = $params->getCertificate();
+ $certificate = (string) $params->getCertificate();
$password = (string) $params->getPassword();
if (openssl_pkcs12_read($certificate, $certInfo, $password)) {
$this->repackCertificateIfPasswordIsUnicode($params, $certInfo['cert'], $certInfo['pkey']);
From 1cc6df487a7600ea11aba9d030fcc84564dc17fd Mon Sep 17 00:00:00 2001
From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Date: Mon, 11 Aug 2025 21:01:44 -0300
Subject: [PATCH 09/17] chore: make the debug more easy
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
---
src/Sign/JSignService.php | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/Sign/JSignService.php b/src/Sign/JSignService.php
index c2577d6..b467c5c 100644
--- a/src/Sign/JSignService.php
+++ b/src/Sign/JSignService.php
@@ -175,7 +175,8 @@ private function pkcs12Read(JSignParam $params): array
}
$msg = openssl_error_string();
if ($msg === 'error:0308010C:digital envelope routines::unsupported') {
- if (!shell_exec('openssl version')) {
+ $opensslVersion = shell_exec('openssl version');
+ if (empty($opensslVersion)) {
return [];
}
$tempPassword = tempnam(sys_get_temp_dir(), 'pfx');
From 17ee7f4df37368696658757a9a175f77aaff0732 Mon Sep 17 00:00:00 2001
From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Date: Mon, 11 Aug 2025 21:05:52 -0300
Subject: [PATCH 10/17] chore: force default to empty
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
---
src/Sign/JSignParam.php | 16 ++++++++--------
src/Sign/JSignService.php | 4 ++--
tests/JSignPDFTest.php | 14 +++++++-------
3 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/src/Sign/JSignParam.php b/src/Sign/JSignParam.php
index 915b8ce..9db2799 100644
--- a/src/Sign/JSignParam.php
+++ b/src/Sign/JSignParam.php
@@ -7,14 +7,14 @@
*/
class JSignParam
{
- private ?string $pdf = null;
- private ?string $certificate = null;
- private ?string $password = null;
+ private string $pdf = '';
+ private string $certificate = '';
+ private string $password = '';
private string $pathPdfSigned = '';
private string $JSignParameters = "-a -kst PKCS12";
private bool $isUseJavaInstalled = false;
private string $javaPath = '';
- private ?string $tempPath = null;
+ private string $tempPath = '';
private string $tempName = '';
private bool $isOutputTypeBase64 = false;
private string $jSignPdfJarPath;
@@ -34,7 +34,7 @@ public static function instance(): self
return new self();
}
- public function getPdf(): ?string
+ public function getPdf(): string
{
return $this->pdf;
}
@@ -45,7 +45,7 @@ public function setPdf(?string $pdf): self
return $this;
}
- public function getCertificate(): ?string
+ public function getCertificate(): string
{
return $this->certificate;
}
@@ -56,7 +56,7 @@ public function setCertificate(?string $certificate): self
return $this;
}
- public function getPassword(): ?string
+ public function getPassword(): string
{
return $this->password;
}
@@ -89,7 +89,7 @@ public function setJSignParameters(string $JSignParameters): self
return $this;
}
- public function getTempPath(): ?string
+ public function getTempPath(): string
{
return $this->tempPath;
}
diff --git a/src/Sign/JSignService.php b/src/Sign/JSignService.php
index b467c5c..74e8f6e 100644
--- a/src/Sign/JSignService.php
+++ b/src/Sign/JSignService.php
@@ -167,8 +167,8 @@ private function isPasswordCertificateValid(JSignParam $params): bool
*/
private function pkcs12Read(JSignParam $params): array
{
- $certificate = (string) $params->getCertificate();
- $password = (string) $params->getPassword();
+ $certificate = $params->getCertificate();
+ $password = $params->getPassword();
if (openssl_pkcs12_read($certificate, $certInfo, $password)) {
$this->repackCertificateIfPasswordIsUnicode($params, $certInfo['cert'], $certInfo['pkey']);
return $certInfo;
diff --git a/tests/JSignPDFTest.php b/tests/JSignPDFTest.php
index 7ed04fc..3b185e5 100644
--- a/tests/JSignPDFTest.php
+++ b/tests/JSignPDFTest.php
@@ -162,31 +162,31 @@ public function testWithWhenResponseIsBase64()
$this->assertEquals(base64_encode('signed file content'), $signedContent);
}
- public function testSignWhenCertificateIsNull()
+ public function testSignWhenCertificateIsEmpty()
{
$this->expectExceptionMessage('Certificate is Empty or Invalid.');
- $params = JSignParamBuilder::instance()->withDefault()->setCertificate(null);
+ $params = JSignParamBuilder::instance()->withDefault()->setCertificate('');
$this->service->sign($params);
}
- public function testSignWhenPdfIsNull()
+ public function testSignWhenPdfIsEmpty()
{
$this->expectExceptionMessage('PDF is Empty or Invalid.');
- $params = JSignParamBuilder::instance()->withDefault()->setPdf(null);
+ $params = JSignParamBuilder::instance()->withDefault()->setPdf('');
$this->service->sign($params);
}
- public function testSignWhenPasswordIsNull()
+ public function testSignWhenPasswordIsEmpty()
{
$this->expectExceptionMessage('Certificate Password is Empty.');
- $params = JSignParamBuilder::instance()->withDefault()->setPassword(null);
+ $params = JSignParamBuilder::instance()->withDefault()->setPassword('');
$this->service->sign($params);
}
public function testSignWhenTempPathIsInvalid()
{
$this->expectExceptionMessage('Temp Path is invalid or has not permission to writable.');
- $params = JSignParamBuilder::instance()->withDefault()->setTempPath(null);
+ $params = JSignParamBuilder::instance()->withDefault()->setTempPath('');
$this->service->sign($params);
}
From f69b183485d6e3d9f09f143d291a1db67ae53986 Mon Sep 17 00:00:00 2001
From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Date: Mon, 11 Aug 2025 21:09:54 -0300
Subject: [PATCH 11/17] fix: add type
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
---
src/Sign/JSignService.php | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/Sign/JSignService.php b/src/Sign/JSignService.php
index 74e8f6e..0d181cf 100644
--- a/src/Sign/JSignService.php
+++ b/src/Sign/JSignService.php
@@ -59,7 +59,11 @@ public function sign(JSignParam $params)
* unicode chars. As workaround, I changed the password certificate in
* memory.
*/
- private function repackCertificateIfPasswordIsUnicode(JSignParam $params, $cert, $pkey): void
+ private function repackCertificateIfPasswordIsUnicode(
+ JSignParam $params,
+ \OpenSSLCertificate|string $cert,
+ \OpenSSLAsymmetricKey|\OpenSSLCertificate|string $pkey,
+ ): void
{
if (!mb_detect_encoding($params->getPassword(), 'ASCII', true)) {
$password = md5(microtime());
From 3d5d3527dcc2ffde38bcbe31b885a17eb0190936 Mon Sep 17 00:00:00 2001
From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Date: Mon, 11 Aug 2025 21:12:40 -0300
Subject: [PATCH 12/17] chore: prevent error when failure to apply json_encode
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
---
src/Sign/JSignService.php | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/Sign/JSignService.php b/src/Sign/JSignService.php
index 0d181cf..6e1836e 100644
--- a/src/Sign/JSignService.php
+++ b/src/Sign/JSignService.php
@@ -30,6 +30,9 @@ public function sign(JSignParam $params)
exec($commandSign, $output);
$out = json_encode($output);
+ if ($out === false) {
+ throw new Exception('Error to sign PDF.');
+ }
$messageSuccess = "Finished: Signature succesfully created.";
$isSigned = strpos($out, $messageSuccess) !== false;
From 64a596ef15b8bb1a54feba579585665a1ec0c590 Mon Sep 17 00:00:00 2001
From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Date: Mon, 11 Aug 2025 21:14:20 -0300
Subject: [PATCH 13/17] fix: add return typing
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
---
src/Sign/JSignService.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Sign/JSignService.php b/src/Sign/JSignService.php
index 6e1836e..111e568 100644
--- a/src/Sign/JSignService.php
+++ b/src/Sign/JSignService.php
@@ -21,7 +21,7 @@ public function __construct()
$this->fileService = JSignFileService::instance();
}
- public function sign(JSignParam $params)
+ public function sign(JSignParam $params): string
{
try {
$this->validation($params);
From b009a30a84e9499a24836a6018980a086cf447cb Mon Sep 17 00:00:00 2001
From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Date: Mon, 11 Aug 2025 21:16:32 -0300
Subject: [PATCH 14/17] fix: remove nullable
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
---
src/Sign/JSignParam.php | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/Sign/JSignParam.php b/src/Sign/JSignParam.php
index 9db2799..7568e4b 100644
--- a/src/Sign/JSignParam.php
+++ b/src/Sign/JSignParam.php
@@ -17,7 +17,7 @@ class JSignParam
private string $tempPath = '';
private string $tempName = '';
private bool $isOutputTypeBase64 = false;
- private string $jSignPdfJarPath;
+ private string $jSignPdfJarPath = '';
private string $javaDownloadUrl = 'https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.8%2B9/OpenJDK21U-jre_x64_linux_hotspot_21.0.8_9.tar.gz';
private string $jSignPdfDownloadUrl = 'https://github.com/intoolswetrust/jsignpdf/releases/download/JSignPdf_2_3_0/jsignpdf-2.3.0.zip';
@@ -39,7 +39,7 @@ public function getPdf(): string
return $this->pdf;
}
- public function setPdf(?string $pdf): self
+ public function setPdf(string $pdf): self
{
$this->pdf = $pdf;
return $this;
@@ -50,7 +50,7 @@ public function getCertificate(): string
return $this->certificate;
}
- public function setCertificate(?string $certificate): self
+ public function setCertificate(string $certificate): self
{
$this->certificate = $certificate;
return $this;
@@ -61,7 +61,7 @@ public function getPassword(): string
return $this->password;
}
- public function setPassword(?string $password): self
+ public function setPassword(string $password): self
{
$this->password = $password;
return $this;
@@ -72,7 +72,7 @@ public function getPathPdfSigned(): string
return $this->pathPdfSigned != null ? $this->pathPdfSigned : $this->getTempPath();
}
- public function setPathPdfSigned($pathPdfSigned): self
+ public function setPathPdfSigned(string $pathPdfSigned): self
{
$this->pathPdfSigned = $pathPdfSigned;
return $this;
@@ -94,7 +94,7 @@ public function getTempPath(): string
return $this->tempPath;
}
- public function setTempPath(?string $tempPath): self
+ public function setTempPath(string $tempPath): self
{
$this->tempPath = $tempPath;
return $this;
@@ -125,7 +125,7 @@ public function getJavaPath(): string {
return $this->javaPath;
}
- public function setjSignPdfJarPath($jSignPdfJarPath): self
+ public function setjSignPdfJarPath(string $jSignPdfJarPath): self
{
$this->jSignPdfJarPath = $jSignPdfJarPath;
return $this;
From 0b5105339f766023f19fca80510186665bdb384d Mon Sep 17 00:00:00 2001
From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Date: Mon, 11 Aug 2025 21:17:34 -0300
Subject: [PATCH 15/17] fix: force typing
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
---
src/JSignFileService.php | 4 ++--
src/JSignPDF.php | 15 +++++++++++----
src/Runtime/JSignPdfRuntimeService.php | 10 +++++++++-
src/Runtime/JavaRuntimeService.php | 21 ++++++++++++++++++---
src/Sign/JSignParam.php | 2 +-
src/Sign/JSignService.php | 18 +++++++++++-------
6 files changed, 52 insertions(+), 18 deletions(-)
diff --git a/src/JSignFileService.php b/src/JSignFileService.php
index 607a2ef..1abab86 100644
--- a/src/JSignFileService.php
+++ b/src/JSignFileService.php
@@ -13,7 +13,7 @@ public static function instance(): self
return new self();
}
- public function contentFile($path, $isInBase64 = false): string
+ public function contentFile(string $path, bool $isInBase64 = false): string
{
$content = file_get_contents($path);
if ($content === false) {
@@ -22,7 +22,7 @@ public function contentFile($path, $isInBase64 = false): string
return $isInBase64 ? base64_encode($content) : $content;
}
- public function storeFile($path, $name, $content): string
+ public function storeFile(string $path, string $name, string $content): string
{
$filename = $path . $name;
file_put_contents($filename, $content);
diff --git a/src/JSignPDF.php b/src/JSignPDF.php
index 63a1552..1768b5e 100644
--- a/src/JSignPDF.php
+++ b/src/JSignPDF.php
@@ -2,6 +2,7 @@
namespace Jeidison\JSignPDF;
+use Exception;
use Jeidison\JSignPDF\Sign\JSignParam;
use Jeidison\JSignPDF\Sign\JSignService;
@@ -10,8 +11,8 @@
*/
class JSignPDF
{
- private $service;
- private $param;
+ private JSignService $service;
+ private ?JSignParam $param = null;
public function __construct(?JSignParam $param = null)
{
@@ -24,13 +25,19 @@ public static function instance(?JSignParam $param = null): self
return new self($param);
}
- public function sign()
+ public function sign(): string
{
+ if (!$this->param instanceof JSignParam) {
+ throw new Exception('Invalid JSignParam instance');
+ }
return $this->service->sign($this->param);
}
- public function getVersion()
+ public function getVersion(): string
{
+ if (!$this->param instanceof JSignParam) {
+ throw new Exception('Invalid JSignParam instance');
+ }
return $this->service->getVersion($this->param);
}
diff --git a/src/Runtime/JSignPdfRuntimeService.php b/src/Runtime/JSignPdfRuntimeService.php
index c746e53..17c5958 100644
--- a/src/Runtime/JSignPdfRuntimeService.php
+++ b/src/Runtime/JSignPdfRuntimeService.php
@@ -25,6 +25,9 @@ public function getPath(JSignParam $params): string
if ($downloadUrl && $jsignPdfPath) {
$baseDir = preg_replace('/\/JSignPdf.jar$/', '', $jsignPdfPath);
+ if (!is_string($baseDir)) {
+ throw new InvalidArgumentException('Invalid JsignParamPath');
+ }
if (!is_dir($baseDir)) {
$ok = mkdir($baseDir, 0755, true);
if ($ok === false) {
@@ -53,7 +56,9 @@ private function downloadAndExtract(JSignParam $params): void
$url = $params->getJSignPdfDownloadUrl();
$baseDir = preg_replace('/\/JSignPdf.jar$/', '', $jsignPdfPath);
-
+ if (!is_string($baseDir)) {
+ throw new InvalidArgumentException('Invalid JsignParamPath');
+ }
if (!is_dir($baseDir)) {
$ok = mkdir($baseDir, 0755, true);
if (!$ok) {
@@ -89,6 +94,9 @@ private function chunkDownload(string $url, string $destination): void
if ($fp) {
$ch = curl_init($url);
+ if ($ch === false) {
+ throw new InvalidArgumentException('Failure to download file using the url ' . $url);
+ }
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
diff --git a/src/Runtime/JavaRuntimeService.php b/src/Runtime/JavaRuntimeService.php
index aa2a6a2..3d0b541 100644
--- a/src/Runtime/JavaRuntimeService.php
+++ b/src/Runtime/JavaRuntimeService.php
@@ -31,6 +31,9 @@ public function getPath(JSignParam $params): string
if ($downloadUrl && $javaPath) {
$baseDir = preg_replace('/\/bin\/java$/', '', $javaPath);
+ if (!is_string($baseDir)) {
+ throw new InvalidArgumentException('Invalid JsignParamPath');
+ }
if (!is_dir($baseDir)) {
$ok = mkdir($baseDir, 0755, true);
if ($ok === false) {
@@ -52,6 +55,9 @@ private function validateVersion(JSignParam $params): bool
{
$javaPath = $params->getJavaPath();
$baseDir = preg_replace('/\/bin\/java$/', '', $javaPath);
+ if (!is_string($baseDir)) {
+ throw new InvalidArgumentException('Invalid JsignParamPath');
+ }
$lastVersion = $baseDir . '/.java_version_' . basename($params->getJavaDownloadUrl());
return file_exists($lastVersion);
}
@@ -59,6 +65,9 @@ private function validateVersion(JSignParam $params): bool
private function downloadAndExtract(string $url, string $baseDir): void
{
$baseDir = preg_replace('/\/bin\/java$/', '', $baseDir);
+ if (!is_string($baseDir)) {
+ throw new InvalidArgumentException('Invalid JsignParamPath');
+ }
if (!is_dir($baseDir)) {
$ok = mkdir($baseDir, 0755, true);
@@ -76,7 +85,7 @@ private function downloadAndExtract(string $url, string $baseDir): void
throw new InvalidArgumentException('The file ' . $baseDir . '/java.tar.gz cannot be extracted');
}
$rootDirInsideTar = $this->findRootDir($tar, $baseDir . '/java.tar.gz');
- if (!$rootDirInsideTar) {
+ if (empty($rootDirInsideTar)) {
throw new InvalidArgumentException('Invalid tar content.');
}
$tar->extractTo(directory: $baseDir, overwrite: true);
@@ -91,9 +100,12 @@ private function downloadAndExtract(string $url, string $baseDir): void
chmod($baseDir . '/bin/java', 0700);
}
- private function findRootDir(PharData $phar, string $rootDir): ?string {
+ private function findRootDir(PharData $phar, string $rootDir): string {
$files = new \RecursiveIteratorIterator($phar, \RecursiveIteratorIterator::CHILD_FIRST);
$rootDir = realpath($rootDir);
+ if (!is_string($rootDir) || empty($rootDir)) {
+ throw new InvalidArgumentException('Invalid tar content.');
+ }
foreach ($files as $file) {
$pathName = $file->getPathname();
@@ -104,7 +116,7 @@ private function findRootDir(PharData $phar, string $rootDir): ?string {
return trim($parts[0], '/');
}
}
- return null;
+ return '';
}
private function chunkDownload(string $url, string $destination): void
@@ -113,6 +125,9 @@ private function chunkDownload(string $url, string $destination): void
if ($fp) {
$ch = curl_init($url);
+ if ($ch === false) {
+ throw new InvalidArgumentException('Failure to download file using the url ' . $url);
+ }
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
diff --git a/src/Sign/JSignParam.php b/src/Sign/JSignParam.php
index 7568e4b..3e3145d 100644
--- a/src/Sign/JSignParam.php
+++ b/src/Sign/JSignParam.php
@@ -100,7 +100,7 @@ public function setTempPath(string $tempPath): self
return $this;
}
- public function getTempName(string|null $extension = null): string
+ public function getTempName(string $extension = ''): string
{
return $this->tempName.$extension;
}
diff --git a/src/Sign/JSignService.php b/src/Sign/JSignService.php
index 111e568..1d8cc7e 100644
--- a/src/Sign/JSignService.php
+++ b/src/Sign/JSignService.php
@@ -14,7 +14,7 @@
*/
class JSignService
{
- private $fileService;
+ private JSignFileService $fileService;
public function __construct()
{
@@ -68,7 +68,8 @@ private function repackCertificateIfPasswordIsUnicode(
\OpenSSLAsymmetricKey|\OpenSSLCertificate|string $pkey,
): void
{
- if (!mb_detect_encoding($params->getPassword(), 'ASCII', true)) {
+ $detectedEncodingString = mb_detect_encoding($params->getPassword(), 'ASCII', true);
+ if ($detectedEncodingString === false) {
$password = md5(microtime());
$newCert = $this->exportToPkcs12($cert, $pkey, $password);
$params->setPassword($password);
@@ -101,6 +102,9 @@ private function validation(JSignParam $params): void
$this->throwIf($this->isExpiredCertificate($params), 'Certificate expired.');
if ($params->isUseJavaInstalled()) {
$javaVersion = exec("java -version 2>&1");
+ if ($javaVersion === false) {
+ throw new Exception('Java not installed, set the flag "isUseJavaInstalled" as false or install java.');
+ }
$hasJavaVersion = strpos($javaVersion, 'not found') === false;
$this->throwIf(!$hasJavaVersion, 'Java not installed, set the flag "isUseJavaInstalled" as false or install java.');
}
@@ -182,8 +186,8 @@ private function pkcs12Read(JSignParam $params): array
}
$msg = openssl_error_string();
if ($msg === 'error:0308010C:digital envelope routines::unsupported') {
- $opensslVersion = shell_exec('openssl version');
- if (empty($opensslVersion)) {
+ $opensslVersion = exec('openssl version');
+ if ($opensslVersion === false) {
return [];
}
$tempPassword = tempnam(sys_get_temp_dir(), 'pfx');
@@ -195,7 +199,7 @@ private function pkcs12Read(JSignParam $params): array
}
file_put_contents($tempPassword, $password);
file_put_contents($tempEncriptedOriginal, $certificate);
- $this->safeShellExec($tempPassword, $tempEncriptedOriginal, $tempDecrypted, $tempEncriptedRepacked);
+ $this->safeExec($tempPassword, $tempEncriptedOriginal, $tempDecrypted, $tempEncriptedRepacked);
$certificateRepacked = file_get_contents($tempEncriptedRepacked);
if ($certificateRepacked === false) {
return [];
@@ -212,7 +216,7 @@ private function pkcs12Read(JSignParam $params): array
return [];
}
- private function safeShellExec(
+ private function safeExec(
string $tempPassword,
string $tempEncriptedOriginal,
string $tempDecrypted,
@@ -224,7 +228,7 @@ private function safeShellExec(
$tempDecrypted = escapeshellarg($tempDecrypted);
$tempEncriptedRepacked = escapeshellarg($tempEncriptedRepacked);
- shell_exec(<<
Date: Mon, 11 Aug 2025 21:36:56 -0300
Subject: [PATCH 16/17] chore: make more strict
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
---
psalm.xml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/psalm.xml b/psalm.xml
index 1dac25a..6e44d64 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -21,5 +21,9 @@
+
+
+
+
From 6f757797d0260dccd6346d388b30f79da7f3ce7c Mon Sep 17 00:00:00 2001
From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Date: Mon, 11 Aug 2025 21:39:56 -0300
Subject: [PATCH 17/17] feat: add GitHub Action to psalm
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
---
.github/workflows/psalm.yml | 39 +++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
create mode 100644 .github/workflows/psalm.yml
diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml
new file mode 100644
index 0000000..c0c8646
--- /dev/null
+++ b/.github/workflows/psalm.yml
@@ -0,0 +1,39 @@
+name: Static analysis
+
+on: pull_request
+
+concurrency:
+ group: psalm-${{ github.head_ref || github.run_id }}
+ cancel-in-progress: true
+
+permissions:
+ contents: read
+
+jobs:
+ static-analysis:
+ runs-on: ubuntu-latest
+
+ name: static-psalm-analysis
+ steps:
+ - name: Checkout
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ with:
+ persist-credentials: false
+
+ - name: Set up php8.1
+ uses: shivammathur/setup-php@ccf2c627fe61b1b4d924adfcbd19d661a18133a0 # v2.35.2
+ with:
+ php-version: 8.1
+ extensions: json, openssl
+ coverage: none
+ ini-file: development
+ # Temporary workaround for missing pcntl_* in PHP 8.3
+ ini-values: disable_functions=
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Install dependencies
+ run: composer i
+
+ - name: Run coding standards check
+ run: composer run psalm -- --output-format=github