diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 8ca381e..bf9c5e3 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -23,7 +23,7 @@ jobs: strategy: fail-fast: false matrix: - php-version: ["8.0", "8.1", "8.2", "8.3"] + php-version: ["8.1", "8.2", "8.3", "8.4"] experimental: [false] os: [ubuntu-latest] coverage-extension: [pcov] @@ -50,7 +50,7 @@ jobs: - name: Run all tests run: make qa - name: Send coverage - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v5 with: flags: php-${{ matrix.php-version }}-${{ matrix.os }} name: php-${{ matrix.php-version }}-${{ matrix.os }} diff --git a/Makefile b/Makefile index 3da98e3..4e26acf 100644 --- a/Makefile +++ b/Makefile @@ -170,7 +170,7 @@ endif deps: ensuretarget rm -rf ./vendor/* ($(COMPOSER) install -vvv --no-interaction) - curl --silent --show-error --fail --location --output ./vendor/phpstan.phar https://github.com/phpstan/phpstan/releases/download/1.10.41/phpstan.phar \ + curl --silent --show-error --fail --location --output ./vendor/phpstan.phar https://github.com/phpstan/phpstan/releases/download/2.0.4/phpstan.phar \ && chmod +x ./vendor/phpstan.phar # Generate source code documentation @@ -212,8 +212,8 @@ endif .PHONY: lint lint: ./vendor/bin/phpcs --ignore="./vendor/" --standard=phpcs.xml src test - ./vendor/bin/phpmd src text codesize,unusedcode,naming,design --exclude vendor - ./vendor/bin/phpmd test text unusedcode,naming,design + ./vendor/bin/phpmd src text codesize,unusedcode,naming,design --exclude */vendor/* + ./vendor/bin/phpmd test text unusedcode,naming,design --exclude */vendor/* php -r 'exit((int)version_compare(PHP_MAJOR_VERSION, "7", ">"));' || ./vendor/phpstan.phar analyse # Run all tests and reports @@ -261,7 +261,7 @@ tag: .PHONY: test test: cp phpunit.xml.dist phpunit.xml - ./vendor/bin/phpunit --migrate-configuration || true + #./vendor/bin/phpunit --migrate-configuration || true XDEBUG_MODE=coverage ./vendor/bin/phpunit --stderr test # Remove all installed files diff --git a/VERSION b/VERSION index 9bbe651..e265a8c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.14 +3.0.15 diff --git a/composer.json b/composer.json index a20e13f..e65fb64 100644 --- a/composer.json +++ b/composer.json @@ -18,15 +18,15 @@ } ], "require": { - "php": ">=8.0", + "php": ">=8.1", "ext-pcre": "*", "tecnickcom/tc-lib-pdf-filter": "^2.0" }, "require-dev": { - "pdepend/pdepend": "2.13.0", - "phpmd/phpmd": "2.13.0", - "phpunit/phpunit": "10.1.2 || 9.6.13", - "squizlabs/php_codesniffer": "3.7.2" + "pdepend/pdepend": "2.16.2", + "phpmd/phpmd": "2.15.0", + "phpunit/phpunit": "11.5.2 || 10.5.40", + "squizlabs/php_codesniffer": "3.11.2" }, "autoload": { "psr-4": { diff --git a/phpstan.neon b/phpstan.neon index bf592ce..86bd47d 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -3,7 +3,7 @@ parameters: paths: - src - test - scanDirectories: + excludePaths: - vendor ignoreErrors: reportUnmatchedIgnoredErrors: false diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 9597570..745e082 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,27 +1,31 @@ + stopOnFailure="false"> ./test - - - src - - + + + src + + + + + + + + - - - + diff --git a/resources/debian/compat b/resources/debian/compat index ec63514..f599e28 100644 --- a/resources/debian/compat +++ b/resources/debian/compat @@ -1 +1 @@ -9 +10 diff --git a/resources/debian/control b/resources/debian/control index bd0b1b2..8eb6702 100644 --- a/resources/debian/control +++ b/resources/debian/control @@ -10,6 +10,6 @@ Vcs-Git: https://github.com/~#VENDOR#~/~#PROJECT#~.git Package: ~#PKGNAME#~ Provides: php-~#PROJECT#~ Architecture: all -Depends: php (>= 8.0.0), php-tecnickcom-tc-lib-pdf-filter (<< 2.0.0), php-tecnickcom-tc-lib-pdf-filter (>= 2.0.17), ${misc:Depends} +Depends: php (>= 8.1.0), php-tecnickcom-tc-lib-pdf-filter (<< 2.0.0), php-tecnickcom-tc-lib-pdf-filter (>= 2.0.18), ${misc:Depends} Description: PHP PDF Parser Library PHP library to parse PDF documents. diff --git a/resources/rpm/rpm.spec b/resources/rpm/rpm.spec index 792299b..deed813 100644 --- a/resources/rpm/rpm.spec +++ b/resources/rpm/rpm.spec @@ -16,9 +16,9 @@ URL: https://github.com/%{gh_owner}/%{gh_project} BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-%(%{__id_u} -n) BuildArch: noarch -Requires: php(language) >= 8.0.0 +Requires: php(language) >= 8.1.0 Requires: php-composer(%{c_vendor}/tc-lib-pdf-filter) < 2.0.0 -Requires: php-composer(%{c_vendor}/tc-lib-pdf-filter) >= 2.0.17 +Requires: php-composer(%{c_vendor}/tc-lib-pdf-filter) >= 2.0.18 Requires: php-pcre Provides: php-composer(%{c_vendor}/%{gh_project}) = %{version} diff --git a/src/Parser.php b/src/Parser.php index ff7ed03..63749bf 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -32,7 +32,7 @@ * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) * @link https://github.com/tecnickcom/tc-lib-pdf-parser * - * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) + * @SuppressWarnings("PHPMD.ExcessiveClassComplexity") * * @phpstan-import-type RawObjectArray from \Com\Tecnick\Pdf\Parser\Process\RawObject */ @@ -230,7 +230,7 @@ protected function getObjectVal(array $obj): array * 1: array, * } Decoded stream data and remaining filters. * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings("PHPMD.CyclomaticComplexity") */ protected function decodeStream(array $sdic, string $stream): array { diff --git a/src/Process/RawObject.php b/src/Process/RawObject.php index 97103fa..5e284fb 100644 --- a/src/Process/RawObject.php +++ b/src/Process/RawObject.php @@ -232,7 +232,7 @@ protected function processParenthesis(string $char, int &$offset, string &$objty * @param string $char Symbol to process * @param int $offset Offset * @param string $objtype Object type - * @param arraygetRawObject($offset); $offset = $element[2]; - $objval[] = $element; + $objval[] = $element; // @phpstan-ignore parameterByRef.type } while ($element[0] != ']'); // remove closing delimiter @@ -289,7 +289,7 @@ protected function processAngular(string $char, int &$offset, string &$objtype, do { $element = $this->getRawObject($offset); $offset = $element[2]; - $objval[] = $element; + $objval[] = $element; // @phpstan-ignore parameterByRef.type } while ($element[0] != '>>'); // remove closing delimiter diff --git a/src/Process/Xref.php b/src/Process/Xref.php index f213258..1bf754d 100644 --- a/src/Process/Xref.php +++ b/src/Process/Xref.php @@ -34,7 +34,7 @@ abstract class Xref extends \Com\Tecnick\Pdf\Parser\Process\XrefStream { /** - * XREF data. + * Default empty XREF data. * * @var array{ * 'trailer': array{ @@ -47,7 +47,7 @@ abstract class Xref extends \Com\Tecnick\Pdf\Parser\Process\XrefStream * 'xref': array, * } */ - protected array $xref = [ + protected const XREF_EMPTY = [ 'trailer' => [ 'encrypt' => '', 'id' => [], @@ -58,6 +58,22 @@ abstract class Xref extends \Com\Tecnick\Pdf\Parser\Process\XrefStream 'xref' => [], ]; + /** + * XREF data. + * + * @var array{ + * 'trailer': array{ + * 'encrypt'?: string, + * 'id': array, + * 'info': string, + * 'root': string, + * 'size': int, + * }, + * 'xref': array, + * } + */ + protected array $xref = self::XREF_EMPTY; + /** * Store the processed offsets * @@ -107,7 +123,7 @@ abstract protected function getIndirectObject(string $obj_ref, int $offset = 0, * 'xref': array, * } Xref and trailer data. * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings("PHPMD.CyclomaticComplexity") */ protected function getXrefData(int $offset = 0, array $xref = []): array { @@ -355,7 +371,7 @@ protected function getTrailerData(array $xref, array $matches): array * 'xref': array, * } Xref and trailer data. * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings("PHPMD.CyclomaticComplexity") */ protected function decodeXrefStream(int $startxref, array $xref): array { @@ -366,16 +382,13 @@ protected function decodeXrefStream(int $startxref, array $xref): array } $xrefcrs = $this->getIndirectObject($xrefobj[1], $startxref, true); - if (! isset($xref['trailer']) || empty($xref['trailer'])) { - // get only the last updated version - $xref['trailer'] = []; - $filltrailer = true; - } else { - $filltrailer = false; - } + $filltrailer = empty($xref['trailer']); + if ($filltrailer) { + $xref['trailer'] = self::XREF_EMPTY['trailer']; + } if (! isset($xref['xref'])) { - $xref['xref'] = []; + $xref['xref'] = self::XREF_EMPTY['xref']; } $valid_crs = false; @@ -405,7 +418,7 @@ protected function decodeXrefStream(int $startxref, array $xref): array $ddata = []; // initialize first row with zeros $prev_row = array_fill(0, $rowlen, 0); - $this->pngUnpredictor($sdata, $ddata, $columns, $prev_row); + $this->pngUnpredictor($sdata, $ddata, $columns, $prev_row); //@phpstan-ignore argument.type // complete decoding $sdata = []; $this->processDdata($sdata, $ddata, $wbt); @@ -417,12 +430,12 @@ protected function decodeXrefStream(int $startxref, array $xref): array } // end decoding data - if ($prevxref !== []) { - // get previous xref - return $this->getXrefData($prevxref, $xref); + if (is_null($prevxref)) { + return $xref; } - return $xref; + // get previous xref + return $this->getXrefData($prevxref, $xref); } /** diff --git a/src/Process/XrefStream.php b/src/Process/XrefStream.php index 0f20024..4826e00 100644 --- a/src/Process/XrefStream.php +++ b/src/Process/XrefStream.php @@ -32,6 +32,8 @@ * @link https://github.com/tecnickcom/tc-lib-pdf-parser * * @phpstan-import-type RawObjectArray from \Com\Tecnick\Pdf\Parser\Process\RawObject + * + * @SuppressWarnings("PHPMD.ExcessiveClassComplexity") */ abstract class XrefStream extends \Com\Tecnick\Pdf\Parser\Process\RawObject { @@ -48,8 +50,8 @@ abstract class XrefStream extends \Com\Tecnick\Pdf\Parser\Process\RawObject * }, * 'xref': array, * } $xref XREF data - * @param int $obj_num Object number - * @param array> $sdata Stream data + * @param int $obj_num Object number + * @param array> $sdata Stream data */ protected function processObjIndexes(array &$xref, int &$obj_num, array $sdata): void { @@ -202,22 +204,22 @@ protected function minDistance( * 'xref': array, * } $xref XREF data * @param array $wbt WBT data - * @param int $index_first Index first - * @param int $prevxref Previous XREF + * @param int|null $index_first Index first + * @param int|null $prevxref Previous XREF * @param int $columns Number of columns - * @param int $valid_crs Valid CRS + * @param bool $valid_crs Valid CRS * @param bool $filltrailer Fill trailer * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings("PHPMD.CyclomaticComplexity") */ protected function processXrefType( array $sarr, array &$xref, array &$wbt, - int &$index_first, - int &$prevxref, + ?int &$index_first, + ?int &$prevxref, int &$columns, - int &$valid_crs, + bool &$valid_crs, bool $filltrailer ): void { foreach ($sarr as $key => $val) { @@ -262,9 +264,9 @@ protected function processXrefType( * * @param array $sarr Stream data * @param int $key Key - * @param int $prevxref Previous XREF + * @param int|null $prevxref Previous XREF */ - protected function processXrefPrev(array $sarr, int $key, int &$prevxref): void + protected function processXrefPrev(array $sarr, int $key, ?int &$prevxref): void { if ($sarr[($key + 1)][0] == 'numeric') { // get previous xref offset @@ -299,9 +301,9 @@ protected function processXrefDecodeParms(array $sarr, int $key, int &$columns): /** * Process XREF type * - * @param string $type Type + * @param string $type Type * @param array $sarr Stream data - * @param int $key Key + * @param int $key Key * @param array{ * 'trailer': array{ * 'encrypt'?: string, @@ -311,8 +313,8 @@ protected function processXrefDecodeParms(array $sarr, int $key, int &$columns): * 'size': int, * }, * 'xref': array, - * } $xref XREF data - * @param bool $filltrailer Fill trailer + * } $xref XREF data + * @param bool $filltrailer Fill trailer */ protected function processXrefTypeFt(string $type, array $sarr, int $key, array &$xref, bool $filltrailer): void { @@ -323,11 +325,19 @@ protected function processXrefTypeFt(string $type, array $sarr, int $key, array switch ($type) { case 'Size': if ($sarr[($key + 1)][0] == 'numeric') { - $xref['trailer']['size'] = $sarr[($key + 1)][1]; + $xref['trailer']['size'] = (int) $sarr[($key + 1)][1]; } break; case 'ID': + if ( + empty($sarr[($key + 1)][1][0][1]) + || empty($sarr[($key + 1)][1][1][1]) + || !is_string($sarr[($key + 1)][1][0][1]) + || !is_string($sarr[($key + 1)][1][1][1]) + ) { + break; + } $xref['trailer']['id'] = []; $xref['trailer']['id'][0] = $sarr[($key + 1)][1][0][1]; $xref['trailer']['id'][1] = $sarr[($key + 1)][1][1][1]; @@ -357,19 +367,26 @@ protected function processXrefTypeFt(string $type, array $sarr, int $key, array */ protected function processXrefObjref(string $type, array $sarr, int $key, array &$xref): void { - if (! isset($sarr[($key + 1)]) || ($sarr[($key + 1)][0] !== 'objref')) { + if ( + empty($sarr[($key + 1)]) + || empty($sarr[($key + 1)][1]) + || !is_string($sarr[($key + 1)][1]) + || ($sarr[($key + 1)][0] !== 'objref') + ) { return; } + $val = $sarr[($key + 1)][1]; + switch ($type) { case 'Root': - $xref['trailer']['root'] = $sarr[($key + 1)][1]; + $xref['trailer']['root'] = $val; break; case 'Info': - $xref['trailer']['info'] = $sarr[($key + 1)][1]; + $xref['trailer']['info'] = $val; break; case 'Encrypt': - $xref['trailer']['encrypt'] = $sarr[($key + 1)][1]; + $xref['trailer']['encrypt'] = $val; break; } } diff --git a/test/ParserTest.php b/test/ParserTest.php index e2c3a26..3a134ee 100644 --- a/test/ParserTest.php +++ b/test/ParserTest.php @@ -18,6 +18,7 @@ use Com\Tecnick\Pdf\Parser\Parser; use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\Attributes\DataProvider; /** * Filter Test @@ -32,9 +33,7 @@ */ class ParserTest extends TestCase { - /** - * @dataProvider getParseProvider - */ + #[DataProvider('getParseProvider')] public function testParse(string $filename, string $hash): void { $cfg = [