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