From 584784c119a5fa05106985a6629db6628535907c Mon Sep 17 00:00:00 2001 From: Ne-Lexa Date: Sun, 16 May 2021 12:18:23 +0300 Subject: [PATCH] php 7.1 - 8.0 compatible version issue #78 --- .gitattributes | 3 +- .github/workflows/build.yml | 130 +++++++ .php_cs => .php-cs-fixer.php | 364 ++++++++++++------ README.RU.md | 20 +- README.md | 20 +- bootstrap.php | 6 - composer.json | 22 +- logo.svg | 1 + phpunit.xml | 5 +- src/Constants/ZipCompressionMethod.php | 5 +- src/Constants/ZipEncryptionMethod.php | 5 +- src/Constants/ZipPlatform.php | 2 +- .../Filter/Cipher/Pkware/PKCryptContext.php | 2 +- .../Pkware/PKEncryptionStreamFilter.php | 6 +- .../WinZipAesDecryptionStreamFilter.php | 10 +- .../WinZipAesEncryptionStreamFilter.php | 6 +- src/IO/Stream/ResponseStream.php | 58 ++- src/IO/ZipReader.php | 58 +-- src/IO/ZipWriter.php | 60 +-- src/Model/Data/ZipNewData.php | 76 ++-- src/Model/Data/ZipSourceFileData.php | 36 +- src/Model/Extra/ExtraFieldsCollection.php | 54 ++- .../Fields/AbstractUnicodeExtraField.php | 4 +- .../Extra/Fields/ApkAlignmentExtraField.php | 26 +- src/Model/Extra/Fields/AsiExtraField.php | 30 +- .../Fields/ExtendedTimestampExtraField.php | 54 +-- .../Extra/Fields/JarMarkerExtraField.php | 16 +- src/Model/Extra/Fields/NewUnixExtraField.php | 26 +- src/Model/Extra/Fields/NtfsExtraField.php | 52 +-- src/Model/Extra/Fields/OldUnixExtraField.php | 74 ++-- .../Extra/Fields/UnicodeCommentExtraField.php | 24 +- .../Extra/Fields/UnicodePathExtraField.php | 24 +- .../Extra/Fields/UnrecognizedExtraField.php | 26 +- .../Extra/Fields/WinZipAesExtraField.php | 38 +- src/Model/Extra/Fields/Zip64ExtraField.php | 66 ++-- src/Model/Extra/ZipExtraDriver.php | 2 - src/Model/Extra/ZipExtraField.php | 10 +- src/Model/ImmutableZipContainer.php | 32 +- src/Model/ZipContainer.php | 6 +- src/Model/ZipEntry.php | 87 +++-- src/Model/ZipInfo.php | 54 +-- src/Util/CryptoUtil.php | 16 +- src/Util/DateTimeConverter.php | 12 +- src/Util/FileAttribUtil.php | 8 + src/Util/FilesUtil.php | 13 +- src/ZipFile.php | 48 +-- src/ZipFileInterface.php | 2 +- .../Fields/AbstractUnicodeExtraFieldTest.php | 12 +- .../Fields/ApkAlignmentExtraFieldTest.php | 6 +- tests/Extra/Fields/AsiExtraFieldTest.php | 6 +- .../ExtendedTimestampExtraFieldTest.php | 24 +- .../Extra/Fields/JarMarkerExtraFieldTest.php | 12 +- tests/Extra/Fields/NtfsExtraFieldTest.php | 10 +- .../Fields/UnicodeCommentExtraFieldTest.php | 2 +- .../Fields/UnicodePathExtraFieldTest.php | 2 +- .../Fields/UnrecognizedExtraFieldTest.php | 12 +- .../Extra/Fields/WinZipAesExtraFieldTest.php | 18 +- tests/Extra/Fields/Zip64ExtraFieldTest.php | 4 +- tests/Issue24Test.php | 2 +- tests/PhpZipExtResourceTest.php | 22 +- tests/Polyfill/LegacyTestCase.php | 18 + tests/Polyfill/PhpUnit8CompatTrait.php | 22 ++ tests/Polyfill/PhpUnit9CompatTrait.php | 53 +++ tests/SymlinkTest.php | 2 +- tests/ZipAlignTest.php | 16 +- tests/ZipEntryTest.php | 64 +-- tests/ZipFileSetTestCase.php | 2 +- tests/ZipFileTest.php | 294 +++++++++----- tests/ZipInfoTest.php | 6 +- tests/ZipMatcherTest.php | 2 +- tests/ZipPasswordTest.php | 56 +-- tests/ZipStreamOpenTest.php | 10 +- tests/ZipTestCase.php | 28 +- 73 files changed, 1446 insertions(+), 958 deletions(-) create mode 100644 .github/workflows/build.yml rename .php_cs => .php-cs-fixer.php (85%) delete mode 100644 bootstrap.php create mode 100644 logo.svg create mode 100644 tests/Polyfill/LegacyTestCase.php create mode 100644 tests/Polyfill/PhpUnit8CompatTrait.php create mode 100644 tests/Polyfill/PhpUnit9CompatTrait.php diff --git a/.gitattributes b/.gitattributes index a76f41e..202d657 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,8 +1,7 @@ .gitattributes export-ignore .github export-ignore .gitignore export-ignore -.php_cs export-ignore -.travis.yml export-ignore +.php-cs-fixer.php export-ignore bootstrap.php export-ignore phpunit.xml export-ignore tests export-ignore diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..66c0ffd --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,130 @@ +name: build + +on: + - push + - pull_request + +jobs: + tests: + name: PHP ${{ matrix.php }} Test on ${{ matrix.os }} + + env: + extensions: bz2, dom, iconv, fileinfo, openssl, xml, zlib, gd + key: cache-v1 + PHPUNIT_COVERAGE: 0 + PHP_INI: date.timezone='UTC', memory_limit=-1, opcache.enable=1, opcache.enable_cli=1 + + strategy: + matrix: + os: + - ubuntu-latest + - windows-latest + - macos-latest + php: + - '7.1' + - '7.2' + - '7.3' + - '7.4' + - '8.0' + + runs-on: ${{ matrix.os }} + + steps: + - + name: Checkout + uses: actions/checkout@v1 + + - + name: Install linux dependencies + if: matrix.os == 'ubuntu-latest' + run: sudo apt-get install unzip p7zip-full zipalign + + - + name: Install windows dependencies + if: matrix.os == 'windows-latest' + run: choco install zip unzip 7zip + + - + name: Install macos dependencies + if: matrix.os == 'macos-latest' + run: brew install zip unzip p7zip + + - + name: Disable JIT for PHP 8 on Linux and Mac + if: (matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest') && matrix.php == '8.0' + run: echo "PHP_INI=\"${PHP_INI}, opcache.jit=0, opcache.jit_buffer_size=0\"" >> $GITHUB_ENV + + - + name: Disable JIT for PHP 8 on Windows + if: matrix.os == 'windows-latest' && matrix.php == '8.0' + run: echo "PHP_INI=\"$PHP_INI, opcache.jit=0, opcache.jit_buffer_size=0\"" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + - + name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: ${{ env.extensions }} + coverage: pcov + ini-values: ${{ env.PHP_INI }} + tools: composer:v2, cs2pr + + - + name: Determine composer cache directory on Linux or MacOS + if: matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest' + run: echo "COMPOSER_CACHE_DIR=$(composer config cache-dir)" >> $GITHUB_ENV + + - + name: Determine composer cache directory on Windows + if: matrix.os == 'windows-latest' + run: echo "COMPOSER_CACHE_DIR=~\AppData\Local\Composer" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + - + name: Set coverage args + if: matrix.os == 'ubuntu-latest' && matrix.php == '7.4' + run: echo "PHPUNIT_COVERAGE=1" >> $GITHUB_ENV + + - + name: Cache composer dependencies + uses: actions/cache@v2 + with: + path: ${{ env.COMPOSER_CACHE_DIR }} + key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: php${{ matrix.php }}-composer- + + - + name: Check PHP Version + run: php -v + + - + name: Check Composer Version + run: composer -V + + - + name: Check PHP Extensions + run: php -m + + - + name: Validate composer.json and composer.lock + run: composer validate + + - + name: Install dependencies with composer + run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi + + - + name: Run tests with phpunit + if: env.PHPUNIT_COVERAGE == 0 + run: vendor/bin/phpunit -v --testsuite "all_tests" --group small,medium,large + + - + name: Run tests with phpunit and coverage + if: env.PHPUNIT_COVERAGE == 1 + run: vendor/bin/phpunit -v --coverage-clover=coverage.clover --testsuite "all_tests" --group small,medium,large + + - + name: Upload code coverage scrutinizer + if: env.PHPUNIT_COVERAGE == 1 + run: | + wget https://scrutinizer-ci.com/ocular.phar + php ocular.phar code-coverage:upload --format=php-clover coverage.clover diff --git a/.php_cs b/.php-cs-fixer.php similarity index 85% rename from .php_cs rename to .php-cs-fixer.php index 2c7f3dd..3a9e470 100644 --- a/.php_cs +++ b/.php-cs-fixer.php @@ -1,16 +1,18 @@ true, + /* + * Converts simple usages of `array_push($x, $y);` to `$x[] = $y;`. + * + * Risky! + * Risky when the function `array_push` is overridden. + */ + 'array_push' => true, + // PHP arrays should be declared using the configured syntax. 'array_syntax' => [ 'syntax' => 'short', @@ -51,23 +61,7 @@ $rules = [ 'blank_line_after_opening_tag' => true, // An empty line feed must precede any configured statement. - 'blank_line_before_statement' => [ - 'statements' => [ - 'continue', - 'declare', - 'return', - 'throw', - 'try', - 'case', - 'die', - 'exit', - 'do', - 'foreach', - 'goto', - 'if', - 'while', - ], - ], + 'blank_line_before_statement' => true, /* * The body of each structure MUST be enclosed by braces. Braces @@ -82,8 +76,8 @@ $rules = [ 'cast_spaces' => true, /* - * Class, trait and interface elements must be separated with one - * blank line. + * Class, trait and interface elements must be separated with one or + * none blank line. */ 'class_attributes_separation' => true, @@ -98,6 +92,9 @@ $rules = [ // Converts `::class` keywords to FQCN strings. 'class_keyword_remove' => false, + // Namespace must not contain spacing, comments or PHPDoc. + 'clean_namespace' => true, + // Using `isset($var) &&` multiple times should be done in one call. 'combine_consecutive_issets' => true, @@ -111,7 +108,7 @@ $rules = [ * Risky! * Risky when the function `dirname` is overridden. */ - 'combine_nested_dirname' => false, + 'combine_nested_dirname' => true, /* * Comments with annotation should be docblock when used on @@ -132,7 +129,7 @@ $rules = [ * * Rule is applied only in a PHP 7.1+ environment. */ - 'compact_nullable_typehint' => false, + 'compact_nullable_typehint' => true, // Concatenation should be spaced according configuration. 'concat_space' => [ @@ -181,7 +178,9 @@ $rules = [ * Doctrine annotations must use configured operator for assignment * in arrays. */ - 'doctrine_annotation_array_assignment' => true, + 'doctrine_annotation_array_assignment' => [ + 'operator' => ':', + ], /* * Doctrine annotations without arguments must use the configured @@ -200,7 +199,15 @@ $rules = [ * space around named arguments assignment operator; there must be * one space around array assignment operator. */ - 'doctrine_annotation_spaces' => true, + 'doctrine_annotation_spaces' => [ + 'before_array_assignments_colon' => false, + ], + + /* + * Replaces short-echo ` true, /* * The keyword `elseif` should be used instead of `else if` so that @@ -270,7 +277,7 @@ $rules = [ * Add curly braces to indirect variables to make them clear to * understand. Requires PHP >= 7.0. */ - 'explicit_indirect_variable' => false, + 'explicit_indirect_variable' => true, /* * Converts implicit variables into explicit ones in double-quoted @@ -332,9 +339,6 @@ $rules = [ */ 'final_public_method_for_abstract_class' => false, - // Converts `static` access to `self` access in `final` classes. - 'final_static_access' => true, - /* * Order the flags in `fopen` calls, `b` and `t` must be last. * @@ -377,15 +381,7 @@ $rules = [ * Risky when any of the configured functions to replace are * overridden. */ - 'function_to_constant' => [ - 'functions' => [ - 'get_class', - 'php_sapi_name', - 'phpversion', - 'pi', - 'get_called_class', - ], - ], + 'function_to_constant' => true, // Ensure single space between function's argument and its typehint. 'function_typehint_space' => true, @@ -393,6 +389,13 @@ $rules = [ // Configured annotations should be omitted from PHPDoc. 'general_phpdoc_annotation_remove' => true, + // Renames PHPDoc tags. + 'general_phpdoc_tag_rename' => [ + 'replacements' => [ + 'inheritDocs' => 'inheritDoc', + ], + ], + // Imports or fully qualifies global classes/functions/constants. 'global_namespace_import' => [ 'import_constants' => false, @@ -400,6 +403,9 @@ $rules = [ 'import_classes' => false, ], + // There MUST be group use for the same namespaces. + 'group_import' => false, + // Add, replace or remove header comment. 'header_comment' => false, @@ -444,6 +450,9 @@ $rules = [ */ 'is_null' => true, + // Lambda must not import variables it doesn't use. + 'lambda_not_used_import' => true, + // All PHP files must use same line ending. 'line_ending' => true, @@ -589,6 +598,9 @@ $rules = [ ], ], + // Master language constructs shall be used instead of aliases. + 'no_alias_language_construct_call' => true, + // Replace control structure alternative syntax to use braces. 'no_alternative_syntax' => true, @@ -630,30 +642,14 @@ $rules = [ // There should not be empty PHPDoc blocks. 'no_empty_phpdoc' => true, - // Remove useless semicolon statements. + // Remove useless (semicolon) statements. 'no_empty_statement' => true, /* * Removes extra blank lines and/or blank lines following * configuration. */ - 'no_extra_blank_lines' => [ - 'tokens' => [ - 'extra', - 'case', - 'continue', - 'default', - 'curly_brace_block', - 'parenthesis_brace_block', - 'return', - 'square_brace_block', - 'use', - 'throw', - 'use_trait', - 'useTrait', - 'switch', - ], - ], + 'no_extra_blank_lines' => true, /* * Replace accidental usage of homoglyphs (non ascii characters) in @@ -701,9 +697,6 @@ $rules = [ */ 'no_short_bool_cast' => true, - // Replace short-echo ` false, - // Single-line whitespace before closing semicolon are prohibited. 'no_singleline_whitespace_before_semicolons' => true, @@ -743,14 +736,36 @@ $rules = [ // There MUST be no trailing spaces inside comment or PHPDoc. 'no_trailing_whitespace_in_comment' => true, + /* + * There must be no trailing whitespace in strings. + * + * Risky! + * Changing the whitespaces in strings might affect string + * comparisons and outputs. + */ + 'no_trailing_whitespace_in_string' => false, + // Removes unneeded parentheses around control statements. - 'no_unneeded_control_parentheses' => true, + 'no_unneeded_control_parentheses' => [ + 'statements' => [ + 'break', + 'clone', + 'continue', + 'echo_print', + 'return', + 'switch_case', + 'yield', + 'yield_from', + ], + ], /* * Removes unneeded curly braces that are superfluous and aren't * part of a control structure's body. */ - 'no_unneeded_curly_braces' => true, + 'no_unneeded_curly_braces' => [ + 'namespaces' => true, + ], /* * A `final` class must not have `final` methods and `private` @@ -779,12 +794,14 @@ $rules = [ * Properties should be set to `null` instead of using `unset`. * * Risky! - * Changing variables to `null` instead of unsetting them will mean - * they still show up when looping over class variables. With PHP - * 7.4, this rule might introduce `null` assignments to property - * whose type declaration does not allow it. + * Risky when relying on attributes to be removed using `unset` + * rather than be set to `null`. Changing variables to `null` + * instead of unsetting means these still show up when looping over + * class variables and reference properties remain unbroken. With + * PHP 7.4, this rule might introduce `null` assignments to + * properties whose type declaration does not allow it. */ - 'no_unset_on_property' => false, + 'no_unset_on_property' => true, // Unused `use` statements must be removed. 'no_unused_imports' => true, @@ -798,6 +815,14 @@ $rules = [ */ 'no_useless_return' => true, + /* + * There must be no `sprintf` calls with only the first argument. + * + * Risky! + * Risky when if the `sprintf` function is overridden. + */ + 'no_useless_sprintf' => true, + /* * In array declaration, there MUST NOT be a whitespace before each * comma. @@ -837,13 +862,33 @@ $rules = [ 'nullable_type_declaration_for_default_null_value' => false, /* - * There should not be space before or after object - * `T_OBJECT_OPERATOR` `->`. + * There should not be space before or after object operators `->` + * and `?->`. */ 'object_operator_without_whitespace' => true, + /* + * Operators - when multiline - must always be at the beginning or + * at the end of the line. + */ + 'operator_linebreak' => true, + // Orders the elements of classes/interfaces/traits. - 'ordered_class_elements' => false, + 'ordered_class_elements' => [ + 'order' => [ + 'use_trait', + 'constant_public', + 'constant_protected', + 'constant_private', + 'property_public', + 'property_protected', + 'property_private', + 'construct', + 'destruct', + 'magic', + 'phpunit', + ], + ], // Ordering `use` statements. 'ordered_imports' => [ @@ -866,6 +911,14 @@ $rules = [ */ 'ordered_interfaces' => false, + /* + * Trait `use` statements must be sorted alphabetically. + * + * Risky! + * Risky when depending on order of the imports. + */ + 'ordered_traits' => false, + /* * PHPUnit assertion method calls like `->assertSame(true, $foo)` * should be written with dedicated method like @@ -885,9 +938,7 @@ $rules = [ * Fixer could be risky if one is overriding PHPUnit's native * methods. */ - 'php_unit_dedicate_assert' => [ - 'target' => '3.5', - ], + 'php_unit_dedicate_assert' => true, /* * PHPUnit assertions like `assertIsArray` should be used over @@ -897,7 +948,7 @@ $rules = [ * Risky when PHPUnit methods are overridden or when project has * PHPUnit incompatibilities. */ - 'php_unit_dedicate_assert_internal_type' => false, + 'php_unit_dedicate_assert_internal_type' => true, /* * Usages of `->setExpectedException*` methods MUST be replaced by @@ -907,7 +958,9 @@ $rules = [ * Risky when PHPUnit classes are overridden or not accessible, or * when project has PHPUnit incompatibilities. */ - 'php_unit_expectation' => false, + 'php_unit_expectation' => [ + 'target' => '5.6', + ], // PHPUnit annotations should be a FQCNs including a root namespace. 'php_unit_fqcn_annotation' => true, @@ -930,7 +983,7 @@ $rules = [ * Risky when PHPUnit classes are overridden or not accessible, or * when project has PHPUnit incompatibilities. */ - 'php_unit_mock' => false, + 'php_unit_mock' => true, /* * Usage of PHPUnit's mock e.g. `->will($this->returnValue(..))` @@ -941,7 +994,7 @@ $rules = [ * Risky when PHPUnit classes are overridden or not accessible, or * when project has PHPUnit incompatibilities. */ - 'php_unit_mock_short_will_return' => false, + 'php_unit_mock_short_will_return' => true, /* * PHPUnit classes MUST be used in namespaced version, e.g. @@ -962,9 +1015,7 @@ $rules = [ * Risky when PHPUnit classes are overridden or not accessible, or * when project has PHPUnit incompatibilities. */ - 'php_unit_namespaced' => [ - 'target' => '4.8', - ], + 'php_unit_namespaced' => true, /* * Usages of `@expectedException*` annotations MUST be replaced by @@ -978,9 +1029,6 @@ $rules = [ 'target' => 'newest', ], - // Order `@covers` annotation of PHPUnit tests. - 'php_unit_ordered_covers' => true, - /* * Changes the visibility of the `setUp()` and `tearDown()` * functions of PHPUnit to `protected`, to match the PHPUnit @@ -1047,18 +1095,7 @@ $rules = [ * All items of the given phpdoc tags must be either left-aligned or * (by default) aligned vertically. */ - 'phpdoc_align' => [ - 'tags' => [ - 'return', - 'throws', - 'type', - 'var', - 'property', - 'method', - 'param', - ], - 'align' => 'vertical', - ], + 'phpdoc_align' => true, // PHPDoc annotation descriptions should not be a sentence. 'phpdoc_annotation_without_dot' => true, @@ -1069,8 +1106,8 @@ $rules = [ */ 'phpdoc_indent' => true, - // Fix PHPDoc inline tags, make `@inheritdoc` always inline. - 'phpdoc_inline_tag' => true, + // Fixes PHPDoc inline tags. + 'phpdoc_inline_tag_normalizer' => true, /* * Changes doc blocks from single to multi line, or reversed. Works @@ -1110,6 +1147,17 @@ $rules = [ */ 'phpdoc_order' => true, + // Order phpdoc tags by value. + 'phpdoc_order_by_value' => [ + 'annotations' => [ + 'covers', + 'method', + 'property', + 'property-read', + 'property-write', + ], + ], + /* * The type of `@return` annotations of methods returning a * reference to itself must the configured one. @@ -1139,6 +1187,16 @@ $rules = [ */ 'phpdoc_summary' => true, + // Fixes casing of PHPDoc tags. + 'phpdoc_tag_casing' => true, + + // Forces PHPDoc tags to be either regular annotations or inline. + 'phpdoc_tag_type' => [ + 'tags' => [ + 'inheritDoc' => 'inline', + ], + ], + // Docblocks should only be used on structural elements. 'phpdoc_to_comment' => false, @@ -1155,6 +1213,19 @@ $rules = [ */ 'phpdoc_to_param_type' => false, + /* + * EXPERIMENTAL: Takes `@var` annotation of non-mixed types and + * adjusts accordingly the property signature. Requires PHP >= 7.4. + * + * Risky! + * This rule is EXPERIMENTAL and [1] is not covered with backward + * compatibility promise. [2] `@var` annotation is mandatory for the + * fixer to make changes, signatures of properties without it (no + * docblock) will not be fixed. [3] Manual actions might be required + * for newly typed properties that are read before initialization. + */ + 'phpdoc_to_property_type' => false, + /* * EXPERIMENTAL: Takes `@return` annotation of non-mixed types and * adjusts accordingly the function signature. Requires PHP >= 7.0. @@ -1164,8 +1235,7 @@ $rules = [ * compatibility promise. [2] `@return` annotation is mandatory for * the fixer to make changes, signatures of methods without it (no * docblock, inheritdocs) will not be fixed. [3] Manual actions are - * required if inherited signatures are not properly documented. [4] - * `@inheritdocs` support is under construction. + * required if inherited signatures are not properly documented. */ 'phpdoc_to_return_type' => false, @@ -1208,7 +1278,7 @@ $rules = [ * Risky! * Risky when the function `pow` is overridden. */ - 'pow_to_exponentiation' => false, + 'pow_to_exponentiation' => true, /* * Converts `protected` variables and methods to `private` where @@ -1225,16 +1295,7 @@ $rules = [ * This fixer may change your class name, which will break the code * that depends on the old name. */ - 'psr0' => false, - - /* - * Class names should match the file name. - * - * Risky! - * This fixer may change your class name, which will break the code - * that depends on the old name. - */ - 'psr4' => true, + 'psr_autoloading' => false, /* * Replaces `rand`, `srand`, `getrandmax` functions calls with their @@ -1245,12 +1306,23 @@ $rules = [ */ 'random_api_migration' => [ 'replacements' => [ - 'getrandmax' => 'mt_getrandmax', - 'rand' => 'mt_rand', - 'srand' => 'mt_srand', + 'mt_rand' => 'random_int', + 'rand' => 'random_int', ], ], + /* + * Callables must be called without using `call_user_func*` when + * possible. + * + * Risky! + * Risky when the `call_user_func` or `call_user_func_array` + * function is overridden or when are used in constructions that + * should be avoided, like `call_user_func_array('foo', ['bar' => + * 'baz'])` or `call_user_func($foo, $foo = 'bar')`. + */ + 'regular_callable_call' => true, + /* * Local, dynamic and directly referenced variables should not be * assigned and directly returned by a function or method. @@ -1263,7 +1335,7 @@ $rules = [ * * Rule is applied only in a PHP 7+ environment. */ - 'return_type_declaration' => false, + 'return_type_declaration' => true, /* * Inside class or interface element `self` should be preferred to @@ -1309,6 +1381,12 @@ $rules = [ */ 'simple_to_complex_string_variable' => true, + /* + * Simplify `if` control structures that return the boolean result + * of their condition. + */ + 'simplified_if_return' => true, + /* * A return statement wishing to return `void` should not return * `null`. @@ -1356,6 +1434,9 @@ $rules = [ 'strings_containing_single_quote_chars' => false, ], + // Ensures a single space after language constructs. + 'single_space_after_construct' => true, + // Each trait `use` must be done as single statement. 'single_trait_insert_per_statement' => true, @@ -1414,17 +1495,32 @@ $rules = [ // Removes extra spaces between colon and case value. 'switch_case_space' => true, + // Switch case must not be ended with `continue` but with `break`. + 'switch_continue_to_break' => true, + // Standardize spaces around ternary operator. 'ternary_operator_spaces' => true, + /* + * Use the Elvis operator `?:` where possible. + * + * Risky! + * Risky when relying on functions called on both sides of the `?` + * operator. + */ + 'ternary_to_elvis_operator' => true, + /* * Use `null` coalescing operator `??` where possible. Requires PHP * >= 7.0. */ - 'ternary_to_null_coalescing' => false, + 'ternary_to_null_coalescing' => true, - // PHP multi-line arrays should have a trailing comma. - 'trailing_comma_in_multiline_array' => true, + /* + * Multi-line arrays, arguments list and parameters list must have a + * trailing comma. + */ + 'trailing_comma_in_multiline' => true, /* * Arrays should be formatted like function/method arguments, @@ -1435,12 +1531,27 @@ $rules = [ // Unary operators should be placed adjacent to their operands. 'unary_operator_spaces' => true, + /* + * Anonymous functions with one-liner return statement must use + * arrow functions. + * + * Risky! + * Risky when using `isset()` on outside variables that are not + * imported with `use ()`. + */ + 'use_arrow_functions' => false, + /* * Visibility MUST be declared on all properties and methods; * `abstract` and `final` MUST be declared before the visibility; * `static` MUST be declared after the visibility. */ - 'visibility_required' => true, + 'visibility_required' => [ + 'elements' => [ + 'method', + 'property', + ], + ], /* * Add `void` return type to functions with missing or empty return @@ -1459,8 +1570,10 @@ $rules = [ 'whitespace_after_comma_in_array' => true, /* - * Write conditions in Yoda style (`true`), non-Yoda style (`false`) - * or ignore those conditions (`null`) based on configuration. + * Write conditions in Yoda style (`true`), non-Yoda style + * (`['equal' => false, 'identical' => false, 'less_and_greater' => + * false]`) or ignore those conditions (`null`) based on + * configuration. */ 'yoda_style' => [ 'equal' => false, @@ -1477,7 +1590,7 @@ if (\PHP_SAPI === 'cli' && !class_exists(\PhpCsFixer\Config::class)) { } $dryRun = !in_array('--force', $_SERVER['argv'], true); - $command = escapeshellarg($binFixer) . ' fix --config ' . escapeshellarg(__FILE__) . ' --diff-format udiff --ansi -vv'; + $command = escapeshellarg($binFixer) . ' fix --config ' . escapeshellarg(__FILE__) . ' --diff --ansi -vv'; if ($dryRun) { $command .= ' --dry-run'; @@ -1498,13 +1611,14 @@ if (\PHP_SAPI === 'cli' && !class_exists(\PhpCsFixer\Config::class)) { exit($returnCode); } -return \PhpCsFixer\Config::create() +return (new \PhpCsFixer\Config()) ->setUsingCache(true) - ->setCacheFile(__DIR__ . '/.php_cs.cache') + ->setCacheFile(__DIR__ . '/.php-cs-fixer.cache') ->setRules($rules) ->setRiskyAllowed(true) ->setFinder( \PhpCsFixer\Finder::create() + ->ignoreUnreadableDirs() ->in(__DIR__) ) ; diff --git a/README.RU.md b/README.RU.md index 0b90797..54b6f1f 100644 --- a/README.RU.md +++ b/README.RU.md @@ -1,16 +1,22 @@ -`PhpZip` -======== +

PhpZip

+ `PhpZip` - php библиотека для продвинутой работы с ZIP-архивами. -[![Build Status](https://travis-ci.org/Ne-Lexa/php-zip.svg?branch=master)](https://travis-ci.org/Ne-Lexa/php-zip) +[![Packagist Version](https://img.shields.io/packagist/v/nelexa/zip.svg)](https://packagist.org/packages/nelexa/zip) +[![Packagist Downloads](https://img.shields.io/packagist/dt/nelexa/zip.svg?color=%23ff007f)](https://packagist.org/packages/nelexa/zip) [![Code Coverage](https://scrutinizer-ci.com/g/Ne-Lexa/php-zip/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/Ne-Lexa/php-zip/?branch=master) -[![Latest Stable Version](https://poser.pugx.org/nelexa/zip/v/stable)](https://packagist.org/packages/nelexa/zip) -[![Total Downloads](https://poser.pugx.org/nelexa/zip/downloads)](https://packagist.org/packages/nelexa/zip) -[![Minimum PHP Version](http://img.shields.io/badge/php-%3E%3D%205.5-8892BF.svg)](https://php.net/) -[![License](https://poser.pugx.org/nelexa/zip/license)](https://packagist.org/packages/nelexa/zip) +[![Build Status](https://github.com/Ne-Lexa/php-zip/workflows/build/badge.svg)](https://github.com/Ne-Lexa/php-zip/actions) +[![License](https://img.shields.io/packagist/l/nelexa/zip.svg)](https://github.com/Ne-Lexa/php-zip/blob/master/LICENSE) [English Documentation](README.md) +### Версии и зависимости +| Версия | PHP | Документация | +| --------------- | ------------ | ----------------------------------------------------------------------------- | +| ^4.0 (master) | ^7.4 \| ^8.0 | [Документация v4.0](https://github.com/Ne-Lexa/php-zip/blob/master/README.md) | +| 3.4.* | ^7.1 \| ^8.0 | текущая документация | +| 3.0.* - 3.3.* | ^5.5 \| ^7.0 | [Документация v3.3](https://github.com/Ne-Lexa/php-zip/blob/3.3.3/README.md) | + Содержание ---------- - [Функционал](#Features) diff --git a/README.md b/README.md index 44ea792..b1ebc44 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,22 @@ -`PhpZip` -======== +

PhpZip

+ `PhpZip` is a php-library for extended work with ZIP-archives. -[![Build Status](https://travis-ci.org/Ne-Lexa/php-zip.svg?branch=master)](https://travis-ci.org/Ne-Lexa/php-zip) +[![Packagist Version](https://img.shields.io/packagist/v/nelexa/zip.svg)](https://packagist.org/packages/nelexa/zip) +[![Packagist Downloads](https://img.shields.io/packagist/dt/nelexa/zip.svg?color=%23ff007f)](https://packagist.org/packages/nelexa/zip) [![Code Coverage](https://scrutinizer-ci.com/g/Ne-Lexa/php-zip/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/Ne-Lexa/php-zip/?branch=master) -[![Latest Stable Version](https://poser.pugx.org/nelexa/zip/v/stable)](https://packagist.org/packages/nelexa/zip) -[![Total Downloads](https://poser.pugx.org/nelexa/zip/downloads)](https://packagist.org/packages/nelexa/zip) -[![Minimum PHP Version](http://img.shields.io/badge/php-%3E%3D%205.5-8892BF.svg)](https://php.net/) -[![License](https://poser.pugx.org/nelexa/zip/license)](https://packagist.org/packages/nelexa/zip) +[![Build Status](https://github.com/Ne-Lexa/php-zip/workflows/build/badge.svg)](https://github.com/Ne-Lexa/php-zip/actions) +[![License](https://img.shields.io/packagist/l/nelexa/zip.svg)](https://github.com/Ne-Lexa/php-zip/blob/master/LICENSE) [Russian Documentation](README.RU.md) +### Versions & Dependencies +| Version | PHP | Documentation | +| --------------- | ------------ | --------------------------------------------------------------------- | +| ^4.0 (master) | ^7.4 \| ^8.0 | [Docs v4.0](https://github.com/Ne-Lexa/php-zip/blob/master/README.md) | +| 3.4.* | ^7.1 \| ^8.0 | current docs | +| 3.0.* - 3.3.* | ^5.5 \| ^7.0 | [Docs v3.3](https://github.com/Ne-Lexa/php-zip/blob/3.3.3/README.md) | + Table of contents ----------------- - [Features](#Features) diff --git a/bootstrap.php b/bootstrap.php deleted file mode 100644 index 1b1b713..0000000 --- a/bootstrap.php +++ /dev/null @@ -1,6 +0,0 @@ - \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml index cbb13f5..d03e079 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,10 +1,9 @@ + bootstrap="vendor/autoload.php"> diff --git a/src/Constants/ZipCompressionMethod.php b/src/Constants/ZipCompressionMethod.php index 7841ccc..c46aa3c 100644 --- a/src/Constants/ZipCompressionMethod.php +++ b/src/Constants/ZipCompressionMethod.php @@ -56,9 +56,8 @@ final class ZipCompressionMethod */ public static function getCompressionMethodName($value) { - return isset(self::$ZIP_COMPRESSION_METHODS[$value]) ? - self::$ZIP_COMPRESSION_METHODS[$value] : - 'Unknown Method'; + return self::$ZIP_COMPRESSION_METHODS[$value] + ?? 'Unknown Method'; } /** diff --git a/src/Constants/ZipEncryptionMethod.php b/src/Constants/ZipEncryptionMethod.php index 0c25a4c..da7a5e6 100644 --- a/src/Constants/ZipEncryptionMethod.php +++ b/src/Constants/ZipEncryptionMethod.php @@ -41,9 +41,8 @@ final class ZipEncryptionMethod { $value = (int) $value; - return isset(self::$ENCRYPTION_METHODS[$value]) ? - self::$ENCRYPTION_METHODS[$value] : - 'Unknown Encryption Method'; + return self::$ENCRYPTION_METHODS[$value] + ?? 'Unknown Encryption Method'; } /** diff --git a/src/Constants/ZipPlatform.php b/src/Constants/ZipPlatform.php index f8085f7..3071ae4 100644 --- a/src/Constants/ZipPlatform.php +++ b/src/Constants/ZipPlatform.php @@ -48,6 +48,6 @@ final class ZipPlatform */ public static function getPlatformName($platform) { - return isset(self::$platforms[$platform]) ? self::$platforms[$platform] : 'Unknown'; + return self::$platforms[$platform] ?? 'Unknown'; } } diff --git a/src/IO/Filter/Cipher/Pkware/PKCryptContext.php b/src/IO/Filter/Cipher/Pkware/PKCryptContext.php index bffa4d6..0b9d23b 100644 --- a/src/IO/Filter/Cipher/Pkware/PKCryptContext.php +++ b/src/IO/Filter/Cipher/Pkware/PKCryptContext.php @@ -328,7 +328,7 @@ class PKCryptContext } if ($byte !== $checkByte) { - throw new ZipAuthenticationException(sprintf('Invalid password')); + throw new ZipAuthenticationException('Invalid password'); } } diff --git a/src/IO/Filter/Cipher/Pkware/PKEncryptionStreamFilter.php b/src/IO/Filter/Cipher/Pkware/PKEncryptionStreamFilter.php index cd54145..7440fa7 100644 --- a/src/IO/Filter/Cipher/Pkware/PKEncryptionStreamFilter.php +++ b/src/IO/Filter/Cipher/Pkware/PKEncryptionStreamFilter.php @@ -66,9 +66,9 @@ class PKEncryptionStreamFilter extends \php_user_filter // init keys $this->context = new PKCryptContext($password); - $crc = $entry->isDataDescriptorRequired() || $entry->getCrc() === ZipEntry::UNKNOWN ? - ($entry->getDosTime() & 0x0000ffff) << 16 : - $entry->getCrc(); + $crc = $entry->isDataDescriptorRequired() || $entry->getCrc() === ZipEntry::UNKNOWN + ? ($entry->getDosTime() & 0x0000ffff) << 16 + : $entry->getCrc(); try { $headerBytes = random_bytes(PKCryptContext::STD_DEC_HDR_SIZE); diff --git a/src/IO/Filter/Cipher/WinZipAes/WinZipAesDecryptionStreamFilter.php b/src/IO/Filter/Cipher/WinZipAes/WinZipAesDecryptionStreamFilter.php index 7839172..987da48 100644 --- a/src/IO/Filter/Cipher/WinZipAes/WinZipAesDecryptionStreamFilter.php +++ b/src/IO/Filter/Cipher/WinZipAes/WinZipAesDecryptionStreamFilter.php @@ -60,9 +60,9 @@ class WinZipAesDecryptionStreamFilter extends \php_user_filter $this->entry = $this->params['entry']; if ( - $this->entry->getPassword() === null || - !$this->entry->isEncrypted() || - !$this->entry->hasExtraField(WinZipAesExtraField::HEADER_ID) + $this->entry->getPassword() === null + || !$this->entry->isEncrypted() + || !$this->entry->hasExtraField(WinZipAesExtraField::HEADER_ID) ) { return false; } @@ -156,8 +156,8 @@ class WinZipAesDecryptionStreamFilter extends \php_user_filter $this->encBlockPosition += $offset; if ( - $this->encBlockPosition === $this->encBlockLength && - \strlen($this->buffer) === WinZipAesContext::FOOTER_SIZE + $this->encBlockPosition === $this->encBlockLength + && \strlen($this->buffer) === WinZipAesContext::FOOTER_SIZE ) { $this->authenticationCode = $this->buffer; $this->buffer = ''; diff --git a/src/IO/Filter/Cipher/WinZipAes/WinZipAesEncryptionStreamFilter.php b/src/IO/Filter/Cipher/WinZipAes/WinZipAesEncryptionStreamFilter.php index 12d12fe..9191b62 100644 --- a/src/IO/Filter/Cipher/WinZipAes/WinZipAesEncryptionStreamFilter.php +++ b/src/IO/Filter/Cipher/WinZipAes/WinZipAesEncryptionStreamFilter.php @@ -53,9 +53,9 @@ class WinZipAesEncryptionStreamFilter extends \php_user_filter $this->entry = $this->params['entry']; if ( - $this->entry->getPassword() === null || - !$this->entry->isEncrypted() || - !$this->entry->hasExtraField(WinZipAesExtraField::HEADER_ID) + $this->entry->getPassword() === null + || !$this->entry->isEncrypted() + || !$this->entry->hasExtraField(WinZipAesExtraField::HEADER_ID) ) { return false; } diff --git a/src/IO/Stream/ResponseStream.php b/src/IO/Stream/ResponseStream.php index e016103..6ee10fc 100644 --- a/src/IO/Stream/ResponseStream.php +++ b/src/IO/Stream/ResponseStream.php @@ -87,27 +87,11 @@ class ResponseStream implements StreamInterface } /** - * Get stream metadata as an associative array or retrieve a specific key. - * - * The keys returned are identical to the keys returned from PHP's - * stream_get_meta_data() function. - * - * @see http://php.net/manual/en/function.stream-get-meta-data.php - * - * @param string $key specific metadata to retrieve - * - * @return array|mixed|null Returns an associative array if no key is - * provided. Returns a specific key value if a key is provided and the - * value is found, or null if the key is not found. + * Closes the stream when the destructed. */ - public function getMetadata($key = null) + public function __destruct() { - if (!$this->stream) { - return $key ? null : []; - } - $meta = stream_get_meta_data($this->stream); - - return isset($meta[$key]) ? $meta[$key] : null; + $this->close(); } /** @@ -135,6 +119,30 @@ class ResponseStream implements StreamInterface return (string) stream_get_contents($this->stream); } + /** + * Get stream metadata as an associative array or retrieve a specific key. + * + * The keys returned are identical to the keys returned from PHP's + * stream_get_meta_data() function. + * + * @see http://php.net/manual/en/function.stream-get-meta-data.php + * + * @param string $key specific metadata to retrieve + * + * @return array|mixed|null Returns an associative array if no key is + * provided. Returns a specific key value if a key is provided and the + * value is found, or null if the key is not found. + */ + public function getMetadata($key = null) + { + if (!$this->stream) { + return $key ? null : []; + } + $meta = stream_get_meta_data($this->stream); + + return $meta[$key] ?? null; + } + /** * Seek to the beginning of the stream. * @@ -163,7 +171,7 @@ class ResponseStream implements StreamInterface } if (!$this->stream) { - return null; + return; } // Clear the stat cache if the stream has a URI if ($this->uri !== null) { @@ -176,8 +184,6 @@ class ResponseStream implements StreamInterface return $this->size; } - - return null; } /** @@ -297,14 +303,6 @@ class ResponseStream implements StreamInterface return $this->stream ? stream_get_contents($this->stream) : ''; } - /** - * Closes the stream when the destructed. - */ - public function __destruct() - { - $this->close(); - } - /** * Closes the stream and any underlying resources. */ diff --git a/src/IO/ZipReader.php b/src/IO/ZipReader.php index f445bf8..55047c0 100644 --- a/src/IO/ZipReader.php +++ b/src/IO/ZipReader.php @@ -59,7 +59,7 @@ class ZipReader } $meta = stream_get_meta_data($inStream); - $wrapperType = isset($meta['wrapper_type']) ? $meta['wrapper_type'] : 'Unknown'; + $wrapperType = $meta['wrapper_type'] ?? 'Unknown'; $supportStreamWrapperTypes = ['plainfile', 'PHP', 'user-space']; if (!\in_array($wrapperType, $supportStreamWrapperTypes, true)) { @@ -72,10 +72,10 @@ class ZipReader } if ( - $wrapperType === 'plainfile' && - ( - $meta['stream_type'] === 'dir' || - (isset($meta['uri']) && is_dir($meta['uri'])) + $wrapperType === 'plainfile' + && ( + $meta['stream_type'] === 'dir' + || (isset($meta['uri']) && is_dir($meta['uri'])) ) ) { throw new InvalidArgumentException('Directory stream not supported'); @@ -94,6 +94,11 @@ class ZipReader $this->options = $options; } + public function __destruct() + { + $this->close(); + } + /** * @return array */ @@ -162,15 +167,15 @@ class ZipReader $buffer = fread($this->inStream, $sizeECD); $unpack = unpack( - 'vdiskNo/vcdDiskNo/vcdEntriesDisk/' . - 'vcdEntries/VcdSize/VcdPos/vcommentLength', + 'vdiskNo/vcdDiskNo/vcdEntriesDisk/' + . 'vcdEntries/VcdSize/VcdPos/vcommentLength', substr($buffer, 0, 18) ); if ( - $unpack['diskNo'] !== 0 || - $unpack['cdDiskNo'] !== 0 || - $unpack['cdEntriesDisk'] !== $unpack['cdEntries'] + $unpack['diskNo'] !== 0 + || $unpack['cdDiskNo'] !== 0 + || $unpack['cdEntriesDisk'] !== $unpack['cdEntries'] ) { throw new ZipException( 'ZIP file spanning/splitting is not supported!' @@ -375,8 +380,8 @@ class ZipReader $unicodePath = str_replace('\\', '/', $unicodePath); if ( - $unicodePath !== '' && - substr_count($entryName, '/') === substr_count($unicodePath, '/') + $unicodePath !== '' + && substr_count($entryName, '/') === substr_count($unicodePath, '/') ) { $entryName = $unicodePath; } @@ -427,12 +432,12 @@ class ZipReader } $unpack = unpack( - 'vversionMadeBy/vversionNeededToExtract/' . - 'vgeneralPurposeBitFlag/vcompressionMethod/' . - 'VlastModFile/Vcrc/VcompressedSize/' . - 'VuncompressedSize/vfileNameLength/vextraFieldLength/' . - 'vfileCommentLength/vdiskNumberStart/vinternalFileAttributes/' . - 'VexternalFileAttributes/VoffsetLocalHeader', + 'vversionMadeBy/vversionNeededToExtract/' + . 'vgeneralPurposeBitFlag/vcompressionMethod/' + . 'VlastModFile/Vcrc/VcompressedSize/' + . 'VuncompressedSize/vfileNameLength/vextraFieldLength/' + . 'vfileCommentLength/vdiskNumberStart/vinternalFileAttributes/' + . 'VexternalFileAttributes/VoffsetLocalHeader', fread($stream, 42) ); @@ -523,9 +528,9 @@ class ZipReader */ protected function parseExtraFields($buffer, ZipEntry $zipEntry, $local = false) { - $collection = $local ? - $zipEntry->getLocalExtraFields() : - $zipEntry->getCdExtraFields(); + $collection = $local + ? $zipEntry->getLocalExtraFields() + : $zipEntry->getCdExtraFields(); if (!empty($buffer)) { $pos = 0; @@ -548,9 +553,9 @@ class ZipReader try { if ($className !== null) { try { - $extraField = $local ? - \call_user_func([$className, 'unpackLocalFileData'], $bufferData, $zipEntry) : - \call_user_func([$className, 'unpackCentralDirData'], $bufferData, $zipEntry); + $extraField = $local + ? \call_user_func([$className, 'unpackLocalFileData'], $bufferData, $zipEntry) + : \call_user_func([$className, 'unpackCentralDirData'], $bufferData, $zipEntry); } catch (\Throwable $e) { // skip errors while parsing invalid data continue; @@ -890,9 +895,4 @@ class ZipReader fclose($this->inStream); } } - - public function __destruct() - { - $this->close(); - } } diff --git a/src/IO/ZipWriter.php b/src/IO/ZipWriter.php index b5cc8a8..c3f6f6f 100644 --- a/src/IO/ZipWriter.php +++ b/src/IO/ZipWriter.php @@ -105,8 +105,8 @@ class ZipWriter $entry->enableDataDescriptor(true); } - $dd = $entry->isDataDescriptorRequired() || - $entry->isDataDescriptorEnabled(); + $dd = $entry->isDataDescriptorRequired() + || $entry->isDataDescriptorEnabled(); $compressedSize = $entry->getCompressedSize(); $uncompressedSize = $entry->getUncompressedSize(); @@ -232,20 +232,20 @@ class ZipWriter $offset = ftell($outStream); - $dataMinStartOffset = - $offset + - ZipConstants::LFH_FILENAME_POS + - $extraLength + - $nameLength; + $dataMinStartOffset + = $offset + + ZipConstants::LFH_FILENAME_POS + + $extraLength + + $nameLength; - $padding = - ($multiple - ($dataMinStartOffset % $multiple)) + $padding + = ($multiple - ($dataMinStartOffset % $multiple)) % $multiple; if ($padding > 0) { $dataMinStartOffset += ApkAlignmentExtraField::MIN_SIZE; - $padding = - ($multiple - ($dataMinStartOffset % $multiple)) + $padding + = ($multiple - ($dataMinStartOffset % $multiple)) % $multiple; $entry->getLocalExtraFields()->add( @@ -268,9 +268,9 @@ class ZipWriter protected function getExtraFieldsContents(ZipEntry $entry, $local) { $local = (bool) $local; - $collection = $local ? - $entry->getLocalExtraFields() : - $entry->getCdExtraFields(); + $collection = $local + ? $entry->getLocalExtraFields() + : $entry->getCdExtraFields(); $extraData = ''; foreach ($collection as $extraField) { @@ -490,6 +490,7 @@ class ZipWriter ))) { throw new \RuntimeException('Could not append filter "zlib.deflate" to out stream'); } + break; case ZipCompressionMethod::BZIP2: @@ -501,6 +502,7 @@ class ZipWriter ))) { throw new \RuntimeException('Could not append filter "bzip2.compress" to out stream'); } + break; case ZipCompressionMethod::STORED: @@ -585,14 +587,14 @@ class ZipWriter ); if ( - $entry->isZip64ExtensionsRequired() || - $entry->getLocalExtraFields()->has(Zip64ExtraField::HEADER_ID) + $entry->isZip64ExtensionsRequired() + || $entry->getLocalExtraFields()->has(Zip64ExtraField::HEADER_ID) ) { - $dd = + $dd // compressed size 8 bytes - PackUtil::packLongLE($entry->getCompressedSize()) . + = PackUtil::packLongLE($entry->getCompressedSize()) // uncompressed size 8 bytes - PackUtil::packLongLE($entry->getUncompressedSize()); + . PackUtil::packLongLE($entry->getUncompressedSize()); } else { $dd = pack( 'VV', @@ -635,9 +637,9 @@ class ZipWriter $entry->getCdExtraFields()->remove(Zip64ExtraField::HEADER_ID); if ( - $localHeaderOffset > ZipConstants::ZIP64_MAGIC || - $compressedSize > ZipConstants::ZIP64_MAGIC || - $uncompressedSize > ZipConstants::ZIP64_MAGIC + $localHeaderOffset > ZipConstants::ZIP64_MAGIC + || $compressedSize > ZipConstants::ZIP64_MAGIC + || $uncompressedSize > ZipConstants::ZIP64_MAGIC ) { $zip64ExtraField = new Zip64ExtraField(); @@ -814,16 +816,16 @@ class ZipWriter $outStream, // total number of entries in the // central directory on this disk 8 bytes - PackUtil::packLongLE($cdEntriesCount) . + PackUtil::packLongLE($cdEntriesCount) // total number of entries in the // central directory 8 bytes - PackUtil::packLongLE($cdEntriesCount) . + . PackUtil::packLongLE($cdEntriesCount) // size of the central directory 8 bytes - PackUtil::packLongLE($centralDirectorySize) . + . PackUtil::packLongLE($centralDirectorySize) // offset of start of central // directory with respect to // the starting disk number 8 bytes - PackUtil::packLongLE($centralDirectoryOffset) + . PackUtil::packLongLE($centralDirectoryOffset) ); // write zip64 end of central directory locator @@ -838,12 +840,12 @@ class ZipWriter // start of the zip64 end of // central directory 4 bytes 0 - ) . + ) // relative offset of the zip64 // end of central directory record 8 bytes - PackUtil::packLongLE($zip64EndOfCentralDirectoryOffset) . + . PackUtil::packLongLE($zip64EndOfCentralDirectoryOffset) // total number of disks 4 bytes - pack('V', 1) + . pack('V', 1) ); } diff --git a/src/Model/Data/ZipNewData.php b/src/Model/Data/ZipNewData.php index e149638..b60b039 100644 --- a/src/Model/Data/ZipNewData.php +++ b/src/Model/Data/ZipNewData.php @@ -51,10 +51,44 @@ class ZipNewData implements ZipData } $resourceId = (int) $this->stream; - self::$guardClonedStream[$resourceId] = - isset(self::$guardClonedStream[$resourceId]) ? - self::$guardClonedStream[$resourceId] + 1 : - 0; + self::$guardClonedStream[$resourceId] + = isset(self::$guardClonedStream[$resourceId]) + ? self::$guardClonedStream[$resourceId] + 1 + : 0; + } + + /** + * The stream will be closed when closing the zip archive. + * + * The method implements protection against closing the stream of the cloned object. + * + * @see ZipFile::close() + */ + public function __destruct() + { + $resourceId = (int) $this->stream; + + if (isset(self::$guardClonedStream[$resourceId]) && self::$guardClonedStream[$resourceId] > 0) { + self::$guardClonedStream[$resourceId]--; + + return; + } + + if (\is_resource($this->stream)) { + fclose($this->stream); + } + } + + /** + * @see https://php.net/manual/en/language.oop5.cloning.php + */ + public function __clone() + { + $resourceId = (int) $this->stream; + self::$guardClonedStream[$resourceId] + = isset(self::$guardClonedStream[$resourceId]) + ? self::$guardClonedStream[$resourceId] + 1 + : 1; } /** @@ -95,38 +129,4 @@ class ZipNewData implements ZipData rewind($stream); stream_copy_to_stream($stream, $outStream); } - - /** - * @see https://php.net/manual/en/language.oop5.cloning.php - */ - public function __clone() - { - $resourceId = (int) $this->stream; - self::$guardClonedStream[$resourceId] = - isset(self::$guardClonedStream[$resourceId]) ? - self::$guardClonedStream[$resourceId] + 1 : - 1; - } - - /** - * The stream will be closed when closing the zip archive. - * - * The method implements protection against closing the stream of the cloned object. - * - * @see ZipFile::close() - */ - public function __destruct() - { - $resourceId = (int) $this->stream; - - if (isset(self::$guardClonedStream[$resourceId]) && self::$guardClonedStream[$resourceId] > 0) { - self::$guardClonedStream[$resourceId]--; - - return; - } - - if (\is_resource($this->stream)) { - fclose($this->stream); - } - } } diff --git a/src/Model/Data/ZipSourceFileData.php b/src/Model/Data/ZipSourceFileData.php index c53df05..6bbdb31 100644 --- a/src/Model/Data/ZipSourceFileData.php +++ b/src/Model/Data/ZipSourceFileData.php @@ -47,6 +47,16 @@ class ZipSourceFileData implements ZipData $this->uncompressedSize = $zipEntry->getUncompressedSize(); } + /** + * {@inheritDoc} + */ + public function __destruct() + { + if (\is_resource($this->stream)) { + fclose($this->stream); + } + } + /** * @param ZipEntry $entry * @@ -54,14 +64,14 @@ class ZipSourceFileData implements ZipData */ public function hasRecompressData(ZipEntry $entry) { - return $this->sourceEntry->getCompressionLevel() !== $entry->getCompressionLevel() || - $this->sourceEntry->getCompressionMethod() !== $entry->getCompressionMethod() || - $this->sourceEntry->isEncrypted() !== $entry->isEncrypted() || - $this->sourceEntry->getEncryptionMethod() !== $entry->getEncryptionMethod() || - $this->sourceEntry->getPassword() !== $entry->getPassword() || - $this->sourceEntry->getCompressedSize() !== $entry->getCompressedSize() || - $this->sourceEntry->getUncompressedSize() !== $entry->getUncompressedSize() || - $this->sourceEntry->getCrc() !== $entry->getCrc(); + return $this->sourceEntry->getCompressionLevel() !== $entry->getCompressionLevel() + || $this->sourceEntry->getCompressionMethod() !== $entry->getCompressionMethod() + || $this->sourceEntry->isEncrypted() !== $entry->isEncrypted() + || $this->sourceEntry->getEncryptionMethod() !== $entry->getEncryptionMethod() + || $this->sourceEntry->getPassword() !== $entry->getPassword() + || $this->sourceEntry->getCompressedSize() !== $entry->getCompressedSize() + || $this->sourceEntry->getUncompressedSize() !== $entry->getUncompressedSize() + || $this->sourceEntry->getCrc() !== $entry->getCrc(); } /** @@ -159,14 +169,4 @@ class ZipSourceFileData implements ZipData { return $this->offset; } - - /** - * {@inheritdoc} - */ - public function __destruct() - { - if (\is_resource($this->stream)) { - fclose($this->stream); - } - } } diff --git a/src/Model/Extra/ExtraFieldsCollection.php b/src/Model/Extra/ExtraFieldsCollection.php index 9cc2020..8043a49 100644 --- a/src/Model/Extra/ExtraFieldsCollection.php +++ b/src/Model/Extra/ExtraFieldsCollection.php @@ -18,6 +18,30 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator */ protected $collection = []; + /** + * @return string + */ + public function __toString() + { + $formats = []; + + foreach ($this->collection as $key => $value) { + $formats[] = (string) $value; + } + + return implode("\n", $formats); + } + + /** + * If clone extra fields. + */ + public function __clone() + { + foreach ($this->collection as $k => $v) { + $this->collection[$k] = clone $v; + } + } + /** * Returns the number of Extra Fields in this collection. * @@ -41,7 +65,7 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator { $this->validateHeaderId($headerId); - return isset($this->collection[$headerId]) ? $this->collection[$headerId] : null; + return $this->collection[$headerId] ?? null; } /** @@ -128,8 +152,6 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator return $ef; } - - return null; } /** @@ -157,7 +179,7 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator */ public function offsetGet($offset) { - return isset($this->collection[$offset]) ? $this->collection[$offset] : null; + return $this->collection[$offset] ?? null; } /** @@ -249,28 +271,4 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator { $this->collection = []; } - - /** - * @return string - */ - public function __toString() - { - $formats = []; - - foreach ($this->collection as $key => $value) { - $formats[] = (string) $value; - } - - return implode("\n", $formats); - } - - /** - * If clone extra fields. - */ - public function __clone() - { - foreach ($this->collection as $k => $v) { - $this->collection[$k] = clone $v; - } - } } diff --git a/src/Model/Extra/Fields/AbstractUnicodeExtraField.php b/src/Model/Extra/Fields/AbstractUnicodeExtraField.php index dd6f566..759ae31 100644 --- a/src/Model/Extra/Fields/AbstractUnicodeExtraField.php +++ b/src/Model/Extra/Fields/AbstractUnicodeExtraField.php @@ -116,8 +116,8 @@ abstract class AbstractUnicodeExtraField implements ZipExtraField 'CV', self::DEFAULT_VERSION, $this->crc32 - ) . - $this->unicodeValue; + ) + . $this->unicodeValue; } /** diff --git a/src/Model/Extra/Fields/ApkAlignmentExtraField.php b/src/Model/Extra/Fields/ApkAlignmentExtraField.php index 69c26b8..3f6192e 100644 --- a/src/Model/Extra/Fields/ApkAlignmentExtraField.php +++ b/src/Model/Extra/Fields/ApkAlignmentExtraField.php @@ -50,6 +50,19 @@ class ApkAlignmentExtraField implements ZipExtraField $this->padding = $padding; } + /** + * @return string + */ + public function __toString() + { + return sprintf( + '0x%04x APK Alignment: Multiple=%d Padding=%d', + self::HEADER_ID, + $this->multiple, + $this->padding + ); + } + /** * Returns the Header ID (type) of this Extra Field. * The Header ID is an unsigned short integer (two bytes) @@ -160,17 +173,4 @@ class ApkAlignmentExtraField implements ZipExtraField { return $this->packLocalFileData(); } - - /** - * @return string - */ - public function __toString() - { - return sprintf( - '0x%04x APK Alignment: Multiple=%d Padding=%d', - self::HEADER_ID, - $this->multiple, - $this->padding - ); - } } diff --git a/src/Model/Extra/Fields/AsiExtraField.php b/src/Model/Extra/Fields/AsiExtraField.php index 3bf62b9..cbbe596 100644 --- a/src/Model/Extra/Fields/AsiExtraField.php +++ b/src/Model/Extra/Fields/AsiExtraField.php @@ -85,6 +85,21 @@ class AsiExtraField implements ZipExtraField $this->link = $link; } + /** + * @return string + */ + public function __toString() + { + return sprintf( + '0x%04x ASI: Mode=%o UID=%d GID=%d Link="%s', + self::HEADER_ID, + $this->mode, + $this->uid, + $this->gid, + $this->link + ); + } + /** * Returns the Header ID (type) of this Extra Field. * The Header ID is an unsigned short integer (two bytes) @@ -284,19 +299,4 @@ class AsiExtraField implements ZipExtraField { $this->gid = (int) $gid; } - - /** - * @return string - */ - public function __toString() - { - return sprintf( - '0x%04x ASI: Mode=%o UID=%d GID=%d Link="%s', - self::HEADER_ID, - $this->mode, - $this->uid, - $this->gid, - $this->link - ); - } } diff --git a/src/Model/Extra/Fields/ExtendedTimestampExtraField.php b/src/Model/Extra/Fields/ExtendedTimestampExtraField.php index 909c783..e5fdc34 100644 --- a/src/Model/Extra/Fields/ExtendedTimestampExtraField.php +++ b/src/Model/Extra/Fields/ExtendedTimestampExtraField.php @@ -116,6 +116,32 @@ class ExtendedTimestampExtraField implements ZipExtraField $this->createTime = $createTime; } + /** + * @return string + */ + public function __toString() + { + $args = [self::HEADER_ID]; + $format = '0x%04x ExtendedTimestamp:'; + + if ($this->modifyTime !== null) { + $format .= ' Modify:[%s]'; + $args[] = date(\DATE_W3C, $this->modifyTime); + } + + if ($this->accessTime !== null) { + $format .= ' Access:[%s]'; + $args[] = date(\DATE_W3C, $this->accessTime); + } + + if ($this->createTime !== null) { + $format .= ' Create:[%s]'; + $args[] = date(\DATE_W3C, $this->createTime); + } + + return vsprintf($format, $args); + } + /** * @param int|null $modifyTime * @param int|null $accessTime @@ -414,33 +440,7 @@ class ExtendedTimestampExtraField implements ZipExtraField try { return $timestamp !== null ? new \DateTimeImmutable('@' . $timestamp) : null; } catch (\Exception $e) { - return null; + return; } } - - /** - * @return string - */ - public function __toString() - { - $args = [self::HEADER_ID]; - $format = '0x%04x ExtendedTimestamp:'; - - if ($this->modifyTime !== null) { - $format .= ' Modify:[%s]'; - $args[] = date(\DATE_W3C, $this->modifyTime); - } - - if ($this->accessTime !== null) { - $format .= ' Access:[%s]'; - $args[] = date(\DATE_W3C, $this->accessTime); - } - - if ($this->createTime !== null) { - $format .= ' Create:[%s]'; - $args[] = date(\DATE_W3C, $this->createTime); - } - - return vsprintf($format, $args); - } } diff --git a/src/Model/Extra/Fields/JarMarkerExtraField.php b/src/Model/Extra/Fields/JarMarkerExtraField.php index e1683aa..a138449 100644 --- a/src/Model/Extra/Fields/JarMarkerExtraField.php +++ b/src/Model/Extra/Fields/JarMarkerExtraField.php @@ -22,6 +22,14 @@ class JarMarkerExtraField implements ZipExtraField /** @var int Header id. */ const HEADER_ID = 0xCAFE; + /** + * @return string + */ + public function __toString() + { + return sprintf('0x%04x Jar Marker', self::HEADER_ID); + } + /** * @param ZipContainer $container */ @@ -107,12 +115,4 @@ class JarMarkerExtraField implements ZipExtraField { return self::unpackLocalFileData($buffer, $entry); } - - /** - * @return string - */ - public function __toString() - { - return sprintf('0x%04x Jar Marker', self::HEADER_ID); - } } diff --git a/src/Model/Extra/Fields/NewUnixExtraField.php b/src/Model/Extra/Fields/NewUnixExtraField.php index 807de72..bb8a5b2 100644 --- a/src/Model/Extra/Fields/NewUnixExtraField.php +++ b/src/Model/Extra/Fields/NewUnixExtraField.php @@ -73,6 +73,19 @@ class NewUnixExtraField implements ZipExtraField $this->gid = (int) $gid; } + /** + * @return string + */ + public function __toString() + { + return sprintf( + '0x%04x NewUnix: UID=%d GID=%d', + self::HEADER_ID, + $this->uid, + $this->gid + ); + } + /** * Returns the Header ID (type) of this Extra Field. * The Header ID is an unsigned short integer (two bytes) @@ -221,17 +234,4 @@ class NewUnixExtraField implements ZipExtraField { return $this->version; } - - /** - * @return string - */ - public function __toString() - { - return sprintf( - '0x%04x NewUnix: UID=%d GID=%d', - self::HEADER_ID, - $this->uid, - $this->gid - ); - } } diff --git a/src/Model/Extra/Fields/NtfsExtraField.php b/src/Model/Extra/Fields/NtfsExtraField.php index 213e925..70f1d1b 100644 --- a/src/Model/Extra/Fields/NtfsExtraField.php +++ b/src/Model/Extra/Fields/NtfsExtraField.php @@ -55,6 +55,32 @@ class NtfsExtraField implements ZipExtraField $this->createNtfsTime = (int) $createNtfsTime; } + /** + * @return string + */ + public function __toString() + { + $args = [self::HEADER_ID]; + $format = '0x%04x NtfsExtra:'; + + if ($this->modifyNtfsTime !== 0) { + $format .= ' Modify:[%s]'; + $args[] = $this->getModifyDateTime()->format(\DATE_ATOM); + } + + if ($this->accessNtfsTime !== 0) { + $format .= ' Access:[%s]'; + $args[] = $this->getAccessDateTime()->format(\DATE_ATOM); + } + + if ($this->createNtfsTime !== 0) { + $format .= ' Create:[%s]'; + $args[] = $this->getCreateDateTime()->format(\DATE_ATOM); + } + + return vsprintf($format, $args); + } + /** * @param \DateTimeInterface $modifyDateTime * @param \DateTimeInterface $accessDateTime @@ -310,30 +336,4 @@ class NtfsExtraField implements ZipExtraField return $dateTime; } - - /** - * @return string - */ - public function __toString() - { - $args = [self::HEADER_ID]; - $format = '0x%04x NtfsExtra:'; - - if ($this->modifyNtfsTime !== 0) { - $format .= ' Modify:[%s]'; - $args[] = $this->getModifyDateTime()->format(\DATE_ATOM); - } - - if ($this->accessNtfsTime !== 0) { - $format .= ' Access:[%s]'; - $args[] = $this->getAccessDateTime()->format(\DATE_ATOM); - } - - if ($this->createNtfsTime !== 0) { - $format .= ' Create:[%s]'; - $args[] = $this->getCreateDateTime()->format(\DATE_ATOM); - } - - return vsprintf($format, $args); - } } diff --git a/src/Model/Extra/Fields/OldUnixExtraField.php b/src/Model/Extra/Fields/OldUnixExtraField.php index 1f69487..95fac8d 100644 --- a/src/Model/Extra/Fields/OldUnixExtraField.php +++ b/src/Model/Extra/Fields/OldUnixExtraField.php @@ -84,6 +84,37 @@ class OldUnixExtraField implements ZipExtraField $this->gid = $gid; } + /** + * @return string + */ + public function __toString() + { + $args = [self::HEADER_ID]; + $format = '0x%04x OldUnix:'; + + if (($modifyTime = $this->getModifyDateTime()) !== null) { + $format .= ' Modify:[%s]'; + $args[] = $modifyTime->format(\DATE_ATOM); + } + + if (($accessTime = $this->getAccessDateTime()) !== null) { + $format .= ' Access:[%s]'; + $args[] = $accessTime->format(\DATE_ATOM); + } + + if ($this->uid !== null) { + $format .= ' UID=%d'; + $args[] = $this->uid; + } + + if ($this->gid !== null) { + $format .= ' GID=%d'; + $args[] = $this->gid; + } + + return vsprintf($format, $args); + } + /** * Returns the Header ID (type) of this Extra Field. * The Header ID is an unsigned short integer (two bytes) @@ -226,10 +257,10 @@ class OldUnixExtraField implements ZipExtraField public function getAccessDateTime() { try { - return $this->accessTime === null ? null : - new \DateTimeImmutable('@' . $this->accessTime); + return $this->accessTime === null ? null + : new \DateTimeImmutable('@' . $this->accessTime); } catch (\Exception $e) { - return null; + return; } } @@ -255,10 +286,10 @@ class OldUnixExtraField implements ZipExtraField public function getModifyDateTime() { try { - return $this->modifyTime === null ? null : - new \DateTimeImmutable('@' . $this->modifyTime); + return $this->modifyTime === null ? null + : new \DateTimeImmutable('@' . $this->modifyTime); } catch (\Exception $e) { - return null; + return; } } @@ -293,35 +324,4 @@ class OldUnixExtraField implements ZipExtraField { $this->gid = $gid; } - - /** - * @return string - */ - public function __toString() - { - $args = [self::HEADER_ID]; - $format = '0x%04x OldUnix:'; - - if (($modifyTime = $this->getModifyDateTime()) !== null) { - $format .= ' Modify:[%s]'; - $args[] = $modifyTime->format(\DATE_ATOM); - } - - if (($accessTime = $this->getAccessDateTime()) !== null) { - $format .= ' Access:[%s]'; - $args[] = $accessTime->format(\DATE_ATOM); - } - - if ($this->uid !== null) { - $format .= ' UID=%d'; - $args[] = $this->uid; - } - - if ($this->gid !== null) { - $format .= ' GID=%d'; - $args[] = $this->gid; - } - - return vsprintf($format, $args); - } } diff --git a/src/Model/Extra/Fields/UnicodeCommentExtraField.php b/src/Model/Extra/Fields/UnicodeCommentExtraField.php index d8280b6..b8aad46 100644 --- a/src/Model/Extra/Fields/UnicodeCommentExtraField.php +++ b/src/Model/Extra/Fields/UnicodeCommentExtraField.php @@ -50,18 +50,6 @@ class UnicodeCommentExtraField extends AbstractUnicodeExtraField { const HEADER_ID = 0x6375; - /** - * Returns the Header ID (type) of this Extra Field. - * The Header ID is an unsigned short integer (two bytes) - * which must be constant during the life cycle of this object. - * - * @return int - */ - public function getHeaderId() - { - return self::HEADER_ID; - } - /** * @return string */ @@ -73,4 +61,16 @@ class UnicodeCommentExtraField extends AbstractUnicodeExtraField $this->getUnicodeValue() ); } + + /** + * Returns the Header ID (type) of this Extra Field. + * The Header ID is an unsigned short integer (two bytes) + * which must be constant during the life cycle of this object. + * + * @return int + */ + public function getHeaderId() + { + return self::HEADER_ID; + } } diff --git a/src/Model/Extra/Fields/UnicodePathExtraField.php b/src/Model/Extra/Fields/UnicodePathExtraField.php index 047b2d0..4b982dd 100644 --- a/src/Model/Extra/Fields/UnicodePathExtraField.php +++ b/src/Model/Extra/Fields/UnicodePathExtraField.php @@ -51,18 +51,6 @@ class UnicodePathExtraField extends AbstractUnicodeExtraField { const HEADER_ID = 0x7075; - /** - * Returns the Header ID (type) of this Extra Field. - * The Header ID is an unsigned short integer (two bytes) - * which must be constant during the life cycle of this object. - * - * @return int - */ - public function getHeaderId() - { - return self::HEADER_ID; - } - /** * @return string */ @@ -74,4 +62,16 @@ class UnicodePathExtraField extends AbstractUnicodeExtraField $this->getUnicodeValue() ); } + + /** + * Returns the Header ID (type) of this Extra Field. + * The Header ID is an unsigned short integer (two bytes) + * which must be constant during the life cycle of this object. + * + * @return int + */ + public function getHeaderId() + { + return self::HEADER_ID; + } } diff --git a/src/Model/Extra/Fields/UnrecognizedExtraField.php b/src/Model/Extra/Fields/UnrecognizedExtraField.php index 699c193..fbc3550 100644 --- a/src/Model/Extra/Fields/UnrecognizedExtraField.php +++ b/src/Model/Extra/Fields/UnrecognizedExtraField.php @@ -29,6 +29,17 @@ class UnrecognizedExtraField implements ZipExtraField $this->data = (string) $data; } + /** + * @return string + */ + public function __toString() + { + $args = [$this->headerId, $this->data]; + $format = '0x%04x Unrecognized Extra Field: "%s"'; + + return vsprintf($format, $args); + } + /** * @param int $headerId */ @@ -72,7 +83,7 @@ class UnrecognizedExtraField implements ZipExtraField } /** - * {@inheritdoc} + * {@inheritDoc} */ public function packLocalFileData() { @@ -80,7 +91,7 @@ class UnrecognizedExtraField implements ZipExtraField } /** - * {@inheritdoc} + * {@inheritDoc} */ public function packCentralDirData() { @@ -102,15 +113,4 @@ class UnrecognizedExtraField implements ZipExtraField { $this->data = (string) $data; } - - /** - * @return string - */ - public function __toString() - { - $args = [$this->headerId, $this->data]; - $format = '0x%04x Unrecognized Extra Field: "%s"'; - - return vsprintf($format, $args); - } } diff --git a/src/Model/Extra/Fields/WinZipAesExtraField.php b/src/Model/Extra/Fields/WinZipAesExtraField.php index 0a50dca..1236551 100644 --- a/src/Model/Extra/Fields/WinZipAesExtraField.php +++ b/src/Model/Extra/Fields/WinZipAesExtraField.php @@ -96,6 +96,20 @@ class WinZipAesExtraField implements ZipExtraField $this->setCompressionMethod($compressionMethod); } + /** + * @return string + */ + public function __toString() + { + return sprintf( + '0x%04x WINZIP AES: VendorVersion=%d KeyStrength=0x%02x CompressionMethod=%s', + __CLASS__, + $this->vendorVersion, + $this->keyStrength, + $this->compressionMethod + ); + } + /** * @param ZipEntry $entry * @@ -118,11 +132,11 @@ class WinZipAesExtraField implements ZipExtraField // // https://www.winzip.com/win/en/aes_info.html $vendorVersion = ( - $entry->getUncompressedSize() < 20 || - $entry->getCompressionMethod() === ZipCompressionMethod::BZIP2 - ) ? - self::VERSION_AE2 : - self::VERSION_AE1; + $entry->getUncompressedSize() < 20 + || $entry->getCompressionMethod() === ZipCompressionMethod::BZIP2 + ) + ? self::VERSION_AE2 + : self::VERSION_AE1; $field = new self($vendorVersion, $keyStrength, $entry->getCompressionMethod()); @@ -370,18 +384,4 @@ class WinZipAesExtraField implements ZipExtraField { return (int) ($this->getEncryptionStrength() / 8 / 2); } - - /** - * @return string - */ - public function __toString() - { - return sprintf( - '0x%04x WINZIP AES: VendorVersion=%d KeyStrength=0x%02x CompressionMethod=%s', - __CLASS__, - $this->vendorVersion, - $this->keyStrength, - $this->compressionMethod - ); - } } diff --git a/src/Model/Extra/Fields/Zip64ExtraField.php b/src/Model/Extra/Fields/Zip64ExtraField.php index 4393a9c..d9569bb 100644 --- a/src/Model/Extra/Fields/Zip64ExtraField.php +++ b/src/Model/Extra/Fields/Zip64ExtraField.php @@ -51,6 +51,39 @@ class Zip64ExtraField implements ZipExtraField $this->diskStart = $diskStart; } + /** + * @return string + */ + public function __toString() + { + $args = [self::HEADER_ID]; + $format = '0x%04x ZIP64: '; + $formats = []; + + if ($this->uncompressedSize !== null) { + $formats[] = 'SIZE=%d'; + $args[] = $this->uncompressedSize; + } + + if ($this->compressedSize !== null) { + $formats[] = 'COMP_SIZE=%d'; + $args[] = $this->compressedSize; + } + + if ($this->localHeaderOffset !== null) { + $formats[] = 'OFFSET=%d'; + $args[] = $this->localHeaderOffset; + } + + if ($this->diskStart !== null) { + $formats[] = 'DISK_START=%d'; + $args[] = $this->diskStart; + } + $format .= implode(' ', $formats); + + return vsprintf($format, $args); + } + /** * Returns the Header ID (type) of this Extra Field. * The Header ID is an unsigned short integer (two bytes) @@ -275,37 +308,4 @@ class Zip64ExtraField implements ZipExtraField { $this->diskStart = $diskStart; } - - /** - * @return string - */ - public function __toString() - { - $args = [self::HEADER_ID]; - $format = '0x%04x ZIP64: '; - $formats = []; - - if ($this->uncompressedSize !== null) { - $formats[] = 'SIZE=%d'; - $args[] = $this->uncompressedSize; - } - - if ($this->compressedSize !== null) { - $formats[] = 'COMP_SIZE=%d'; - $args[] = $this->compressedSize; - } - - if ($this->localHeaderOffset !== null) { - $formats[] = 'OFFSET=%d'; - $args[] = $this->localHeaderOffset; - } - - if ($this->diskStart !== null) { - $formats[] = 'DISK_START=%d'; - $args[] = $this->diskStart; - } - $format .= implode(' ', $formats); - - return vsprintf($format, $args); - } } diff --git a/src/Model/Extra/ZipExtraDriver.php b/src/Model/Extra/ZipExtraDriver.php index e1332f0..ec04056 100644 --- a/src/Model/Extra/ZipExtraDriver.php +++ b/src/Model/Extra/ZipExtraDriver.php @@ -101,7 +101,5 @@ final class ZipExtraDriver if (isset(self::$implementations[$headerId])) { return self::$implementations[$headerId]; } - - return null; } } diff --git a/src/Model/Extra/ZipExtraField.php b/src/Model/Extra/ZipExtraField.php index ce69aaf..ef2219c 100644 --- a/src/Model/Extra/ZipExtraField.php +++ b/src/Model/Extra/ZipExtraField.php @@ -11,6 +11,11 @@ use PhpZip\Model\ZipEntry; */ interface ZipExtraField { + /** + * @return string + */ + public function __toString(); + /** * Returns the Header ID (type) of this Extra Field. * The Header ID is an unsigned short integer (two bytes) @@ -55,9 +60,4 @@ interface ZipExtraField * @return string the data */ public function packCentralDirData(); - - /** - * @return string - */ - public function __toString(); } diff --git a/src/Model/ImmutableZipContainer.php b/src/Model/ImmutableZipContainer.php index 69722a0..89fbde2 100644 --- a/src/Model/ImmutableZipContainer.php +++ b/src/Model/ImmutableZipContainer.php @@ -25,6 +25,22 @@ class ImmutableZipContainer implements \Countable $this->archiveComment = $archiveComment; } + /** + * When an object is cloned, PHP 5 will perform a shallow copy of all of the object's properties. + * Any properties that are references to other variables, will remain references. + * Once the cloning is complete, if a __clone() method is defined, + * then the newly created object's __clone() method will be called, to allow any necessary properties that need to + * be changed. NOT CALLABLE DIRECTLY. + * + * @see https://php.net/manual/en/language.oop5.cloning.php + */ + public function __clone() + { + foreach ($this->entries as $key => $value) { + $this->entries[$key] = clone $value; + } + } + /** * @return ZipEntry[] */ @@ -53,20 +69,4 @@ class ImmutableZipContainer implements \Countable { return \count($this->entries); } - - /** - * When an object is cloned, PHP 5 will perform a shallow copy of all of the object's properties. - * Any properties that are references to other variables, will remain references. - * Once the cloning is complete, if a __clone() method is defined, - * then the newly created object's __clone() method will be called, to allow any necessary properties that need to - * be changed. NOT CALLABLE DIRECTLY. - * - * @see https://php.net/manual/en/language.oop5.cloning.php - */ - public function __clone() - { - foreach ($this->entries as $key => $value) { - $this->entries[$key] = clone $value; - } - } } diff --git a/src/Model/ZipContainer.php b/src/Model/ZipContainer.php index 6cfe87e..e59bbff 100644 --- a/src/Model/ZipContainer.php +++ b/src/Model/ZipContainer.php @@ -134,7 +134,7 @@ class ZipContainer extends ImmutableZipContainer { $entryName = $entryName instanceof ZipEntry ? $entryName->getName() : (string) $entryName; - return isset($this->entries[$entryName]) ? $this->entries[$entryName] : null; + return $this->entries[$entryName] ?? null; } /** @@ -225,8 +225,8 @@ class ZipContainer extends ImmutableZipContainer $entry = $entry instanceof ZipEntry ? $entry->getName() : (string) $entry; if ( - $this->sourceContainer !== null && - isset($this->entries[$entry], $this->sourceContainer->entries[$entry]) + $this->sourceContainer !== null + && isset($this->entries[$entry], $this->sourceContainer->entries[$entry]) ) { $this->entries[$entry] = clone $this->sourceContainer->entries[$entry]; diff --git a/src/Model/ZipEntry.php b/src/Model/ZipEntry.php index 5194fc0..9c97514 100644 --- a/src/Model/ZipEntry.php +++ b/src/Model/ZipEntry.php @@ -64,12 +64,28 @@ class ZipEntry /** * Pseudo compression method for WinZip AES encrypted entries. - * Require php extension openssl or mcrypt. + * Require php extension openssl. * * @deprecated Use {@see ZipCompressionMethod::WINZIP_AES} */ const METHOD_WINZIP_AES = ZipCompressionMethod::WINZIP_AES; + /** + * Collections of Extra Fields in Central Directory. + * Keys from Header ID [int] and value Extra Field [ExtraField]. + * + * @var ExtraFieldsCollection + */ + protected $cdExtraFields; + + /** + * Collections of Extra Fields int local header. + * Keys from Header ID [int] and value Extra Field [ExtraField]. + * + * @var ExtraFieldsCollection + */ + protected $localExtraFields; + /** @var string Entry name (filename in archive) */ private $name; @@ -118,22 +134,6 @@ class ZipEntry /** @var int relative Offset Of Local File Header */ private $localHeaderOffset = 0; - /** - * Collections of Extra Fields in Central Directory. - * Keys from Header ID [int] and value Extra Field [ExtraField]. - * - * @var ExtraFieldsCollection - */ - protected $cdExtraFields; - - /** - * Collections of Extra Fields int local header. - * Keys from Header ID [int] and value Extra Field [ExtraField]. - * - * @var ExtraFieldsCollection - */ - protected $localExtraFields; - /** @var string|null comment field */ private $comment; @@ -163,6 +163,16 @@ class ZipEntry $this->localExtraFields = new ExtraFieldsCollection(); } + public function __clone() + { + $this->cdExtraFields = clone $this->cdExtraFields; + $this->localExtraFields = clone $this->localExtraFields; + + if ($this->data !== null) { + $this->data = clone $this->data; + } + } + /** * This method only internal use. * @@ -267,9 +277,9 @@ class ZipEntry if ($this->extractVersion !== self::UNKNOWN) { $this->extractVersion = max( $this->extractVersion, - $this->isDirectory ? - ZipVersion::v20_DEFLATED_FOLDER_ZIPCRYPTO : - ZipVersion::v10_DEFAULT_MIN + $this->isDirectory + ? ZipVersion::v20_DEFLATED_FOLDER_ZIPCRYPTO + : ZipVersion::v10_DEFAULT_MIN ); } @@ -343,7 +353,7 @@ class ZipEntry * * @internal */ - public function setData($data) + public function setData(ZipData $data = null) { $this->data = $data; } @@ -487,9 +497,9 @@ class ZipEntry } if ( - $this->compressionMethod === ZipCompressionMethod::DEFLATED || - $this->isDirectory || - $this->encryptionMethod === ZipEncryptionMethod::PKWARE + $this->compressionMethod === ZipCompressionMethod::DEFLATED + || $this->isDirectory + || $this->encryptionMethod === ZipEncryptionMethod::PKWARE ) { return ZipVersion::v20_DEFLATED_FOLDER_ZIPCRYPTO; } @@ -1151,8 +1161,8 @@ class ZipEntry $headerId = (int) $headerId; return - isset($this->localExtraFields[$headerId]) || - isset($this->cdExtraFields[$headerId]); + isset($this->localExtraFields[$headerId]) + || isset($this->cdExtraFields[$headerId]); } /** @@ -1358,12 +1368,12 @@ class ZipEntry } if ( - $compressionLevel < ZipCompressionLevel::LEVEL_MIN || - $compressionLevel > ZipCompressionLevel::LEVEL_MAX + $compressionLevel < ZipCompressionLevel::LEVEL_MIN + || $compressionLevel > ZipCompressionLevel::LEVEL_MAX ) { throw new InvalidArgumentException( - 'Invalid compression level. Minimum level ' . - ZipCompressionLevel::LEVEL_MIN . '. Maximum level ' . ZipCompressionLevel::LEVEL_MAX + 'Invalid compression level. Minimum level ' + . ZipCompressionLevel::LEVEL_MIN . '. Maximum level ' . ZipCompressionLevel::LEVEL_MAX ); } $this->compressionLevel = $compressionLevel; @@ -1385,15 +1395,18 @@ class ZipEntry switch ($this->compressionLevel) { case ZipCompressionLevel::MAXIMUM: $bit1 = true; + break; case ZipCompressionLevel::FAST: $bit2 = true; + break; case ZipCompressionLevel::SUPER_FAST: $bit1 = true; $bit2 = true; + break; // default is ZipCompressionLevel::NORMAL } @@ -1535,8 +1548,6 @@ class ZipEntry if ($oldUnixExtra !== null) { return $oldUnixExtra->getAccessDateTime(); } - - return null; } /** @@ -1557,17 +1568,5 @@ class ZipEntry if ($extendedExtra !== null) { return $extendedExtra->getCreateDateTime(); } - - return null; - } - - public function __clone() - { - $this->cdExtraFields = clone $this->cdExtraFields; - $this->localExtraFields = clone $this->localExtraFields; - - if ($this->data !== null) { - $this->data = clone $this->data; - } } } diff --git a/src/Model/ZipInfo.php b/src/Model/ZipInfo.php index 42eebbf..754a9f6 100644 --- a/src/Model/ZipInfo.php +++ b/src/Model/ZipInfo.php @@ -31,6 +31,33 @@ class ZipInfo $this->entry = $entry; } + /** + * @return string + */ + public function __toString() + { + $ctime = $this->entry->getCTime(); + $atime = $this->entry->getATime(); + $comment = $this->getComment(); + + return __CLASS__ . ' {' + . 'Name="' . $this->getName() . '", ' + . ($this->isFolder() ? 'Folder, ' : '') + . 'Size="' . FilesUtil::humanSize($this->getSize()) . '"' + . ', Compressed size="' . FilesUtil::humanSize($this->getCompressedSize()) . '"' + . ', Modified time="' . $this->entry->getMTime()->format(\DATE_W3C) . '", ' + . ($ctime !== null ? 'Created time="' . $ctime->format(\DATE_W3C) . '", ' : '') + . ($atime !== null ? 'Accessed time="' . $atime->format(\DATE_W3C) . '", ' : '') + . ($this->isEncrypted() ? 'Encrypted, ' : '') + . ($comment !== null ? 'Comment="' . $comment . '", ' : '') + . (!empty($this->crc) ? 'Crc=0x' . dechex($this->crc) . ', ' : '') + . 'Method name="' . $this->getMethodName() . '", ' + . 'Attributes="' . $this->getAttributes() . '", ' + . 'Platform="' . $this->getPlatform() . '", ' + . 'Version=' . $this->getVersion() + . '}'; + } + /** * @param ZipEntry $entry * @@ -236,31 +263,4 @@ class ZipInfo 'version' => $this->getVersion(), ]; } - - /** - * @return string - */ - public function __toString() - { - $ctime = $this->entry->getCTime(); - $atime = $this->entry->getATime(); - $comment = $this->getComment(); - - return __CLASS__ . ' {' - . 'Name="' . $this->getName() . '", ' - . ($this->isFolder() ? 'Folder, ' : '') - . 'Size="' . FilesUtil::humanSize($this->getSize()) . '"' - . ', Compressed size="' . FilesUtil::humanSize($this->getCompressedSize()) . '"' - . ', Modified time="' . $this->entry->getMTime()->format(\DATE_W3C) . '", ' - . ($ctime !== null ? 'Created time="' . $ctime->format(\DATE_W3C) . '", ' : '') - . ($atime !== null ? 'Accessed time="' . $atime->format(\DATE_W3C) . '", ' : '') - . ($this->isEncrypted() ? 'Encrypted, ' : '') - . ($comment !== null ? 'Comment="' . $comment . '", ' : '') - . (!empty($this->crc) ? 'Crc=0x' . dechex($this->crc) . ', ' : '') - . 'Method name="' . $this->getMethodName() . '", ' - . 'Attributes="' . $this->getAttributes() . '", ' - . 'Platform="' . $this->getPlatform() . '", ' - . 'Version=' . $this->getVersion() - . '}'; - } } diff --git a/src/Util/CryptoUtil.php b/src/Util/CryptoUtil.php index 852a5e1..013d1a7 100644 --- a/src/Util/CryptoUtil.php +++ b/src/Util/CryptoUtil.php @@ -40,15 +40,11 @@ class CryptoUtil { if (\extension_loaded('openssl')) { $numBits = \strlen($key) * 8; - /** @noinspection PhpComposerExtensionStubsInspection */ + return openssl_decrypt($data, 'AES-' . $numBits . '-CTR', $key, \OPENSSL_RAW_DATA, $iv); } - if (\extension_loaded('mcrypt')) { - return mcrypt_decrypt(\MCRYPT_RIJNDAEL_128, $key, $data, 'ctr', $iv); - } - - throw new RuntimeException('Extension openssl or mcrypt not loaded'); + throw new RuntimeException('Openssl extension not loaded'); } /** @@ -64,14 +60,10 @@ class CryptoUtil { if (\extension_loaded('openssl')) { $numBits = \strlen($key) * 8; - /** @noinspection PhpComposerExtensionStubsInspection */ + return openssl_encrypt($data, 'AES-' . $numBits . '-CTR', $key, \OPENSSL_RAW_DATA, $iv); } - if (\extension_loaded('mcrypt')) { - return mcrypt_encrypt(\MCRYPT_RIJNDAEL_128, $key, $data, 'ctr', $iv); - } - - throw new RuntimeException('Extension openssl or mcrypt not loaded'); + throw new RuntimeException('Openssl extension not loaded'); } } diff --git a/src/Util/DateTimeConverter.php b/src/Util/DateTimeConverter.php index 615ba22..3559149 100644 --- a/src/Util/DateTimeConverter.php +++ b/src/Util/DateTimeConverter.php @@ -82,12 +82,12 @@ class DateTimeConverter $date = getdate($unixTimestamp); $dosTime = ( - (($date['year'] - 1980) << 25) | - ($date['mon'] << 21) | - ($date['mday'] << 16) | - ($date['hours'] << 11) | - ($date['minutes'] << 5) | - ($date['seconds'] >> 1) + (($date['year'] - 1980) << 25) + | ($date['mon'] << 21) + | ($date['mday'] << 16) + | ($date['hours'] << 11) + | ($date['minutes'] << 5) + | ($date['seconds'] >> 1) ); if ($dosTime <= self::MIN_DOS_TIME) { diff --git a/src/Util/FileAttribUtil.php b/src/Util/FileAttribUtil.php index 06247ae..61e7b1c 100644 --- a/src/Util/FileAttribUtil.php +++ b/src/Util/FileAttribUtil.php @@ -45,34 +45,42 @@ class FileAttribUtil implements DosAttrs, UnixStat switch ($permission & self::UNX_IFMT) { case self::UNX_IFDIR: $mode .= 'd'; + break; case self::UNX_IFREG: $mode .= '-'; + break; case self::UNX_IFLNK: $mode .= 'l'; + break; case self::UNX_IFBLK: $mode .= 'b'; + break; case self::UNX_IFCHR: $mode .= 'c'; + break; case self::UNX_IFIFO: $mode .= 'p'; + break; case self::UNX_IFSOCK: $mode .= 's'; + break; default: $mode .= '?'; + break; } $mode .= ($permission & self::UNX_IRUSR) ? 'r' : '-'; diff --git a/src/Util/FilesUtil.php b/src/Util/FilesUtil.php index 3e64614..318f735 100644 --- a/src/Util/FilesUtil.php +++ b/src/Util/FilesUtil.php @@ -72,11 +72,13 @@ final class FilesUtil case '*': $regexPattern .= ($escaping ? '\\*' : '.*'); $escaping = false; + break; case '?': $regexPattern .= ($escaping ? '\\?' : '.'); $escaping = false; + break; case '.': @@ -90,6 +92,7 @@ final class FilesUtil case '%': $regexPattern .= '\\' . $currentChar; $escaping = false; + break; case '\\': @@ -99,6 +102,7 @@ final class FilesUtil } else { $escaping = true; } + break; case '{': @@ -109,6 +113,7 @@ final class FilesUtil $inCurrent++; } $escaping = false; + break; case '}': @@ -121,6 +126,7 @@ final class FilesUtil $regexPattern = '}'; } $escaping = false; + break; case ',': @@ -131,6 +137,7 @@ final class FilesUtil } else { $regexPattern = ','; } + break; default: $escaping = false; @@ -406,11 +413,9 @@ final class FilesUtil 'x-epoc/x-sisx-app', ]; - if (\in_array($mimeType, $badDeflateCompMimeTypes, true)) { - return true; - } + return (bool) (\in_array($mimeType, $badDeflateCompMimeTypes, true)) - return false; + ; } /** diff --git a/src/ZipFile.php b/src/ZipFile.php index 384c03f..b9c7aa4 100644 --- a/src/ZipFile.php +++ b/src/ZipFile.php @@ -42,6 +42,9 @@ use Symfony\Component\Finder\SplFileInfo as SymfonySplFileInfo; */ class ZipFile implements ZipFileInterface { + /** @var ZipContainer */ + protected $zipContainer; + /** @var array default mime types */ private static $defaultMimeTypes = [ 'zip' => 'application/zip', @@ -55,9 +58,6 @@ class ZipFile implements ZipFileInterface 'xpi' => 'application/x-xpinstall', ]; - /** @var ZipContainer */ - protected $zipContainer; - /** @var ZipReader|null */ private $reader; @@ -69,6 +69,14 @@ class ZipFile implements ZipFileInterface $this->zipContainer = $this->createZipContainer(null); } + /** + * Release all resources. + */ + public function __destruct() + { + $this->close(); + } + /** * @param resource $inputStream * @param array $options @@ -376,7 +384,7 @@ class ZipFile implements ZipFileInterface * @param string $destDir location where to extract the files * @param array|string|null $entries entries to extract * @param array $options extract options - * @param array $extractedEntries if the extractedEntries argument + * @param array|null $extractedEntries if the extractedEntries argument * is present, then the specified * array will be filled with * information about the @@ -576,9 +584,9 @@ class ZipFile implements ZipFileInterface $compressionMethod = ZipCompressionMethod::STORED; } else { $mimeType = FilesUtil::getMimeTypeFromString($contents); - $compressionMethod = FilesUtil::isBadCompressionMimeType($mimeType) ? - ZipCompressionMethod::STORED : - ZipCompressionMethod::DEFLATED; + $compressionMethod = FilesUtil::isBadCompressionMimeType($mimeType) + ? ZipCompressionMethod::STORED + : ZipCompressionMethod::DEFLATED; } } @@ -714,9 +722,9 @@ class ZipFile implements ZipFileInterface } elseif ($file->getSize() < 512) { $compressionMethod = ZipCompressionMethod::STORED; } else { - $compressionMethod = FilesUtil::isBadCompressionFile($file->getPathname()) ? - ZipCompressionMethod::STORED : - ZipCompressionMethod::DEFLATED; + $compressionMethod = FilesUtil::isBadCompressionFile($file->getPathname()) + ? ZipCompressionMethod::STORED + : ZipCompressionMethod::DEFLATED; } $zipEntry->setCompressionMethod($compressionMethod); @@ -838,9 +846,9 @@ class ZipFile implements ZipFileInterface $bufferContents = stream_get_contents($stream, min(1024, $length)); rewind($stream); $mimeType = FilesUtil::getMimeTypeFromString($bufferContents); - $compressionMethod = FilesUtil::isBadCompressionMimeType($mimeType) ? - ZipCompressionMethod::STORED : - ZipCompressionMethod::DEFLATED; + $compressionMethod = FilesUtil::isBadCompressionMimeType($mimeType) + ? ZipCompressionMethod::STORED + : ZipCompressionMethod::DEFLATED; } $zipEntry->setUncompressedSize($length); } @@ -999,9 +1007,9 @@ class ZipFile implements ZipFileInterface $localPath = ''; } - $iterator = $iterator instanceof \RecursiveIterator ? - new \RecursiveIteratorIterator($iterator) : - new \IteratorIterator($iterator); + $iterator = $iterator instanceof \RecursiveIterator + ? new \RecursiveIteratorIterator($iterator) + : new \IteratorIterator($iterator); /** * @var string[] $files * @var string $path @@ -1843,14 +1851,6 @@ class ZipFile implements ZipFileInterface return $this->saveAsFile($meta['uri']); } - /** - * Release all resources. - */ - public function __destruct() - { - $this->close(); - } - /** * Offset to set. * diff --git a/src/ZipFileInterface.php b/src/ZipFileInterface.php index 07108d1..e831398 100644 --- a/src/ZipFileInterface.php +++ b/src/ZipFileInterface.php @@ -295,7 +295,7 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator * @param string $destDir location where to extract the files * @param array|string|null $entries entries to extract * @param array $options extract options - * @param array $extractedEntries if the extractedEntries argument + * @param array|null $extractedEntries if the extractedEntries argument * is present, then the specified * array will be filled with * information about the diff --git a/tests/Extra/Fields/AbstractUnicodeExtraFieldTest.php b/tests/Extra/Fields/AbstractUnicodeExtraFieldTest.php index 2dd5ee4..308efe2 100644 --- a/tests/Extra/Fields/AbstractUnicodeExtraFieldTest.php +++ b/tests/Extra/Fields/AbstractUnicodeExtraFieldTest.php @@ -76,8 +76,10 @@ abstract class AbstractUnicodeExtraFieldTest extends TestCase */ public function testUnicodeErrorParse() { - $this->setExpectedException( - ZipException::class, + $this->expectException( + ZipException::class + ); + $this->expectExceptionMessage( 'Unicode path extra data must have at least 5 bytes.' ); @@ -90,8 +92,10 @@ abstract class AbstractUnicodeExtraFieldTest extends TestCase */ public function testUnknownVersionParse() { - $this->setExpectedException( - ZipException::class, + $this->expectException( + ZipException::class + ); + $this->expectExceptionMessage( 'Unsupported version [2] for Unicode path extra data.' ); diff --git a/tests/Extra/Fields/ApkAlignmentExtraFieldTest.php b/tests/Extra/Fields/ApkAlignmentExtraFieldTest.php index ddc68f5..4aa903c 100644 --- a/tests/Extra/Fields/ApkAlignmentExtraFieldTest.php +++ b/tests/Extra/Fields/ApkAlignmentExtraFieldTest.php @@ -96,8 +96,10 @@ final class ApkAlignmentExtraFieldTest extends TestCase */ public function testInvalidParse() { - $this->setExpectedException( - ZipException::class, + $this->expectException( + ZipException::class + ); + $this->expectExceptionMessage( 'Minimum 6 bytes of the extensible data block/field used for alignment of uncompressed entries.' ); diff --git a/tests/Extra/Fields/AsiExtraFieldTest.php b/tests/Extra/Fields/AsiExtraFieldTest.php index 5360e87..e0f82e3 100644 --- a/tests/Extra/Fields/AsiExtraFieldTest.php +++ b/tests/Extra/Fields/AsiExtraFieldTest.php @@ -91,8 +91,10 @@ final class AsiExtraFieldTest extends TestCase */ public function testInvalidParse() { - $this->setExpectedException( - Crc32Exception::class, + $this->expectException( + Crc32Exception::class + ); + $this->expectExceptionMessage( 'Asi Unix Extra Filed Data (expected CRC32 value' ); diff --git a/tests/Extra/Fields/ExtendedTimestampExtraFieldTest.php b/tests/Extra/Fields/ExtendedTimestampExtraFieldTest.php index 0da3af5..c2fc88d 100644 --- a/tests/Extra/Fields/ExtendedTimestampExtraFieldTest.php +++ b/tests/Extra/Fields/ExtendedTimestampExtraFieldTest.php @@ -66,9 +66,9 @@ final class ExtendedTimestampExtraFieldTest extends TestCase { return [ [ - ExtendedTimestampExtraField::MODIFY_TIME_BIT | - ExtendedTimestampExtraField::ACCESS_TIME_BIT | - ExtendedTimestampExtraField::CREATE_TIME_BIT, + ExtendedTimestampExtraField::MODIFY_TIME_BIT + | ExtendedTimestampExtraField::ACCESS_TIME_BIT + | ExtendedTimestampExtraField::CREATE_TIME_BIT, 911512006, 911430000, 893709400, @@ -76,8 +76,8 @@ final class ExtendedTimestampExtraFieldTest extends TestCase "\x07\xC6\x91T6", ], [ - ExtendedTimestampExtraField::MODIFY_TIME_BIT | - ExtendedTimestampExtraField::ACCESS_TIME_BIT, + ExtendedTimestampExtraField::MODIFY_TIME_BIT + | ExtendedTimestampExtraField::ACCESS_TIME_BIT, 1492955702, 1492955638, null, @@ -115,8 +115,8 @@ final class ExtendedTimestampExtraFieldTest extends TestCase $field->setAccessTime($atime); self::assertSame( $field->getFlags(), - ExtendedTimestampExtraField::MODIFY_TIME_BIT | - ExtendedTimestampExtraField::ACCESS_TIME_BIT + ExtendedTimestampExtraField::MODIFY_TIME_BIT + | ExtendedTimestampExtraField::ACCESS_TIME_BIT ); self::assertSame($field->getModifyTime(), $mtime); self::assertSame($field->getAccessTime(), $atime); @@ -127,9 +127,9 @@ final class ExtendedTimestampExtraFieldTest extends TestCase $field->setCreateTime($ctime); self::assertSame( $field->getFlags(), - ExtendedTimestampExtraField::MODIFY_TIME_BIT | - ExtendedTimestampExtraField::ACCESS_TIME_BIT | - ExtendedTimestampExtraField::CREATE_TIME_BIT + ExtendedTimestampExtraField::MODIFY_TIME_BIT + | ExtendedTimestampExtraField::ACCESS_TIME_BIT + | ExtendedTimestampExtraField::CREATE_TIME_BIT ); self::assertSame($field->getModifyTime(), $mtime); self::assertSame($field->getAccessTime(), $atime); @@ -141,8 +141,8 @@ final class ExtendedTimestampExtraFieldTest extends TestCase self::assertNull($field->getCreateDateTime()); self::assertSame( $field->getFlags(), - ExtendedTimestampExtraField::MODIFY_TIME_BIT | - ExtendedTimestampExtraField::ACCESS_TIME_BIT + ExtendedTimestampExtraField::MODIFY_TIME_BIT + | ExtendedTimestampExtraField::ACCESS_TIME_BIT ); $field->setAccessTime(null); diff --git a/tests/Extra/Fields/JarMarkerExtraFieldTest.php b/tests/Extra/Fields/JarMarkerExtraFieldTest.php index 2067215..92ce409 100644 --- a/tests/Extra/Fields/JarMarkerExtraFieldTest.php +++ b/tests/Extra/Fields/JarMarkerExtraFieldTest.php @@ -32,8 +32,10 @@ final class JarMarkerExtraFieldTest extends TestCase */ public function testInvalidUnpackLocalData() { - $this->setExpectedException( - ZipException::class, + $this->expectException( + ZipException::class + ); + $this->expectExceptionMessage( "JarMarker doesn't expect any data" ); @@ -45,8 +47,10 @@ final class JarMarkerExtraFieldTest extends TestCase */ public function testInvalidUnpackCdData() { - $this->setExpectedException( - ZipException::class, + $this->expectException( + ZipException::class + ); + $this->expectExceptionMessage( "JarMarker doesn't expect any data" ); diff --git a/tests/Extra/Fields/NtfsExtraFieldTest.php b/tests/Extra/Fields/NtfsExtraFieldTest.php index 822a51f..0772851 100644 --- a/tests/Extra/Fields/NtfsExtraFieldTest.php +++ b/tests/Extra/Fields/NtfsExtraFieldTest.php @@ -14,8 +14,10 @@ use PhpZip\Model\Extra\Fields\NtfsExtraField; */ final class NtfsExtraFieldTest extends TestCase { - protected function setUp() + protected function setUp(): void { + parent::setUp(); + if (\PHP_INT_SIZE === 4) { self::markTestSkipped('only 64 bit test'); } @@ -156,9 +158,9 @@ final class NtfsExtraFieldTest extends TestCase $atimeTimestamp, $ctimeTimestamp ) { - self::assertEquals(NtfsExtraField::ntfsTimeToTimestamp($mtimeNtfs), $mtimeTimestamp, '', 0.00001); - self::assertEquals(NtfsExtraField::ntfsTimeToTimestamp($atimeNtfs), $atimeTimestamp, '', 0.00001); - self::assertEquals(NtfsExtraField::ntfsTimeToTimestamp($ctimeNtfs), $ctimeTimestamp, '', 0.00001); + self::assertEqualsWithDelta(NtfsExtraField::ntfsTimeToTimestamp($mtimeNtfs), $mtimeTimestamp, 0.00001); + self::assertEqualsWithDelta(NtfsExtraField::ntfsTimeToTimestamp($atimeNtfs), $atimeTimestamp, 0.00001); + self::assertEqualsWithDelta(NtfsExtraField::ntfsTimeToTimestamp($ctimeNtfs), $ctimeTimestamp, 0.00001); self::assertEqualsIntegerWithDelta(NtfsExtraField::timestampToNtfsTime($mtimeTimestamp), $mtimeNtfs, 10); self::assertEqualsIntegerWithDelta(NtfsExtraField::timestampToNtfsTime($atimeTimestamp), $atimeNtfs, 10); diff --git a/tests/Extra/Fields/UnicodeCommentExtraFieldTest.php b/tests/Extra/Fields/UnicodeCommentExtraFieldTest.php index a637111..46c2392 100644 --- a/tests/Extra/Fields/UnicodeCommentExtraFieldTest.php +++ b/tests/Extra/Fields/UnicodeCommentExtraFieldTest.php @@ -12,7 +12,7 @@ use PhpZip\Model\Extra\Fields\UnicodeCommentExtraField; final class UnicodeCommentExtraFieldTest extends AbstractUnicodeExtraFieldTest { /** - * {@inheritdoc} + * {@inheritDoc} */ protected function getUnicodeExtraFieldClassName() { diff --git a/tests/Extra/Fields/UnicodePathExtraFieldTest.php b/tests/Extra/Fields/UnicodePathExtraFieldTest.php index d856dd2..75d65f6 100644 --- a/tests/Extra/Fields/UnicodePathExtraFieldTest.php +++ b/tests/Extra/Fields/UnicodePathExtraFieldTest.php @@ -14,7 +14,7 @@ use PhpZip\Model\Extra\Fields\UnicodePathExtraField; final class UnicodePathExtraFieldTest extends AbstractUnicodeExtraFieldTest { /** - * {@inheritdoc} + * {@inheritDoc} */ protected function getUnicodeExtraFieldClassName() { diff --git a/tests/Extra/Fields/UnrecognizedExtraFieldTest.php b/tests/Extra/Fields/UnrecognizedExtraFieldTest.php index 8dfa1ef..24b2f55 100644 --- a/tests/Extra/Fields/UnrecognizedExtraFieldTest.php +++ b/tests/Extra/Fields/UnrecognizedExtraFieldTest.php @@ -37,8 +37,10 @@ final class UnrecognizedExtraFieldTest extends TestCase public function testUnpackLocalData() { - $this->setExpectedException( - RuntimeException::class, + $this->expectException( + RuntimeException::class + ); + $this->expectExceptionMessage( 'Unsupport parse' ); @@ -47,8 +49,10 @@ final class UnrecognizedExtraFieldTest extends TestCase public function testUnpackCentralDirData() { - $this->setExpectedException( - RuntimeException::class, + $this->expectException( + RuntimeException::class + ); + $this->expectExceptionMessage( 'Unsupport parse' ); diff --git a/tests/Extra/Fields/WinZipAesExtraFieldTest.php b/tests/Extra/Fields/WinZipAesExtraFieldTest.php index 70e7a69..2837007 100644 --- a/tests/Extra/Fields/WinZipAesExtraFieldTest.php +++ b/tests/Extra/Fields/WinZipAesExtraFieldTest.php @@ -157,7 +157,8 @@ final class WinZipAesExtraFieldTest extends TestCase */ public function testConstructUnsupportVendorVersion() { - $this->setExpectedException(InvalidArgumentException::class, 'Unsupport WinZip AES vendor version: 3'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Unsupport WinZip AES vendor version: 3'); new WinZipAesExtraField( 3, @@ -171,7 +172,8 @@ final class WinZipAesExtraFieldTest extends TestCase */ public function testSetterUnsupportVendorVersion() { - $this->setExpectedException(InvalidArgumentException::class, 'Unsupport WinZip AES vendor version: 3'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Unsupport WinZip AES vendor version: 3'); $extraField = new WinZipAesExtraField( WinZipAesExtraField::VERSION_AE1, @@ -186,7 +188,8 @@ final class WinZipAesExtraFieldTest extends TestCase */ public function testConstructUnsupportCompressionMethod() { - $this->setExpectedException(ZipUnsupportMethodException::class, 'Compression method 3 (Reduced compression factor 2) is not supported.'); + $this->expectException(ZipUnsupportMethodException::class); + $this->expectExceptionMessage('Compression method 3 (Reduced compression factor 2) is not supported.'); new WinZipAesExtraField( WinZipAesExtraField::VERSION_AE1, @@ -200,7 +203,8 @@ final class WinZipAesExtraFieldTest extends TestCase */ public function testSetterUnsupportCompressionMethod() { - $this->setExpectedException(ZipUnsupportMethodException::class, 'Compression method 3 (Reduced compression factor 2) is not supported.'); + $this->expectException(ZipUnsupportMethodException::class); + $this->expectExceptionMessage('Compression method 3 (Reduced compression factor 2) is not supported.'); $extraField = new WinZipAesExtraField( WinZipAesExtraField::VERSION_AE1, @@ -215,7 +219,8 @@ final class WinZipAesExtraFieldTest extends TestCase */ public function testConstructUnsupportKeyStrength() { - $this->setExpectedException(InvalidArgumentException::class, 'Key strength 16 not support value. Allow values: 1, 2, 3'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Key strength 16 not support value. Allow values: 1, 2, 3'); new WinZipAesExtraField( WinZipAesExtraField::VERSION_AE1, @@ -229,7 +234,8 @@ final class WinZipAesExtraFieldTest extends TestCase */ public function testSetterUnsupportKeyStrength() { - $this->setExpectedException(InvalidArgumentException::class, 'Key strength 16 not support value. Allow values: 1, 2, 3'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Key strength 16 not support value. Allow values: 1, 2, 3'); new WinZipAesExtraField( WinZipAesExtraField::VERSION_AE1, diff --git a/tests/Extra/Fields/Zip64ExtraFieldTest.php b/tests/Extra/Fields/Zip64ExtraFieldTest.php index 815128d..50b0695 100644 --- a/tests/Extra/Fields/Zip64ExtraFieldTest.php +++ b/tests/Extra/Fields/Zip64ExtraFieldTest.php @@ -15,8 +15,10 @@ use PhpZip\Model\ZipEntry; */ final class Zip64ExtraFieldTest extends TestCase { - protected function setUp() + protected function setUp(): void { + parent::setUp(); + if (\PHP_INT_SIZE === 4) { self::markTestSkipped('only 64 bit test'); } diff --git a/tests/Issue24Test.php b/tests/Issue24Test.php index d71e128..16fe87a 100644 --- a/tests/Issue24Test.php +++ b/tests/Issue24Test.php @@ -21,7 +21,7 @@ class Issue24Test extends ZipTestCase * * @noinspection PhpMissingParentCallCommonInspection */ - public static function setUpBeforeClass() + public static function setUpBeforeClass(): void { stream_wrapper_register(self::PROTO_DUMMYFS, DummyFileSystemStream::class); } diff --git a/tests/PhpZipExtResourceTest.php b/tests/PhpZipExtResourceTest.php index cd6eaef..a946250 100644 --- a/tests/PhpZipExtResourceTest.php +++ b/tests/PhpZipExtResourceTest.php @@ -87,7 +87,7 @@ class PhpZipExtResourceTest extends ZipTestCase $zipFile->extractTo($this->outputDirname); $zipFile->close(); - static::assertTrue(is_dir($this->outputDirname . '/test/empty')); + static::assertDirectoryExists($this->outputDirname . '/test/empty'); } /** @@ -109,7 +109,8 @@ class PhpZipExtResourceTest extends ZipTestCase */ public function testBug49072() { - $this->setExpectedException(Crc32Exception::class, 'file1'); + $this->expectException(Crc32Exception::class); + $this->expectExceptionMessage('file1'); $filename = __DIR__ . '/resources/pecl/bug49072.zip'; @@ -128,13 +129,17 @@ class PhpZipExtResourceTest extends ZipTestCase public function testBug70752() { if (\PHP_INT_SIZE === 4) { // php 32 bit - $this->setExpectedException( - RuntimeException::class, + $this->expectException( + RuntimeException::class + ); + $this->expectExceptionMessage( 'Traditional PKWARE Encryption is not supported in 32-bit PHP.' ); } else { // php 64 bit - $this->setExpectedException( - ZipAuthenticationException::class, + $this->expectException( + ZipAuthenticationException::class + ); + $this->expectExceptionMessage( 'Invalid password' ); } @@ -151,7 +156,7 @@ class PhpZipExtResourceTest extends ZipTestCase $zipFile->extractTo($this->outputDirname); static::markTestIncomplete('failed test'); } catch (ZipException $exception) { - static::assertFileNotExists($this->outputDirname . '/bug70752.txt'); + static::assertFileDoesNotExist($this->outputDirname . '/bug70752.txt'); throw $exception; } finally { @@ -168,7 +173,8 @@ class PhpZipExtResourceTest extends ZipTestCase */ public function testPecl12414() { - $this->setExpectedException(ZipException::class, 'Corrupt zip file. Cannot read zip entry.'); + $this->expectException(ZipException::class); + $this->expectExceptionMessage('Corrupt zip file. Cannot read zip entry.'); $filename = __DIR__ . '/resources/pecl/pecl12414.zip'; diff --git a/tests/Polyfill/LegacyTestCase.php b/tests/Polyfill/LegacyTestCase.php new file mode 100644 index 0000000..fe9fda1 --- /dev/null +++ b/tests/Polyfill/LegacyTestCase.php @@ -0,0 +1,18 @@ +expectExceptionMessageRegExp($regularExpression); + + return; + } + + parent::expectExceptionMessageMatches($regularExpression); + } +} diff --git a/tests/Polyfill/PhpUnit9CompatTrait.php b/tests/Polyfill/PhpUnit9CompatTrait.php new file mode 100644 index 0000000..1f0fc85 --- /dev/null +++ b/tests/Polyfill/PhpUnit9CompatTrait.php @@ -0,0 +1,53 @@ +outputFilename); FilesUtil::removeDir($this->outputDirname); - self::assertFalse(is_dir($this->outputDirname)); + self::assertDirectoryDoesNotExist($this->outputDirname); self::assertTrue(mkdir($this->outputDirname, 0755, true)); $zipFile->openFile($this->outputFilename); diff --git a/tests/ZipAlignTest.php b/tests/ZipAlignTest.php index 984907e..577c9a6 100644 --- a/tests/ZipAlignTest.php +++ b/tests/ZipAlignTest.php @@ -55,7 +55,7 @@ class ZipAlignTest extends ZipTestCase for ($i = 0; $i < 100; $i++) { $zipFile->addFromString( 'entry' . $i . '.txt', - random_bytes(mt_rand(100, 4096)), + random_bytes(random_int(100, 4096)), ZipCompressionMethod::STORED ); } @@ -97,7 +97,7 @@ class ZipAlignTest extends ZipTestCase for ($i = 0; $i < 100; $i++) { $zipFile->addFromString( 'entry' . $i . '.txt', - random_bytes(mt_rand(100, 4096)), + random_bytes(random_int(100, 4096)), ZipCompressionMethod::STORED ); } @@ -126,7 +126,7 @@ class ZipAlignTest extends ZipTestCase for ($i = 0; $i < 100; $i++) { $zipFile->addFromString( 'entry' . $i . '.txt', - random_bytes(mt_rand(100, 4096)), + random_bytes(random_int(100, 4096)), ZipCompressionMethod::STORED ); } @@ -147,14 +147,14 @@ class ZipAlignTest extends ZipTestCase $zipFile->openFile($this->outputFilename); $zipFile->deleteFromRegex('~entry2[\\d]+\\.txt$~s'); for ($i = 0; $i < 100; $i++) { - $isStored = (bool) mt_rand(0, 1); + $isStored = (bool) random_int(0, 1); $zipFile->addFromString( 'entry_new_' . ($isStored ? 'stored' : 'deflated') . '_' . $i . '.txt', - random_bytes(mt_rand(100, 4096)), - $isStored ? - ZipCompressionMethod::STORED : - ZipCompressionMethod::DEFLATED + random_bytes(random_int(100, 4096)), + $isStored + ? ZipCompressionMethod::STORED + : ZipCompressionMethod::DEFLATED ); } $zipFile->setZipAlign(4); diff --git a/tests/ZipEntryTest.php b/tests/ZipEntryTest.php index 7bb46b1..b75945f 100644 --- a/tests/ZipEntryTest.php +++ b/tests/ZipEntryTest.php @@ -89,7 +89,8 @@ class ZipEntryTest extends TestCase */ public function testEmptyName($entryName, $exceptionMessage) { - $this->setExpectedException(InvalidArgumentException::class, $exceptionMessage); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage($exceptionMessage); new ZipEntry($entryName); } @@ -174,7 +175,8 @@ class ZipEntryTest extends TestCase */ public function testOutOfRangeCompressionMethod($compressionMethod) { - $this->setExpectedException(InvalidArgumentException::class, 'method out of range: ' . $compressionMethod); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('method out of range: ' . $compressionMethod); $zipEntry = new ZipEntry('entry'); $zipEntry->setCompressionMethod($compressionMethod); @@ -201,7 +203,8 @@ class ZipEntryTest extends TestCase */ public function testUnsupportCompressionMethod($compressionMethod, $exceptionMessage) { - $this->setExpectedException(ZipUnsupportMethodException::class, $exceptionMessage); + $this->expectException(ZipUnsupportMethodException::class); + $this->expectExceptionMessage($exceptionMessage); $zipEntry = new ZipEntry('entry'); $zipEntry->setCompressionMethod($compressionMethod); @@ -253,7 +256,8 @@ class ZipEntryTest extends TestCase public function testEmptyCharset() { - $this->setExpectedException(InvalidArgumentException::class, 'Empty charset'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Empty charset'); $zipEntry = new ZipEntry('entry'); $zipEntry->setCharset(''); @@ -398,7 +402,8 @@ class ZipEntryTest extends TestCase */ public function testInvalidCreatedOs($zipOS) { - $this->setExpectedException(InvalidArgumentException::class, 'Platform out of range'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Platform out of range'); $zipEntry = new ZipEntry('entry'); $zipEntry->setCreatedOS($zipOS); @@ -422,7 +427,8 @@ class ZipEntryTest extends TestCase */ public function testInvalidExtractedOs($zipOS) { - $this->setExpectedException(InvalidArgumentException::class, 'Platform out of range'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Platform out of range'); $zipEntry = new ZipEntry('entry'); $zipEntry->setExtractedOS($zipOS); @@ -545,7 +551,8 @@ class ZipEntryTest extends TestCase public function testInvalidCompressedSize() { - $this->setExpectedException(InvalidArgumentException::class, 'Compressed size < -1'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Compressed size < -1'); $zipEntry = new ZipEntry('entry'); $zipEntry->setCompressedSize(-2); @@ -553,7 +560,8 @@ class ZipEntryTest extends TestCase public function testInvalidUncompressedSize() { - $this->setExpectedException(InvalidArgumentException::class, 'Uncompressed size < -1'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Uncompressed size < -1'); $zipEntry = new ZipEntry('entry'); $zipEntry->setUncompressedSize(-2); @@ -568,7 +576,8 @@ class ZipEntryTest extends TestCase $zipEntry->setLocalHeaderOffset($localHeaderOffset); static::assertSame($zipEntry->getLocalHeaderOffset(), $localHeaderOffset); - $this->setExpectedException(InvalidArgumentException::class, 'Negative $localHeaderOffset'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Negative $localHeaderOffset'); $zipEntry->setLocalHeaderOffset(-1); } @@ -652,7 +661,8 @@ class ZipEntryTest extends TestCase */ public function testInvalidGPBF($gpbf) { - $this->setExpectedException(InvalidArgumentException::class, 'general purpose bit flags out of range'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('general purpose bit flags out of range'); $zipEntry = new ZipEntry('entry'); $zipEntry->setGeneralPurposeBitFlags($gpbf); @@ -683,8 +693,8 @@ class ZipEntryTest extends TestCase $zipEntry = new ZipEntry('entry'); $zipEntry->setCompressionMethod(ZipCompressionMethod::DEFLATED); - $gpbf = ($bit1 ? GeneralPurposeBitFlag::COMPRESSION_FLAG1 : 0) | - ($bit2 ? GeneralPurposeBitFlag::COMPRESSION_FLAG2 : 0); + $gpbf = ($bit1 ? GeneralPurposeBitFlag::COMPRESSION_FLAG1 : 0) + | ($bit2 ? GeneralPurposeBitFlag::COMPRESSION_FLAG2 : 0); $zipEntry->setGeneralPurposeBitFlags($gpbf); static::assertSame($zipEntry->getCompressionLevel(), $compressionLevel); @@ -791,10 +801,12 @@ class ZipEntryTest extends TestCase */ public function testInvalidCompressionLevel($compressionLevel) { - $this->setExpectedException( - InvalidArgumentException::class, - 'Invalid compression level. Minimum level ' . ZipCompressionLevel::LEVEL_MIN . - '. Maximum level ' . ZipCompressionLevel::LEVEL_MAX + $this->expectException( + InvalidArgumentException::class + ); + $this->expectExceptionMessage( + 'Invalid compression level. Minimum level ' . ZipCompressionLevel::LEVEL_MIN + . '. Maximum level ' . ZipCompressionLevel::LEVEL_MAX ); $zipEntry = new ZipEntry('entry'); @@ -855,7 +867,8 @@ class ZipEntryTest extends TestCase return; } - $this->setExpectedException(InvalidArgumentException::class, 'DosTime out of range'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('DosTime out of range'); $zipEntry = new ZipEntry('entry'); $zipEntry->setDosTime($dosTime); @@ -1012,7 +1025,8 @@ class ZipEntryTest extends TestCase return; } - $this->setExpectedException(InvalidArgumentException::class, 'external attributes out of range'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('external attributes out of range'); $zipEntry = new ZipEntry('entry'); $zipEntry->setExternalAttributes($externalAttributes); @@ -1045,7 +1059,8 @@ class ZipEntryTest extends TestCase */ public function testInvalidInternalAttributes($internalAttributes) { - $this->setExpectedException(InvalidArgumentException::class, 'internal attributes out of range'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('internal attributes out of range'); $zipEntry = new ZipEntry('entry'); $zipEntry->setInternalAttributes($internalAttributes); @@ -1140,7 +1155,8 @@ class ZipEntryTest extends TestCase */ public function testLongComment() { - $this->setExpectedException(InvalidArgumentException::class, 'Comment too long'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Comment too long'); $longComment = random_bytes(0xffff + 1); $zipEntry = new ZipEntry('entry'); @@ -1305,8 +1321,10 @@ class ZipEntryTest extends TestCase */ public function testInvalidEncryptionMethod($encryptionMethod) { - $this->setExpectedException( - InvalidArgumentException::class, + $this->expectException( + InvalidArgumentException::class + ); + $this->expectExceptionMessage( 'Encryption method ' . $encryptionMethod . ' is not supported.' ); @@ -1456,7 +1474,7 @@ class ZipEntryTest extends TestCase * @param \DateTimeInterface|null $atime * @param \DateTimeInterface|null $ctime */ - public function testMTimeATimeCTime(ExtraFieldsCollection $extraFieldsCollection, $mtime, $atime, $ctime) + public function testMTimeATimeCTime(ExtraFieldsCollection $extraFieldsCollection, \DateTimeInterface $mtime, \DateTimeInterface $atime = null, \DateTimeInterface $ctime = null) { $unixTimestamp = time(); diff --git a/tests/ZipFileSetTestCase.php b/tests/ZipFileSetTestCase.php index f77a15f..ee61e33 100644 --- a/tests/ZipFileSetTestCase.php +++ b/tests/ZipFileSetTestCase.php @@ -30,7 +30,7 @@ abstract class ZipFileSetTestCase extends ZipTestCase /** * Before test. */ - protected function setUp() + protected function setUp(): void { parent::setUp(); $this->fillDirectory(); diff --git a/tests/ZipFileTest.php b/tests/ZipFileTest.php index a22a524..9dfc738 100644 --- a/tests/ZipFileTest.php +++ b/tests/ZipFileTest.php @@ -31,7 +31,8 @@ class ZipFileTest extends ZipTestCase */ public function testOpenFileCantExists() { - $this->setExpectedException(ZipException::class, 'does not exist'); + $this->expectException(ZipException::class); + $this->expectExceptionMessage('does not exist'); $zipFile = new ZipFile(); $zipFile->openFile(uniqid('', false)); @@ -50,7 +51,8 @@ class ZipFileTest extends ZipTestCase return; } - $this->setExpectedException(ZipException::class, 'can\'t open'); + $this->expectException(ZipException::class); + $this->expectExceptionMessage('can\'t open'); static::assertNotFalse(file_put_contents($this->outputFilename, 'content')); static::assertTrue(chmod($this->outputFilename, 0222)); @@ -64,7 +66,8 @@ class ZipFileTest extends ZipTestCase */ public function testOpenFileEmptyFile() { - $this->setExpectedException(ZipException::class, 'Corrupt zip file'); + $this->expectException(ZipException::class); + $this->expectExceptionMessage('Corrupt zip file'); static::assertNotFalse(touch($this->outputFilename)); $zipFile = new ZipFile(); @@ -77,8 +80,10 @@ class ZipFileTest extends ZipTestCase */ public function testOpenFileInvalidZip() { - $this->setExpectedException( - ZipException::class, + $this->expectException( + ZipException::class + ); + $this->expectExceptionMessage( 'Invalid zip file. The end of the central directory could not be found.' ); @@ -92,7 +97,8 @@ class ZipFileTest extends ZipTestCase */ public function testOpenFromStringNullString() { - $this->setExpectedException(InvalidArgumentException::class, 'Empty string passed'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Empty string passed'); $zipFile = new ZipFile(); $zipFile->openFromString(null); @@ -103,7 +109,8 @@ class ZipFileTest extends ZipTestCase */ public function testOpenFromStringEmptyString() { - $this->setExpectedException(InvalidArgumentException::class, 'Empty string passed'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Empty string passed'); $zipFile = new ZipFile(); $zipFile->openFromString(''); @@ -115,8 +122,10 @@ class ZipFileTest extends ZipTestCase */ public function testOpenFromStringInvalidZip() { - $this->setExpectedException( - ZipException::class, + $this->expectException( + ZipException::class + ); + $this->expectExceptionMessage( 'Invalid zip file. The end of the central directory could not be found.' ); @@ -149,7 +158,8 @@ class ZipFileTest extends ZipTestCase */ public function testOpenFromStreamNullStream() { - $this->setExpectedException(InvalidArgumentException::class, 'Stream must be a resource'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Stream must be a resource'); $zipFile = new ZipFile(); $zipFile->openFromStream(null); @@ -160,7 +170,8 @@ class ZipFileTest extends ZipTestCase */ public function testOpenFromStreamInvalidResourceType() { - $this->setExpectedException(InvalidArgumentException::class, 'Stream must be a resource'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Stream must be a resource'); $zipFile = new ZipFile(); /** @noinspection PhpParamsInspection */ @@ -169,19 +180,22 @@ class ZipFileTest extends ZipTestCase /** * @throws ZipException + * + * @noinspection PhpComposerExtensionStubsInspection */ public function testOpenFromStreamInvalidResourceType2() { - $this->setExpectedException(InvalidArgumentException::class, 'Invalid resource type'); + $this->expectException(InvalidArgumentException::class); + $exceptionMessage = PHP_VERSION_ID < 80000 ? + 'Invalid resource type' : + 'Stream must be a resource'; + $this->expectExceptionMessage($exceptionMessage); $zipFile = new ZipFile(); if (!\extension_loaded('gd')) { static::markTestSkipped('not extension gd'); - - return; } - /** @noinspection PhpComposerExtensionStubsInspection */ $zipFile->openFromStream(imagecreate(1, 1)); } @@ -190,7 +204,8 @@ class ZipFileTest extends ZipTestCase */ public function testOpenFromStreamInvalidResourceType3() { - $this->setExpectedException(InvalidArgumentException::class, 'Directory stream not supported'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Directory stream not supported'); $zipFile = new ZipFile(); $zipFile->openFromStream(opendir(__DIR__)); @@ -203,7 +218,8 @@ class ZipFileTest extends ZipTestCase */ public function testOpenFromStreamNoSeekable() { - $this->setExpectedException(InvalidArgumentException::class, 'The stream wrapper type "http" is not supported'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The stream wrapper type "http" is not supported'); if (!$fp = @fopen('http://localhost', 'rb')) { if (!$fp = @fopen('http://example.org', 'rb')) { @@ -222,7 +238,8 @@ class ZipFileTest extends ZipTestCase */ public function testOpenFromStreamEmptyContents() { - $this->setExpectedException(ZipException::class, 'Corrupt zip file'); + $this->expectException(ZipException::class); + $this->expectExceptionMessage('Corrupt zip file'); $fp = fopen($this->outputFilename, 'w+b'); $zipFile = new ZipFile(); @@ -235,8 +252,10 @@ class ZipFileTest extends ZipTestCase */ public function testOpenFromStreamInvalidZip() { - $this->setExpectedException( - ZipException::class, + $this->expectException( + ZipException::class + ); + $this->expectExceptionMessage( 'Invalid zip file. The end of the central directory could not be found.' ); @@ -508,7 +527,8 @@ class ZipFileTest extends ZipTestCase */ public function testRenameEntryNull() { - $this->setExpectedException(InvalidArgumentException::class, 'name is null'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('name is null'); $zipFile = new ZipFile(); $zipFile->rename(null, 'new-file'); @@ -519,7 +539,8 @@ class ZipFileTest extends ZipTestCase */ public function testRenameEntryNull2() { - $this->setExpectedException(InvalidArgumentException::class, 'name is null'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('name is null'); $zipFile = new ZipFile(); $zipFile->rename('old-file', null); @@ -530,7 +551,8 @@ class ZipFileTest extends ZipTestCase */ public function testRenameEntryToExistsNewEntry() { - $this->setExpectedException(InvalidArgumentException::class, 'is exists'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('is exists'); $zipFile = new ZipFile(); $zipFile['file'] = 'content'; @@ -548,7 +570,7 @@ class ZipFileTest extends ZipTestCase */ public function testRenameEntryNotFound() { - $this->setExpectedException(ZipEntryNotFoundException::class); + $this->expectException(ZipEntryNotFoundException::class); $zipFile = new ZipFile(); $zipFile['file'] = 'content'; @@ -615,7 +637,7 @@ class ZipFileTest extends ZipTestCase */ public function testDeleteFromNameNotFoundEntry() { - $this->setExpectedException(ZipEntryNotFoundException::class); + $this->expectException(ZipEntryNotFoundException::class); $zipFile = new ZipFile(); $zipFile->deleteFromName('entry'); @@ -674,7 +696,8 @@ class ZipFileTest extends ZipTestCase public function testDeleteFromGlobFailNull() { - $this->setExpectedException(InvalidArgumentException::class, 'The glob pattern is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The glob pattern is not specified'); $zipFile = new ZipFile(); $zipFile->deleteFromGlob(null); @@ -682,7 +705,8 @@ class ZipFileTest extends ZipTestCase public function testDeleteFromGlobFailEmpty() { - $this->setExpectedException(InvalidArgumentException::class, 'The glob pattern is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The glob pattern is not specified'); $zipFile = new ZipFile(); $zipFile->deleteFromGlob(''); @@ -722,7 +746,8 @@ class ZipFileTest extends ZipTestCase public function testDeleteFromRegexFailNull() { - $this->setExpectedException(InvalidArgumentException::class, 'The regex pattern is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The regex pattern is not specified'); $zipFile = new ZipFile(); $zipFile->deleteFromRegex(null); @@ -730,7 +755,8 @@ class ZipFileTest extends ZipTestCase public function testDeleteFromRegexFailEmpty() { - $this->setExpectedException(InvalidArgumentException::class, 'The regex pattern is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The regex pattern is not specified'); $zipFile = new ZipFile(); $zipFile->deleteFromRegex(''); @@ -806,10 +832,10 @@ class ZipFileTest extends ZipTestCase */ public function testVeryLongArchiveComment() { - $this->setExpectedException(InvalidArgumentException::class); + $this->expectException(InvalidArgumentException::class); - $comment = 'Very long comment' . \PHP_EOL . - 'Очень длинный комментарий' . \PHP_EOL; + $comment = 'Very long comment' . \PHP_EOL + . 'Очень длинный комментарий' . \PHP_EOL; $comment = str_repeat($comment, ceil(0xffff / \strlen($comment)) + \strlen($comment) + 1); $zipFile = new ZipFile(); @@ -873,7 +899,7 @@ class ZipFileTest extends ZipTestCase static::assertSame($zipFile->getEntryComment($entryName), (string) $entriesItem['comment']); } // modify comment - $entries['file5.txt']['comment'] = mt_rand(1, 100000000); + $entries['file5.txt']['comment'] = random_int(1, 100000000); $zipFile->setEntryComment('file5.txt', $entries['file5.txt']['comment']); $zipFile->saveAsFile($this->outputFilename); $zipFile->close(); @@ -898,10 +924,11 @@ class ZipFileTest extends ZipTestCase */ public function testVeryLongEntryComment() { - $this->setExpectedException(InvalidArgumentException::class, 'Comment too long'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Comment too long'); - $comment = 'Very long comment' . \PHP_EOL . - 'Очень длинный комментарий' . \PHP_EOL; + $comment = 'Very long comment' . \PHP_EOL + . 'Очень длинный комментарий' . \PHP_EOL; $comment = str_repeat($comment, ceil(0xffff / \strlen($comment)) + \strlen($comment) + 1); $zipFile = new ZipFile(); @@ -914,7 +941,7 @@ class ZipFileTest extends ZipTestCase */ public function testSetEntryCommentNotFoundEntry() { - $this->setExpectedException(ZipEntryNotFoundException::class); + $this->expectException(ZipEntryNotFoundException::class); $zipFile = new ZipFile(); $zipFile->setEntryComment('test', 'comment'); @@ -979,8 +1006,10 @@ class ZipFileTest extends ZipTestCase */ public function testSetInvalidCompressionLevel($compressionLevel) { - $this->setExpectedException( - InvalidArgumentException::class, + $this->expectException( + InvalidArgumentException::class + ); + $this->expectExceptionMessage( 'Invalid compression level. Minimum level 1. Maximum level 9' ); @@ -1048,7 +1077,7 @@ class ZipFileTest extends ZipTestCase ); if ($contents === null) { - static::assertTrue(is_dir($fullExtractedFilename)); + static::assertDirectoryExists($fullExtractedFilename); static::assertTrue(FilesUtil::isEmptyDir($fullExtractedFilename)); } else { static::assertTrue(is_file($fullExtractedFilename)); @@ -1106,7 +1135,7 @@ class ZipFileTest extends ZipTestCase if (\in_array($entryName, $extractEntries, true)) { if ($value === null) { - static::assertTrue(is_dir($fullExtractFilename)); + static::assertDirectoryExists($fullExtractFilename); static::assertTrue(FilesUtil::isEmptyDir($fullExtractFilename)); } else { static::assertTrue(is_file($fullExtractFilename)); @@ -1114,7 +1143,7 @@ class ZipFileTest extends ZipTestCase static::assertEquals($contents, $value); } } elseif ($value === null) { - static::assertFalse(is_dir($fullExtractFilename)); + static::assertDirectoryDoesNotExist($fullExtractFilename); } else { static::assertFalse(is_file($fullExtractFilename)); } @@ -1131,7 +1160,8 @@ class ZipFileTest extends ZipTestCase */ public function testExtractFail() { - $this->setExpectedException(ZipException::class, 'not found'); + $this->expectException(ZipException::class); + $this->expectExceptionMessage('not found'); $zipFile = new ZipFile(); $zipFile['file'] = 'content'; @@ -1147,7 +1177,8 @@ class ZipFileTest extends ZipTestCase */ public function testExtractFail2() { - $this->setExpectedException(ZipException::class, 'Destination is not directory'); + $this->expectException(ZipException::class); + $this->expectExceptionMessage('Destination is not directory'); $zipFile = new ZipFile(); $zipFile['file'] = 'content'; @@ -1163,7 +1194,8 @@ class ZipFileTest extends ZipTestCase */ public function testExtractFail3() { - $this->setExpectedException(ZipException::class, 'Destination is not writable directory'); + $this->expectException(ZipException::class); + $this->expectExceptionMessage('Destination is not writable directory'); if (static::skipTestForRootUser()) { return; @@ -1186,8 +1218,10 @@ class ZipFileTest extends ZipTestCase */ public function testAddFromArrayAccessNullName() { - $this->setExpectedException( - InvalidArgumentException::class, + $this->expectException( + InvalidArgumentException::class + ); + $this->expectExceptionMessage( 'Key must not be null, but must contain the name of the zip entry.' ); @@ -1200,8 +1234,10 @@ class ZipFileTest extends ZipTestCase */ public function testAddFromArrayAccessEmptyName() { - $this->setExpectedException( - InvalidArgumentException::class, + $this->expectException( + InvalidArgumentException::class + ); + $this->expectExceptionMessage( 'Key is empty, but must contain the name of the zip entry.' ); @@ -1214,7 +1250,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFromStringNullContents() { - $this->setExpectedException(InvalidArgumentException::class, 'Contents is null'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Contents is null'); $zipFile = new ZipFile(); $zipFile->addFromString('file', null); @@ -1225,7 +1262,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFromStringNullEntryName() { - $this->setExpectedException(InvalidArgumentException::class, 'Entry name is null'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Entry name is null'); $zipFile = new ZipFile(); $zipFile->addFromString(null, 'contents'); @@ -1236,8 +1274,10 @@ class ZipFileTest extends ZipTestCase */ public function testAddFromStringUnsupportedMethod() { - $this->setExpectedException( - ZipUnsupportMethodException::class, + $this->expectException( + ZipUnsupportMethodException::class + ); + $this->expectExceptionMessage( 'Compression method 99 (AES Encryption) is not supported.' ); @@ -1251,7 +1291,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFromStringEmptyEntryName() { - $this->setExpectedException(InvalidArgumentException::class, 'Empty entry name'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Empty entry name'); $zipFile = new ZipFile(); $zipFile->addFromString('', 'contents'); @@ -1292,7 +1333,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFromStreamInvalidResource() { - $this->setExpectedException(InvalidArgumentException::class, 'Stream is not resource'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Stream is not resource'); $zipFile = new ZipFile(); /** @noinspection PhpParamsInspection */ @@ -1304,7 +1346,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFromStreamEmptyEntryName() { - $this->setExpectedException(InvalidArgumentException::class, 'Empty entry name'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Empty entry name'); $handle = fopen(__FILE__, 'rb'); @@ -1317,8 +1360,10 @@ class ZipFileTest extends ZipTestCase */ public function testAddFromStreamUnsupportedMethod() { - $this->setExpectedException( - ZipUnsupportMethodException::class, + $this->expectException( + ZipUnsupportMethodException::class + ); + $this->expectExceptionMessage( 'Compression method 99 (AES Encryption) is not supported.' ); @@ -1367,7 +1412,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFileNullFileName() { - $this->setExpectedException(InvalidArgumentException::class, 'Filename is null'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Filename is null'); $zipFile = new ZipFile(); $zipFile->addFile(null); @@ -1378,7 +1424,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFileCantExists() { - $this->setExpectedException(InvalidArgumentException::class, 'File path/to/file is not readable'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('File path/to/file is not readable'); $zipFile = new ZipFile(); $zipFile->addFile('path/to/file'); @@ -1389,8 +1436,10 @@ class ZipFileTest extends ZipTestCase */ public function testAddFileUnsupportedMethod() { - $this->setExpectedException( - ZipUnsupportMethodException::class, + $this->expectException( + ZipUnsupportMethodException::class + ); + $this->expectExceptionMessage( 'Compression method 99 (AES Encryption) is not supported.' ); @@ -1412,7 +1461,8 @@ class ZipFileTest extends ZipTestCase return; } - $this->setExpectedException(InvalidArgumentException::class, 'is not readable'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('is not readable'); static::assertNotFalse(file_put_contents($this->outputFilename, '')); static::assertTrue(chmod($this->outputFilename, 0244)); @@ -1426,7 +1476,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddDirNullDirname() { - $this->setExpectedException(InvalidArgumentException::class, 'Input dir is null'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Input dir is null'); $zipFile = new ZipFile(); $zipFile->addDir(null); @@ -1437,7 +1488,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddDirEmptyDirname() { - $this->setExpectedException(InvalidArgumentException::class, 'The input directory is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The input directory is not specified'); $zipFile = new ZipFile(); $zipFile->addDir(''); @@ -1448,7 +1500,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddDirCantExists() { - $this->setExpectedException(InvalidArgumentException::class, 'does not exist'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('does not exist'); $zipFile = new ZipFile(); $zipFile->addDir(uniqid('', false)); @@ -1459,7 +1512,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddDirRecursiveNullDirname() { - $this->setExpectedException(InvalidArgumentException::class, 'Input dir is null'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Input dir is null'); $zipFile = new ZipFile(); $zipFile->addDirRecursive(null); @@ -1470,7 +1524,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddDirRecursiveEmptyDirname() { - $this->setExpectedException(InvalidArgumentException::class, 'The input directory is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The input directory is not specified'); $zipFile = new ZipFile(); $zipFile->addDirRecursive(''); @@ -1481,7 +1536,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddDirRecursiveCantExists() { - $this->setExpectedException(InvalidArgumentException::class, 'does not exist'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('does not exist'); $zipFile = new ZipFile(); $zipFile->addDirRecursive(uniqid('', false)); @@ -1492,7 +1548,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromGlobNull() { - $this->setExpectedException(InvalidArgumentException::class, 'Input dir is null'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Input dir is null'); $zipFile = new ZipFile(); $zipFile->addFilesFromGlob(null, '*.png'); @@ -1503,7 +1560,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromGlobEmpty() { - $this->setExpectedException(InvalidArgumentException::class, 'The input directory is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The input directory is not specified'); $zipFile = new ZipFile(); $zipFile->addFilesFromGlob('', '*.png'); @@ -1514,7 +1572,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromGlobCantExists() { - $this->setExpectedException(InvalidArgumentException::class, 'does not exist'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('does not exist'); $zipFile = new ZipFile(); $zipFile->addFilesFromGlob('path/to/path', '*.png'); @@ -1525,7 +1584,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromGlobNullPattern() { - $this->setExpectedException(InvalidArgumentException::class, 'The glob pattern is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The glob pattern is not specified'); $zipFile = new ZipFile(); $zipFile->addFilesFromGlob(__DIR__, null); @@ -1536,7 +1596,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromGlobEmptyPattern() { - $this->setExpectedException(InvalidArgumentException::class, 'The glob pattern is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The glob pattern is not specified'); $zipFile = new ZipFile(); $zipFile->addFilesFromGlob(__DIR__, ''); @@ -1547,7 +1608,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromGlobRecursiveNull() { - $this->setExpectedException(InvalidArgumentException::class, 'Input dir is null'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Input dir is null'); $zipFile = new ZipFile(); $zipFile->addFilesFromGlobRecursive(null, '*.png'); @@ -1558,7 +1620,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromGlobRecursiveEmpty() { - $this->setExpectedException(InvalidArgumentException::class, 'The input directory is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The input directory is not specified'); $zipFile = new ZipFile(); $zipFile->addFilesFromGlobRecursive('', '*.png'); @@ -1569,7 +1632,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromGlobRecursiveCantExists() { - $this->setExpectedException(InvalidArgumentException::class, 'does not exist'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('does not exist'); $zipFile = new ZipFile(); $zipFile->addFilesFromGlobRecursive('path/to/path', '*.png'); @@ -1580,7 +1644,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromGlobRecursiveNullPattern() { - $this->setExpectedException(InvalidArgumentException::class, 'The glob pattern is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The glob pattern is not specified'); $zipFile = new ZipFile(); $zipFile->addFilesFromGlobRecursive(__DIR__, null); @@ -1591,7 +1656,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromGlobRecursiveEmptyPattern() { - $this->setExpectedException(InvalidArgumentException::class, 'The glob pattern is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The glob pattern is not specified'); $zipFile = new ZipFile(); $zipFile->addFilesFromGlobRecursive(__DIR__, ''); @@ -1602,7 +1668,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromRegexDirectoryNull() { - $this->setExpectedException(InvalidArgumentException::class, 'The input directory is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The input directory is not specified'); $zipFile = new ZipFile(); $zipFile->addFilesFromRegex(null, '~\.png$~i'); @@ -1613,7 +1680,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromRegexDirectoryEmpty() { - $this->setExpectedException(InvalidArgumentException::class, 'The input directory is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The input directory is not specified'); $zipFile = new ZipFile(); $zipFile->addFilesFromRegex('', '~\.png$~i'); @@ -1624,7 +1692,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromRegexCantExists() { - $this->setExpectedException(InvalidArgumentException::class, 'does not exist'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('does not exist'); $zipFile = new ZipFile(); $zipFile->addFilesFromRegex('path/to/path', '~\.png$~i'); @@ -1635,7 +1704,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromRegexNullPattern() { - $this->setExpectedException(InvalidArgumentException::class, 'The regex pattern is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The regex pattern is not specified'); $zipFile = new ZipFile(); $zipFile->addFilesFromRegex(__DIR__, null); @@ -1646,7 +1716,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromRegexEmptyPattern() { - $this->setExpectedException(InvalidArgumentException::class, 'The regex pattern is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The regex pattern is not specified'); $zipFile = new ZipFile(); $zipFile->addFilesFromRegex(__DIR__, ''); @@ -1657,7 +1728,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromRegexRecursiveDirectoryNull() { - $this->setExpectedException(InvalidArgumentException::class, 'The input directory is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The input directory is not specified'); $zipFile = new ZipFile(); $zipFile->addFilesFromRegexRecursive(null, '~\.png$~i'); @@ -1668,7 +1740,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromRegexRecursiveEmpty() { - $this->setExpectedException(InvalidArgumentException::class, 'The input directory is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The input directory is not specified'); $zipFile = new ZipFile(); $zipFile->addFilesFromRegexRecursive('', '~\.png$~i'); @@ -1679,7 +1752,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromRegexRecursiveCantExists() { - $this->setExpectedException(InvalidArgumentException::class, 'does not exist'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('does not exist'); $zipFile = new ZipFile(); $zipFile->addFilesFromGlobRecursive('path/to/path', '~\.png$~i'); @@ -1690,7 +1764,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromRegexRecursiveNullPattern() { - $this->setExpectedException(InvalidArgumentException::class, 'The regex pattern is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The regex pattern is not specified'); $zipFile = new ZipFile(); $zipFile->addFilesFromRegexRecursive(__DIR__, null); @@ -1701,7 +1776,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddFilesFromRegexRecursiveEmptyPattern() { - $this->setExpectedException(InvalidArgumentException::class, 'The regex pattern is not specified'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The regex pattern is not specified'); $zipFile = new ZipFile(); $zipFile->addFilesFromRegexRecursive(__DIR__, ''); @@ -1712,7 +1788,8 @@ class ZipFileTest extends ZipTestCase */ public function testSaveAsStreamBadStream() { - $this->setExpectedException(InvalidArgumentException::class, 'handle is not resource'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('handle is not resource'); $zipFile = new ZipFile(); /** @noinspection PhpParamsInspection */ @@ -1737,7 +1814,8 @@ class ZipFileTest extends ZipTestCase $this->outputFilename = $this->outputDirname . \DIRECTORY_SEPARATOR . basename($this->outputFilename); - $this->setExpectedExceptionRegExp(InvalidArgumentException::class, '~Cannot open ".*?" for writing.~'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessageMatches('~Cannot open ".*?" for writing.~'); $zipFile = new ZipFile(); $zipFile->saveAsFile($this->outputFilename); @@ -1752,7 +1830,7 @@ class ZipFileTest extends ZipTestCase public function testZipFileArrayAccessAndCountableAndIterator() { $files = []; - $numFiles = mt_rand(20, 100); + $numFiles = random_int(20, 100); for ($i = 0; $i < $numFiles; $i++) { $files['file' . $i . '.txt'] = random_bytes(255); } @@ -1894,7 +1972,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddEmptyDirNullName() { - $this->setExpectedException(InvalidArgumentException::class, 'Entry name is null'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Entry name is null'); $zipFile = new ZipFile(); $zipFile->addEmptyDir(null); @@ -1905,7 +1984,8 @@ class ZipFileTest extends ZipTestCase */ public function testAddEmptyDirEmptyName() { - $this->setExpectedException(InvalidArgumentException::class, 'Empty entry name'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Empty entry name'); $zipFile = new ZipFile(); $zipFile->addEmptyDir(''); @@ -1913,7 +1993,8 @@ class ZipFileTest extends ZipTestCase public function testNotFoundEntry() { - $this->setExpectedException(ZipEntryNotFoundException::class, '"bad entry name"'); + $this->expectException(ZipEntryNotFoundException::class); + $this->expectExceptionMessage('"bad entry name"'); $zipFile = new ZipFile(); $zipFile['bad entry name']; @@ -1960,7 +2041,8 @@ class ZipFileTest extends ZipTestCase */ public function testRewriteString() { - $this->setExpectedException(ZipException::class, 'Overwrite is only supported for open local files'); + $this->expectException(ZipException::class); + $this->expectExceptionMessage('Overwrite is only supported for open local files'); $zipFile = new ZipFile(); $zipFile['file'] = 'content'; @@ -1986,7 +2068,8 @@ class ZipFileTest extends ZipTestCase */ public function testRewriteNullStream() { - $this->setExpectedException(ZipException::class, 'input stream is null'); + $this->expectException(ZipException::class); + $this->expectExceptionMessage('input stream is null'); $zipFile = new ZipFile(); $zipFile->rewrite(); @@ -2177,7 +2260,8 @@ class ZipFileTest extends ZipTestCase */ public function testInvalidCompressionLevel() { - $this->setExpectedException(InvalidArgumentException::class, 'Invalid compression level'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid compression level'); $zipFile = new ZipFile(); $zipFile->addFromString('file', 'content'); @@ -2189,7 +2273,8 @@ class ZipFileTest extends ZipTestCase */ public function testInvalidCompressionLevelEntry() { - $this->setExpectedException(InvalidArgumentException::class, 'Invalid compression level'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid compression level'); $zipFile = new ZipFile(); $zipFile->addFromString('file', 'content'); @@ -2249,8 +2334,10 @@ class ZipFileTest extends ZipTestCase */ public function testInvalidCompressionMethodEntry() { - $this->setExpectedException( - ZipUnsupportMethodException::class, + $this->expectException( + ZipUnsupportMethodException::class + ); + $this->expectExceptionMessage( 'Compression method 99 (AES Encryption) is not supported.' ); @@ -2428,7 +2515,7 @@ class ZipFileTest extends ZipTestCase { for ($i = 0; $i < 2; $i++) { $fp = $zipFile->getEntryStream($entryName); - static::assertInternalType('resource', $fp); + static::assertIsResource($fp); static::assertSame(stream_get_contents($fp), $contents); fclose($fp); } @@ -2566,7 +2653,8 @@ class ZipFileTest extends ZipTestCase */ public function testNoData() { - $this->setExpectedException(ZipException::class, 'No data for zip entry file'); + $this->expectException(ZipException::class); + $this->expectExceptionMessage('No data for zip entry file'); $entryName = 'file'; diff --git a/tests/ZipInfoTest.php b/tests/ZipInfoTest.php index 4706ca6..ce30c35 100644 --- a/tests/ZipInfoTest.php +++ b/tests/ZipInfoTest.php @@ -54,8 +54,10 @@ final class ZipInfoTest extends ZipTestCase */ public function testZipInfoEntryNotFound() { - $this->setExpectedException( - ZipEntryNotFoundException::class, + $this->expectException( + ZipEntryNotFoundException::class + ); + $this->expectExceptionMessage( 'Zip Entry "unknown.name" was not found in the archive.' ); diff --git a/tests/ZipMatcherTest.php b/tests/ZipMatcherTest.php index 415af67..18fbc56 100644 --- a/tests/ZipMatcherTest.php +++ b/tests/ZipMatcherTest.php @@ -24,7 +24,7 @@ class ZipMatcherTest extends TestCase $matcher = $zipFile->matcher(); static::assertInstanceOf(ZipEntryMatcher::class, $matcher); - static::assertInternalType('array', $matcher->getMatches()); + static::assertIsArray($matcher->getMatches()); static::assertCount(0, $matcher); $matcher->add(1)->add(10)->add(20); diff --git a/tests/ZipPasswordTest.php b/tests/ZipPasswordTest.php index 88a93b0..e047201 100644 --- a/tests/ZipPasswordTest.php +++ b/tests/ZipPasswordTest.php @@ -31,10 +31,8 @@ class ZipPasswordTest extends ZipFileSetTestCase public function testSetPassword() { if (\PHP_INT_SIZE === 4) { // php 32 bit - $this->setExpectedException( - RuntimeException::class, - 'Traditional PKWARE Encryption is not supported in 32-bit PHP.' - ); + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Traditional PKWARE Encryption is not supported in 32-bit PHP.'); } $password = base64_encode(random_bytes(100)); @@ -66,10 +64,10 @@ class ZipPasswordTest extends ZipFileSetTestCase foreach ($zipFile->getAllInfo() as $info) { static::assertTrue($info->isEncrypted()); - static::assertContains('Traditional PKWARE encryption', $info->getEncryptionMethodName()); + static::assertStringContainsString('Traditional PKWARE encryption', $info->getEncryptionMethodName()); $decryptContent = $zipFile[$info->getName()]; static::assertNotEmpty($decryptContent); - static::assertContains('getAllInfo() as $info) { static::assertTrue($info->isEncrypted()); - static::assertContains('Deflated', $info->getMethodName()); - static::assertContains('WinZip AES-256', $info->getEncryptionMethodName()); + static::assertStringContainsString('Deflated', $info->getMethodName()); + static::assertStringContainsString('WinZip AES-256', $info->getEncryptionMethodName()); $decryptContent = $zipFile[$info->getName()]; static::assertNotEmpty($decryptContent); - static::assertContains('setExpectedException( - RuntimeException::class, + $this->expectException( + RuntimeException::class + ); + $this->expectExceptionMessage( 'Traditional PKWARE Encryption is not supported in 32-bit PHP.' ); } @@ -155,7 +155,7 @@ class ZipPasswordTest extends ZipFileSetTestCase foreach ($zip->getAllInfo() as $info) { if (!$info->isFolder()) { static::assertTrue($info->isEncrypted()); - static::assertContains('Traditional PKWARE encryption', $info->getEncryptionMethodName()); + static::assertStringContainsString('Traditional PKWARE encryption', $info->getEncryptionMethodName()); } } $zip->close(); @@ -190,7 +190,7 @@ class ZipPasswordTest extends ZipFileSetTestCase if (!$info->isFolder()) { static::assertTrue($info->isEncrypted()); static::assertSame($info->getEncryptionMethod(), $encryptionMethod); - static::assertContains('WinZip AES-' . $bitSize, $info->getEncryptionMethodName()); + static::assertStringContainsString('WinZip AES-' . $bitSize, $info->getEncryptionMethodName()); } } $zip->close(); @@ -215,8 +215,10 @@ class ZipPasswordTest extends ZipFileSetTestCase public function testEncryptionEntries() { if (\PHP_INT_SIZE === 4) { // php 32 bit - $this->setExpectedException( - RuntimeException::class, + $this->expectException( + RuntimeException::class + ); + $this->expectExceptionMessage( 'Traditional PKWARE Encryption is not supported in 32-bit PHP.' ); } @@ -247,11 +249,11 @@ class ZipPasswordTest extends ZipFileSetTestCase $info = $zip->getEntryInfo('.hidden'); static::assertTrue($info->isEncrypted()); - static::assertContains('Traditional PKWARE encryption', $info->getEncryptionMethodName()); + static::assertStringContainsString('Traditional PKWARE encryption', $info->getEncryptionMethodName()); $info = $zip->getEntryInfo('text file.txt'); static::assertTrue($info->isEncrypted()); - static::assertContains('WinZip AES', $info->getEncryptionMethodName()); + static::assertStringContainsString('WinZip AES', $info->getEncryptionMethodName()); static::assertFalse($zip->getEntryInfo('Текстовый документ.txt')->isEncrypted()); static::assertFalse($zip->getEntryInfo('empty dir/')->isEncrypted()); @@ -266,8 +268,10 @@ class ZipPasswordTest extends ZipFileSetTestCase public function testEncryptionEntriesWithDefaultPassword() { if (\PHP_INT_SIZE === 4) { // php 32 bit - $this->setExpectedException( - RuntimeException::class, + $this->expectException( + RuntimeException::class + ); + $this->expectExceptionMessage( 'Traditional PKWARE Encryption is not supported in 32-bit PHP.' ); } @@ -301,15 +305,15 @@ class ZipPasswordTest extends ZipFileSetTestCase $info = $zip->getEntryInfo('.hidden'); static::assertTrue($info->isEncrypted()); - static::assertContains('Traditional PKWARE encryption', $info->getEncryptionMethodName()); + static::assertStringContainsString('Traditional PKWARE encryption', $info->getEncryptionMethodName()); $info = $zip->getEntryInfo('text file.txt'); static::assertTrue($info->isEncrypted()); - static::assertContains('WinZip AES', $info->getEncryptionMethodName()); + static::assertStringContainsString('WinZip AES', $info->getEncryptionMethodName()); $info = $zip->getEntryInfo('Текстовый документ.txt'); static::assertTrue($info->isEncrypted()); - static::assertContains('WinZip AES', $info->getEncryptionMethodName()); + static::assertStringContainsString('WinZip AES', $info->getEncryptionMethodName()); static::assertFalse($zip->getEntryInfo('empty dir/')->isEncrypted()); @@ -321,7 +325,8 @@ class ZipPasswordTest extends ZipFileSetTestCase */ public function testSetEncryptionMethodInvalid() { - $this->setExpectedException(InvalidArgumentException::class, 'Encryption method 9999 is not supported.'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Encryption method 9999 is not supported.'); $zipFile = new ZipFile(); $encryptionMethod = 9999; @@ -369,7 +374,8 @@ class ZipPasswordTest extends ZipFileSetTestCase */ public function testInvalidEncryptionMethodEntry() { - $this->setExpectedException(InvalidArgumentException::class, 'Encryption method 99 is not supported.'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Encryption method 99 is not supported.'); $zipFile = new ZipFile(); $zipFile->addFromString('file', 'content', ZipCompressionMethod::STORED); @@ -471,7 +477,7 @@ class ZipPasswordTest extends ZipFileSetTestCase foreach ($zipFile as $name => $contents) { static::assertNotEmpty($name); static::assertNotEmpty($contents); - static::assertContains('test contents', $contents); + static::assertStringContainsString('test contents', $contents); static::assertSame($zipFile2[$name], $contents); } $zipFile2->close(); diff --git a/tests/ZipStreamOpenTest.php b/tests/ZipStreamOpenTest.php index 42e98e0..2c426ff 100644 --- a/tests/ZipStreamOpenTest.php +++ b/tests/ZipStreamOpenTest.php @@ -31,18 +31,18 @@ class ZipStreamOpenTest extends TestCase { if ($resource === null || $resource === false) { static::markTestSkipped('skip resource'); - - return; } if ($exceptionClass !== null) { - $this->setExpectedException( - $exceptionClass, + $this->expectException( + $exceptionClass + ); + $this->expectExceptionMessage( $exceptionMessage ); } - static::assertInternalType('resource', $resource); + static::assertIsResource($resource); $zipFile = new ZipFile(); $zipFile->openFromStream($resource); diff --git a/tests/ZipTestCase.php b/tests/ZipTestCase.php index e195c43..993ee72 100644 --- a/tests/ZipTestCase.php +++ b/tests/ZipTestCase.php @@ -2,14 +2,14 @@ namespace PhpZip\Tests; -use PHPUnit\Framework\TestCase; use PhpZip\Constants\ZipConstants; +use PhpZip\Tests\Polyfill\LegacyTestCase; use PhpZip\Util\FilesUtil; /** * PHPUnit test case and helper methods. */ -abstract class ZipTestCase extends TestCase +abstract class ZipTestCase extends LegacyTestCase { /** @var string */ protected $outputFilename; @@ -22,7 +22,7 @@ abstract class ZipTestCase extends TestCase * * @noinspection PhpMissingParentCallCommonInspection */ - protected function setUp() + protected function setUp(): void { $id = uniqid('phpzip', false); $tempDir = sys_get_temp_dir() . \DIRECTORY_SEPARATOR . 'phpunit-phpzip'; @@ -37,10 +37,8 @@ abstract class ZipTestCase extends TestCase /** * After test. */ - protected function tearDown() + protected function tearDown(): void { - parent::tearDown(); - if ($this->outputFilename !== null && file_exists($this->outputFilename)) { unlink($this->outputFilename); } @@ -92,8 +90,8 @@ abstract class ZipTestCase extends TestCase $output = implode(\PHP_EOL, $output); static::assertSame($returnCode, 0); - static::assertNotContains(' Errors', $output); - static::assertContains(' Ok', $output); + static::assertStringNotContainsString(' Errors', $output); + static::assertStringContainsString(' Ok', $output); } /** @@ -123,8 +121,8 @@ abstract class ZipTestCase extends TestCase static::assertSame($returnCode, 0, $output); static::assertNotContains('incorrect password', $output); - static::assertContains(' OK', $output); - static::assertContains('No errors', $output); + static::assertStringContainsString(' OK', $output); + static::assertStringContainsString('No errors', $output); } /** @@ -135,9 +133,9 @@ abstract class ZipTestCase extends TestCase */ protected static function existsProgram($program, array $successCodes = [0]) { - $command = \DIRECTORY_SEPARATOR === '\\' ? - escapeshellarg($program) : - 'which ' . escapeshellarg($program); + $command = \DIRECTORY_SEPARATOR === '\\' + ? escapeshellarg($program) + : 'which ' . escapeshellarg($program); $command .= ' 2>&1'; exec($command, $output, $returnCode); @@ -157,7 +155,7 @@ abstract class ZipTestCase extends TestCase $output = implode(\PHP_EOL, $output); - static::assertContains('Empty zipfile', $output); + static::assertStringContainsString('Empty zipfile', $output); } $actualEmptyZipData = pack('VVVVVv', ZipConstants::END_CD, 0, 0, 0, 0, 0); static::assertStringEqualsFile($filename, $actualEmptyZipData); @@ -189,7 +187,7 @@ abstract class ZipTestCase extends TestCase fwrite(\STDERR, 'Install on Windows:' . \PHP_EOL); fwrite(\STDERR, ' 1. Install Android Studio' . \PHP_EOL); fwrite(\STDERR, ' 2. Install Android Sdk' . \PHP_EOL); - fwrite(\STDERR, ' 3. Add zipalign path to \$Path' . \PHP_EOL); + fwrite(\STDERR, ' 3. Add zipalign path to $Path' . \PHP_EOL); return null; }