1
0
mirror of https://github.com/Ne-Lexa/php-zip.git synced 2025-01-16 14:58:26 +01:00

php8 support

This commit is contained in:
Ne-Lexa 2021-02-22 13:12:01 +03:00
parent 44c2041f62
commit a65fe4579b
118 changed files with 4060 additions and 6568 deletions

1
.gitattributes vendored
View File

@ -2,7 +2,6 @@
.github export-ignore
.gitignore export-ignore
.php_cs export-ignore
.travis.yml export-ignore
bootstrap.php export-ignore
phpunit.xml export-ignore
tests export-ignore

View File

@ -1,48 +1,86 @@
name: build
on: [ push, pull_request ]
on:
- push
- pull_request
jobs:
run:
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: [ubuntu-latest]
php-versions: ['7.2', '7.3', '7.4', '8.0']
name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }}
tests:
name: PHP ${{ matrix.php }} Test on ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
extensions: mbstring, intl, zip
coverage: none
- 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 for PHP 7
if: matrix.php-versions < '8.0'
run: composer update --prefer-dist --no-progress
- name: Install dependencies for PHP 8
if: matrix.php-versions >= '8.0'
run: composer update --prefer-dist --no-progress --ignore-platform-req=php
- name: Run test suite
run: composer check
env:
PHP_CS_FIXER_IGNORE_ENV: 1
extensions: bz2, dom, iconv, fileinfo, openssl, xml, zlib
key: cache-v1
strategy:
matrix:
os:
- ubuntu-latest
- windows-latest
php:
- '7.4'
- '8.0'
runs-on: ${{ matrix.os }}
steps:
-
name: Checkout
uses: actions/checkout@v1
-
name: Install linux dependencies
run: sudo apt-get install unzip p7zip-full
-
name: Install PHP with extensions
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: ${{ env.extensions }}
coverage: pcov
ini-values: date.timezone='UTC'
tools: composer:v2
-
name: Determine composer cache directory on Linux
if: matrix.os == 'ubuntu-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: Cache dependencies installed with composer
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
run: vendor/bin/phpunit --colors=always

671
.php_cs

File diff suppressed because it is too large Load Diff

View File

@ -1,67 +0,0 @@
language: php
env:
global:
- COVERAGE=false
- PHPUNIT_FLAGS="-v -c phpunit.xml"
matrix:
include:
- php: 5.5
os: linux
dist: trusty
env: ZIPALIGN_INSTALL=false
- php: 5.6
os: linux
dist: xenial
env: ZIPALIGN_INSTALL=true
- php: 7.0
os: linux
dist: xenial
env: ZIPALIGN_INSTALL=true
- php: 7.1
os: linux
dist: xenial
env: ZIPALIGN_INSTALL=true
- php: 7.2
os: linux
dist: xenial
env: ZIPALIGN_INSTALL=true
- php: 7.3
os: linux
dist: xenial
env: ZIPALIGN_INSTALL=true
- php: 7.4
os: linux
dist: xenial
env: COVERAGE=true ZIPALIGN_INSTALL=true PHPUNIT_FLAGS="-v -c phpunit.xml --coverage-clover=coverage.clover"
before_install:
- if [[ $COVERAGE != true ]]; then phpenv config-rm xdebug.ini || true; fi
install:
- travis_retry composer self-update && composer --version
- travis_retry composer install --no-interaction
addons:
apt:
packages:
- unzip
- p7zip-full
before_script:
- if [[ $ZIPALIGN_INSTALL = true ]]; then sudo apt-get install -y zipalign; fi
script:
- composer validate --no-check-lock
- vendor/bin/phpunit ${PHPUNIT_FLAGS}
after_success:
- if [[ $COVERAGE = true ]]; then wget https://scrutinizer-ci.com/ocular.phar; fi
- if [[ $COVERAGE = true ]]; then php ocular.phar code-coverage:upload --format=php-clover coverage.clover; fi

View File

@ -28,7 +28,6 @@
+ [Удаление записей из архива](#Documentation-Remove-Zip-Entries)
+ [Работа с записями и с архивом](#Documentation-Entries)
+ [Работа с паролями](#Documentation-Password)
+ [zipalign - выравнивание архива для оптимизации Android пакетов (APK)](#Documentation-ZipAlign-Usage)
+ [Отмена изменений](#Documentation-Unchanged)
+ [Сохранение файла или вывод в браузер](#Documentation-Save-Or-Output-Entries)
+ [Закрытие архива](#Documentation-Close-Zip-Archive)
@ -50,8 +49,7 @@
+ Deflate сжатие.
+ BZIP2 сжатие при наличии расширения `php-bz2`.
- Поддержка `ZIP64` (размер файла более 4 GB или количество записей в архиве более 65535).
- Встроенная поддержка выравнивания архива для оптимизации Android пакетов (APK) [`zipalign`](https://developer.android.com/studio/command-line/zipalign.html).
- Работа с паролями для PHP 5.5
- Работа с паролями
> **Внимание!**
>
> Для 32-bit систем, в данный момент не поддерживается метод шифрование `Traditional PKWARE Encryption (ZipCrypto)`.
@ -66,9 +64,9 @@
+ Установка метода шифрования для всех или для отдельных записей в архиве.
### <a name="Requirements"></a> Требования
- `PHP` >= 5.5 (предпочтительно 64-bit).
- `PHP` 7.4 или ^8.0 (предпочтительно 64-bit).
- Опционально php-расширение `bzip2` для поддержки BZIP2 компрессии.
- Опционально php-расширение `openssl` или `mcrypt` для `WinZip Aes Encryption` шифрования.
- Опционально php-расширение `openssl` для `WinZip Aes Encryption` шифрования.
### <a name="Installation"></a> Установка
`composer require nelexa/zip`
@ -110,10 +108,10 @@ finally{
### <a name="Documentation"></a> Документация
#### <a name="Documentation-Overview"></a> Обзор методов класса `\PhpZip\ZipFile`
- [ZipFile::__construct](#Documentation-ZipFile-__construct) - инициализацирует ZIP-архив.
- [ZipFile::__construct](#Documentation-ZipFile-__construct) - инициализирует ZIP-архив.
- [ZipFile::addAll](#Documentation-ZipFile-addAll) - добавляет все записи из массива.
- [ZipFile::addDir](#Documentation-ZipFile-addDir) - добавляет файлы из директории по указанному пути без вложенных директорий.
- [ZipFile::addDirRecursive](#Documentation-ZipFile-addDirRecursive) - добавляет файлы из директории по указанному пути c вложенными директориями.
- [ZipFile::addDirRecursive](#Documentation-ZipFile-addDirRecursive) - добавляет файлы из директории по указанному пути с вложенными директориями.
- [ZipFile::addEmptyDir](#Documentation-ZipFile-addEmptyDir) - добавляет в ZIP-архив новую директорию.
- [ZipFile::addFile](#Documentation-ZipFile-addFile) - добавляет в ZIP-архив файл по указанному пути.
- [ZipFile::addSplFile](#Documentation-ZipFile-addSplFile) - добавляет объект `\SplFileInfo` в zip-архив.
@ -122,7 +120,7 @@ finally{
- [ZipFile::addFilesFromGlob](#Documentation-ZipFile-addFilesFromGlob) - добавляет файлы из директории в соответствии с glob шаблоном без вложенных директорий.
- [ZipFile::addFilesFromGlobRecursive](#Documentation-ZipFile-addFilesFromGlobRecursive) - добавляет файлы из директории в соответствии с glob шаблоном c вложенными директориями.
- [ZipFile::addFilesFromRegex](#Documentation-ZipFile-addFilesFromRegex) - добавляет файлы из директории в соответствии с регулярным выражением без вложенных директорий.
- [ZipFile::addFilesFromRegexRecursive](#Documentation-ZipFile-addFilesFromRegexRecursive) - добавляет файлы из директории в соответствии с регулярным выражением c вложенными директориями.
- [ZipFile::addFilesFromRegexRecursive](#Documentation-ZipFile-addFilesFromRegexRecursive) - добавляет файлы из директории в соответствии с регулярным выражением с вложенными директориями.
- [ZipFile::addFromStream](#Documentation-ZipFile-addFromStream) - добавляет в ZIP-архив запись из потока.
- [ZipFile::addFromString](#Documentation-ZipFile-addFromString) - добавляет файл в ZIP-архив, используя его содержимое в виде строки.
- [ZipFile::close](#Documentation-ZipFile-close) - закрывает ZIP-архив.
@ -134,11 +132,9 @@ finally{
- [ZipFile::disableEncryption](#Documentation-ZipFile-disableEncryption) - отключает шифрования всех записей, находящихся в архиве.
- [ZipFile::disableEncryptionEntry](#Documentation-ZipFile-disableEncryptionEntry) - отключает шифрование записи по её имени.
- [ZipFile::extractTo](#Documentation-ZipFile-extractTo) - извлекает содержимое архива в заданную директорию.
- [ZipFile::getAllInfo](#Documentation-ZipFile-getAllInfo) - возвращает подробную информацию обо всех записях в архиве.
- [ZipFile::getArchiveComment](#Documentation-ZipFile-getArchiveComment) - возвращает комментарий ZIP-архива.
- [ZipFile::getEntryComment](#Documentation-ZipFile-getEntryComment) - возвращает комментарий к записи, используя её имя.
- [ZipFile::getEntryContent](#Documentation-ZipFile-getEntryContent) - возвращает содержимое записи.
- [ZipFile::getEntryInfo](#Documentation-ZipFile-getEntryInfo) - возвращает подробную информацию о записи в архиве.
- [ZipFile::getListFiles](#Documentation-ZipFile-getListFiles) - возвращает список файлов архива.
- [ZipFile::hasEntry](#Documentation-ZipFile-hasEntry) - проверяет, присутствует ли запись в архиве.
- [ZipFile::isDirectory](#Documentation-ZipFile-isDirectory) - проверяет, является ли запись в архиве директорией.
@ -160,15 +156,11 @@ finally{
- [ZipFile::setEntryComment](#Documentation-ZipFile-setEntryComment) - устанавливает комментарий к записи, используя её имя.
- [ZipFile::setReadPassword](#Documentation-ZipFile-setReadPassword) - устанавливает пароль на чтение открытого запароленного архива для всех зашифрованных записей.
- [ZipFile::setReadPasswordEntry](#Documentation-ZipFile-setReadPasswordEntry) - устанавливает пароль на чтение конкретной зашифрованной записи открытого запароленного архива.
- ~~ZipFile::withNewPassword~~ - устаревший метод (**deprecated**) используйте метод [ZipFile::setPassword](#Documentation-ZipFile-setPassword).
- [ZipFile::setPassword](#Documentation-ZipFile-setPassword) - устанавливает новый пароль для всех файлов, находящихся в архиве.
- [ZipFile::setPasswordEntry](#Documentation-ZipFile-setPasswordEntry) - устанавливает новый пароль для конкретного файла.
- [ZipFile::setZipAlign](#Documentation-ZipFile-setZipAlign) - устанавливает выравнивание архива для оптимизации APK файлов (Android packages).
- [ZipFile::unchangeAll](#Documentation-ZipFile-unchangeAll) - отменяет все изменения, сделанные в архиве.
- [ZipFile::unchangeArchiveComment](#Documentation-ZipFile-unchangeArchiveComment) - отменяет изменения в комментарии к архиву.
- [ZipFile::unchangeEntry](#Documentation-ZipFile-unchangeEntry) - отменяет изменения для конкретной записи архива.
- ~~ZipFile::withoutPassword~~ - устаревший метод (**deprecated**) используйте метод [ZipFile::disableEncryption](#Documentation-ZipFile-disableEncryption).
- ~~ZipFile::withReadPassword~~ - устаревший метод (**deprecated**) используйте метод [ZipFile::setReadPassword](#Documentation-ZipFile-setReadPassword).
#### <a name="Documentation-Open-Zip-Archive"></a> Создание/Открытие ZIP-архива
<a name="Documentation-ZipFile-__construct"></a>**ZipFile::__construct** - Инициализацирует ZIP-архив.
@ -289,15 +281,6 @@ $commentArchive = $zipFile->getArchiveComment();
```php
$commentEntry = $zipFile->getEntryComment($entryName);
```
<a name="Documentation-ZipFile-getEntryInfo"></a> **ZipFile::getEntryInfo** - возвращает подробную информацию о записи в архиве.
```php
$zipFile = new \PhpZip\ZipFile();
$zipInfo = $zipFile->getEntryInfo('file.txt');
```
<a name="Documentation-ZipFile-getAllInfo"></a> **ZipFile::getAllInfo** - возвращает подробную информацию обо всех записях в архиве.
```php
$zipAllInfo = $zipFile->getAllInfo();
```
#### <a name="Documentation-Add-Zip-Entries"></a> Добавление записей в архив
Все методы добавления записей в ZIP-архив позволяют указать метод сжатия содержимого.
@ -395,7 +378,7 @@ $zipFile[$path] = null;
$entries = [
'file.txt' => 'file contents', // запись из строки данных
'empty dir/' => null, // пустой каталог
'path/to/file.jpg' => fopen('..../filename', 'r'), // запись из потока
'path/to/file.jpg' => fopen('..../filename', 'rb'), // запись из потока
'path/to/file.dat' => new \SplFileInfo('..../filename'), // запись из файла
];
@ -683,18 +666,6 @@ $zipFile->disableEncryption();
```php
$zipFile->disableEncryptionEntry($entryName);
```
#### <a name="Documentation-ZipAlign-Usage"></a> zipalign
<a name="Documentation-ZipFile-setZipAlign"></a> **ZipFile::setZipAlign** - устанавливает выравнивание архива для оптимизации APK файлов (Android packages).
Метод добавляет паддинги незашифрованным и не сжатым записям, для оптимизации расхода памяти в системе Android. Рекомендуется использовать для `APK` файлов. Файл может незначительно увеличиться.
Этот метод является альтернативой вызова команды `zipalign -f -v 4 filename.zip`.
Подробнее можно ознакомиться по [ссылке](https://developer.android.com/studio/command-line/zipalign.html).
```php
// вызовите до сохранения или вывода архива
$zipFile->setZipAlign(4);
```
#### <a name="Documentation-Unchanged"></a> Отмена изменений
<a name="Documentation-ZipFile-unchangeAll"></a> **ZipFile::unchangeAll** - отменяет все изменения, сделанные в архиве.
```php
@ -731,7 +702,7 @@ $zipFile->outputAsAttachment($outputFilename);
```
Можно установить MIME-тип:
```php
$mimeType = 'application/zip'
$mimeType = 'application/zip';
$zipFile->outputAsAttachment($outputFilename, $mimeType);
```
<a name="Documentation-ZipFile-outputAsResponse"></a> **ZipFile::outputAsResponse** - выводит ZIP-архив, как Response [PSR-7](http://www.php-fig.org/psr/psr-7/).
@ -743,7 +714,7 @@ $zipFile->outputAsResponse($response, $outputFilename);
```
Можно установить MIME-тип:
```php
$mimeType = 'application/zip'
$mimeType = 'application/zip';
$zipFile->outputAsResponse($response, $outputFilename, $mimeType);
```
Пример для Slim Framework:

View File

@ -6,11 +6,16 @@
[![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)
[Russian Documentation](README.RU.md)
### Versions & Dependencies
| Version | PHP | Documentation |
| ------------------- | ---------- | -------------------------------------------------------------------- |
| ^4.0 (master) | ^7.4\|^8.0 | current |
| ^3.0 | ^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)
@ -28,13 +33,13 @@ Table of contents
+ [Deleting entries from the archive](#Documentation-Remove-Zip-Entries)
+ [Working with entries and archive](#Documentation-Entries)
+ [Working with passwords](#Documentation-Password)
+ [zipalign - alignment tool for Android (APK) files](#Documentation-ZipAlign-Usage)
+ [Undo changes](#Documentation-Unchanged)
+ [Saving a file or output to a browser](#Documentation-Save-Or-Output-Entries)
+ [Closing the archive](#Documentation-Close-Zip-Archive)
- [Running the tests](#Running-Tests)
- [Changelog](#Changelog)
- [Upgrade](#Upgrade)
+ [Upgrade version 3 to version 4](#Upgrade-v3-to-v4)
+ [Upgrade version 2 to version 3.0](#Upgrade-v2-to-v3)
### <a name="Features"></a> Features
@ -50,8 +55,7 @@ Table of contents
+ Deflate compression.
+ BZIP2 compression with the extension `php-bz2`.
- Support for `ZIP64` (file size is more than 4 GB or the number of entries in the archive is more than 65535).
- Built-in support for aligning the archive to optimize Android packages (APK) [`zipalign`](https://developer.android.com/studio/command-line/zipalign.html).
- Working with passwords for PHP 5.5
- Working with passwords
> **Attention!**
>
> For 32-bit systems, the `Traditional PKWARE Encryption (ZipCrypto)` encryption method is not currently supported.
@ -66,9 +70,9 @@ Table of contents
+ Set the encryption method for all or individual entries in the archive.
### <a name="Requirements"></a> Requirements
- `PHP` >= 7.2 or `PHP` >= 8.0 (preferably 64-bit).
- `PHP` >= 7.4 or `PHP` >= 8.0 (preferably 64-bit).
- Optional php-extension `bzip2` for BZIP2 compression.
- Optional php-extension `openssl` or `mcrypt` for `WinZip Aes Encryption` support.
- Optional php-extension `openssl` for `WinZip Aes Encryption` support.
### <a name="Installation"></a> Installation
`composer require nelexa/zip`
@ -123,22 +127,20 @@ Other examples can be found in the `tests/` folder
- [ZipFile::addFilesFromGlobRecursive](#Documentation-ZipFile-addFilesFromGlobRecursive) - adds files from a directory by glob pattern with subdirectories.
- [ZipFile::addFilesFromRegex](#Documentation-ZipFile-addFilesFromRegex) - adds files from a directory by PCRE pattern without subdirectories.
- [ZipFile::addFilesFromRegexRecursive](#Documentation-ZipFile-addFilesFromRegexRecursive) - adds files from a directory by PCRE pattern with subdirectories.
- [ZipFile::addFromStream](#Documentation-ZipFile-addFromStream) - adds a entry from the stream to the ZIP archive.
- [ZipFile::addFromStream](#Documentation-ZipFile-addFromStream) - adds an entry from the stream to the ZIP archive.
- [ZipFile::addFromString](#Documentation-ZipFile-addFromString) - adds a file to a ZIP archive using its contents.
- [ZipFile::close](#Documentation-ZipFile-close) - close the archive.
- [ZipFile::count](#Documentation-ZipFile-count) - returns the number of entries in the archive.
- [ZipFile::deleteFromName](#Documentation-ZipFile-deleteFromName) - deletes an entry in the archive using its name.
- [ZipFile::deleteFromGlob](#Documentation-ZipFile-deleteFromGlob) - deletes a entries in the archive using glob pattern.
- [ZipFile::deleteFromRegex](#Documentation-ZipFile-deleteFromRegex) - deletes a entries in the archive using PCRE pattern.
- [ZipFile::deleteFromGlob](#Documentation-ZipFile-deleteFromGlob) - deletes an entries in the archive using glob pattern.
- [ZipFile::deleteFromRegex](#Documentation-ZipFile-deleteFromRegex) - deletes an entries in the archive using PCRE pattern.
- [ZipFile::deleteAll](#Documentation-ZipFile-deleteAll) - deletes all entries in the ZIP archive.
- [ZipFile::disableEncryption](#Documentation-ZipFile-disableEncryption) - disable encryption for all entries that are already in the archive.
- [ZipFile::disableEncryptionEntry](#Documentation-ZipFile-disableEncryptionEntry) - disable encryption of an entry defined by its name.
- [ZipFile::extractTo](#Documentation-ZipFile-extractTo) - extract the archive contents.
- [ZipFile::getAllInfo](#Documentation-ZipFile-getAllInfo) - returns detailed information about all entries in the archive.
- [ZipFile::getArchiveComment](#Documentation-ZipFile-getArchiveComment) - returns the Zip archive comment.
- [ZipFile::getEntryComment](#Documentation-ZipFile-getEntryComment) - returns the comment of an entry using the entry name.
- [ZipFile::getEntryContent](#Documentation-ZipFile-getEntryContent) - returns the entry contents using its name.
- [ZipFile::getEntryInfo](#Documentation-ZipFile-getEntryInfo) - returns detailed information about the entry in the archive.
- [ZipFile::getListFiles](#Documentation-ZipFile-getListFiles) - returns list of archive files.
- [ZipFile::hasEntry](#Documentation-ZipFile-hasEntry) - checks if there is an entry in the archive.
- [ZipFile::isDirectory](#Documentation-ZipFile-isDirectory) - checks that the entry in the archive is a directory.
@ -160,15 +162,11 @@ Other examples can be found in the `tests/` folder
- [ZipFile::setEntryComment](#Documentation-ZipFile-setEntryComment) - set the comment of an entry defined by its name.
- [ZipFile::setReadPassword](#Documentation-ZipFile-setReadPassword) - set the password for the open archive.
- [ZipFile::setReadPasswordEntry](#Documentation-ZipFile-setReadPasswordEntry) - sets a password for reading of an entry defined by its name.
- ~~ZipFile::withNewPassword~~ - is an deprecated method, use the [ZipFile::setPassword](#Documentation-ZipFile-setPassword) method.
- [ZipFile::setPassword](#Documentation-ZipFile-setPassword) - sets a new password for all files in the archive.
- [ZipFile::setPasswordEntry](#Documentation-ZipFile-setPasswordEntry) - sets a new password of an entry defined by its name.
- [ZipFile::setZipAlign](#Documentation-ZipFile-setZipAlign) - sets the alignment of the archive to optimize APK files (Android packages).
- [ZipFile::unchangeAll](#Documentation-ZipFile-unchangeAll) - undo all changes done in the archive.
- [ZipFile::unchangeArchiveComment](#Documentation-ZipFile-unchangeArchiveComment) - undo changes to the archive comment.
- [ZipFile::unchangeEntry](#Documentation-ZipFile-unchangeEntry) - undo changes of an entry defined by its name.
- ~~ZipFile::withoutPassword~~ - is an deprecated method, use the [ZipFile::disableEncryption](#Documentation-ZipFile-disableEncryption) method.
- ~~ZipFile::withReadPassword~~ - is an deprecated method, use the [ZipFile::setReadPassword](#Documentation-ZipFile-setReadPassword) method.
#### <a name="Documentation-Open-Zip-Archive"></a> Creation/Opening of ZIP-archive
<a name="Documentation-ZipFile-__construct"></a>**ZipFile::__construct** - initializes the ZIP archive.
@ -293,15 +291,6 @@ $commentArchive = $zipFile->getArchiveComment();
$zipFile = new \PhpZip\ZipFile();
$commentEntry = $zipFile->getEntryComment($entryName);
```
<a name="Documentation-ZipFile-getEntryInfo"></a> **ZipFile::getEntryInfo** - returns detailed information about the entry in the archive
```php
$zipFile = new \PhpZip\ZipFile();
$zipInfo = $zipFile->getEntryInfo('file.txt');
```
<a name="Documentation-ZipFile-getAllInfo"></a> **ZipFile::getAllInfo** - returns detailed information about all entries in the archive.
```php
$zipAllInfo = $zipFile->getAllInfo();
```
#### <a name="Documentation-Add-Zip-Entries"></a> Adding entries to the archive
All methods of adding entries to a ZIP archive allow you to specify a method for compressing content.
@ -346,7 +335,7 @@ $zipFile->addSplFile($splFile, $entryName, $options = [
]);
```
<a name="Documentation-ZipFile-addFromFinder"></a>
**ZipFile::addFromFinder"** - adds files from the `Symfony\Component\Finder\Finder` to a ZIP archive.
**ZipFile::addFromFinder** - adds files from the `Symfony\Component\Finder\Finder` to a ZIP archive.
https://symfony.com/doc/current/components/finder.html
```php
$finder = new \Symfony\Component\Finder\Finder();
@ -376,7 +365,7 @@ $zipFile->addFromString($entryName, $contents, \PhpZip\Constants\ZipCompressionM
$zipFile->addFromString($entryName, $contents, \PhpZip\Constants\ZipCompressionMethod::DEFLATED); // Deflate compression
$zipFile->addFromString($entryName, $contents, \PhpZip\Constants\ZipCompressionMethod::BZIP2); // BZIP2 compression
```
<a name="Documentation-ZipFile-addFromStream"></a> **ZipFile::addFromStream** - adds a entry from the stream to the ZIP archive.
<a name="Documentation-ZipFile-addFromStream"></a> **ZipFile::addFromStream** - adds an entry from the stream to the ZIP archive.
```php
$zipFile = new \PhpZip\ZipFile();
// $stream = fopen(..., 'rb');
@ -710,17 +699,6 @@ $zipFile->disableEncryption();
```php
$zipFile->disableEncryptionEntry($entryName);
```
#### <a name="Documentation-ZipAlign-Usage"></a> zipalign
<a name="Documentation-ZipFile-setZipAlign"></a> **ZipFile::setZipAlign** - sets the alignment of the archive to optimize APK files (Android packages).
This method adds padding to unencrypted and not compressed entries, to optimize memory consumption in the Android system. It is recommended to use for `APK` files. The file may grow slightly.
This method is an alternative to executing the `zipalign -f -v 4 filename.zip`.
More details can be found on the [link](https://developer.android.com/studio/command-line/zipalign.html).
```php
$zipFile->setZipAlign(4);
```
#### <a name="Documentation-Unchanged"></a> Undo changes
<a name="Documentation-ZipFile-unchangeAll"></a> **ZipFile::unchangeAll** - undo all changes done in the archive.
```php
@ -792,6 +770,20 @@ vendor/bin/phpunit
Changes are documented in the [releases page](https://github.com/Ne-Lexa/php-zip/releases).
### <a name="Upgrade"></a> Upgrade
#### <a name="Upgrade-v3-to-v4"></a> Upgrade version 3 to version 4
Update the major version in the file `composer.json` to `^4.0`.
```json
{
"require": {
"nelexa/zip": "^4.0"
}
}
```
Then install updates using `Composer`:
```bash
composer update nelexa/zip
```
#### <a name="Upgrade-v2-to-v3"></a> Upgrade version 2 to version 3.0
Update the major version in the file `composer.json` to `^3.0`.
```json
@ -800,6 +792,9 @@ Update the major version in the file `composer.json` to `^3.0`.
"nelexa/zip": "^3.0"
}
}
Update your code to work with the new version:
**BC**
- removed `zipalign` functional. This functionality will be placed in a separate package `nelexa/apkfile`.
```
Then install updates using `Composer`:
```bash
@ -828,5 +823,3 @@ Update your code to work with the new version:
+ `getLevel`
+ `setCompressionMethod`
+ `setEntryPassword`

View File

@ -1,6 +1,14 @@
<?php
// see https://stackoverflow.com/questions/33299149/phpstorm-8-and-phpunit-problems-with-runinseparateprocess/37174348#37174348
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
if (!defined('PHPUNIT_COMPOSER_INSTALL')) {
define('PHPUNIT_COMPOSER_INSTALL', __DIR__ . '/vendor/autoload.php');
}

View File

@ -1,7 +1,7 @@
{
"name": "nelexa/zip",
"type": "library",
"description": "PhpZip is a php-library for extended work with ZIP-archives. Open, create, update, delete, extract and get info tool. Supports appending to existing ZIP files, WinZip AES encryption, Traditional PKWARE Encryption, ZipAlign tool, BZIP2 compression, external file attributes and ZIP64 extensions. Alternative ZipArchive. It does not require php-zip extension.",
"description": "PhpZip is a php-library for extended work with ZIP-archives. Open, create, update, delete, extract and get info tool. Supports appending to existing ZIP files, WinZip AES encryption, Traditional PKWARE Encryption, BZIP2 compression, external file attributes and ZIP64 extensions. Alternative ZipArchive. It does not require php-zip extension.",
"keywords": [
"zip",
"unzip",
@ -21,20 +21,23 @@
}
],
"require": {
"php": "^7.2 || ^8.0",
"php": "^7.4 || ^8.0",
"ext-zlib": "*",
"psr/http-message": "^1.0",
"paragonie/random_compat": "*",
"symfony/finder": "^3.0 || ^4.0 || ^5.0"
},
"require-dev": {
"ext-iconv": "*",
"ext-bz2": "*",
"ext-openssl": "*",
"ext-fileinfo": "*",
"ext-xml": "*",
"ext-dom": "*",
"guzzlehttp/psr7": "^1.6",
"phpunit/phpunit": "^8 || ^9",
"symfony/var-dumper": "^5.0"
"phpunit/phpunit": "^9",
"symfony/var-dumper": "^5.0",
"friendsofphp/php-cs-fixer": "^2.18",
"vimeo/psalm": "^4.6"
},
"autoload": {
"psr-4": {
@ -47,8 +50,8 @@
}
},
"suggest": {
"ext-iconv": "Needed to support convert zip entry name to requested character encoding",
"ext-openssl": "Needed to support encrypt zip entries or use ext-mcrypt",
"ext-mcrypt": "Needed to support encrypt zip entries or use ext-openssl",
"ext-bz2": "Needed to support BZIP2 compression",
"ext-fileinfo": "Needed to get mime-type file"
},

View File

@ -1,36 +1,28 @@
<?xml version="1.0" encoding="utf-8" ?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.8/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="bootstrap.php">
<php>
<ini name="error_reporting" value="-1"/>
</php>
<testsuites>
<testsuite name="all_tests">
<directory>tests</directory>
</testsuite>
<testsuite name="only_fast_tests">
<directory>tests</directory>
<exclude>tests/SlowTests</exclude>
</testsuite>
<testsuite name="only_slow_tests">
<directory>tests/SlowTests</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>large</group>
</exclude>
</groups>
<filter>
<whitelist>
<directory>src</directory>
</whitelist>
</filter>
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" backupGlobals="false" colors="true" bootstrap="bootstrap.php">
<coverage>
<include>
<directory>src</directory>
</include>
</coverage>
<php>
<ini name="error_reporting" value="-1"/>
</php>
<testsuites>
<testsuite name="all_tests">
<directory>tests</directory>
</testsuite>
<testsuite name="only_fast_tests">
<directory>tests</directory>
<exclude>tests/SlowTests</exclude>
</testsuite>
<testsuite name="only_slow_tests">
<directory>tests/SlowTests</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>large</group>
</exclude>
</groups>
</phpunit>

17
psalm.xml Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0"?>
<psalm
errorLevel="3"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="src" />
<ignoreFiles>
<directory name="vendor" />
<directory name="benchmarks" />
<directory name="tests"/>
</ignoreFiles>
</projectFiles>
</psalm>

View File

@ -1,33 +1,39 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Constants;
/**
* Interface DosAttrs.
*/
interface DosAttrs
{
/** @var int DOS File Attribute Read Only */
const DOS_READ_ONLY = 0x01;
public const DOS_READ_ONLY = 0x01;
/** @var int DOS File Attribute Hidden */
const DOS_HIDDEN = 0x02;
public const DOS_HIDDEN = 0x02;
/** @var int DOS File Attribute System */
const DOS_SYSTEM = 0x04;
public const DOS_SYSTEM = 0x04;
/** @var int DOS File Attribute Label */
const DOS_LABEL = 0x08;
public const DOS_LABEL = 0x08;
/** @var int DOS File Attribute Directory */
const DOS_DIRECTORY = 0x10;
public const DOS_DIRECTORY = 0x10;
/** @var int DOS File Attribute Archive */
const DOS_ARCHIVE = 0x20;
public const DOS_ARCHIVE = 0x20;
/** @var int DOS File Attribute Link */
const DOS_LINK = 0x40;
public const DOS_LINK = 0x40;
/** @var int DOS File Attribute Execute */
const DOS_EXE = 0x80;
public const DOS_EXE = 0x80;
}

View File

@ -1,48 +1,52 @@
<?php
/** @noinspection PhpComposerExtensionStubsInspection */
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Constants;
/**
* Class DosCodePage.
*/
final class DosCodePage
{
const CP_LATIN_US = 'cp437';
public const CP_LATIN_US = 'cp437';
const CP_GREEK = 'cp737';
public const CP_GREEK = 'cp737';
const CP_BALT_RIM = 'cp775';
public const CP_BALT_RIM = 'cp775';
const CP_LATIN1 = 'cp850';
public const CP_LATIN1 = 'cp850';
const CP_LATIN2 = 'cp852';
public const CP_LATIN2 = 'cp852';
const CP_CYRILLIC = 'cp855';
public const CP_CYRILLIC = 'cp855';
const CP_TURKISH = 'cp857';
public const CP_TURKISH = 'cp857';
const CP_PORTUGUESE = 'cp860';
public const CP_PORTUGUESE = 'cp860';
const CP_ICELANDIC = 'cp861';
public const CP_ICELANDIC = 'cp861';
const CP_HEBREW = 'cp862';
public const CP_HEBREW = 'cp862';
const CP_CANADA = 'cp863';
public const CP_CANADA = 'cp863';
const CP_ARABIC = 'cp864';
public const CP_ARABIC = 'cp864';
const CP_NORDIC = 'cp865';
public const CP_NORDIC = 'cp865';
const CP_CYRILLIC_RUSSIAN = 'cp866';
public const CP_CYRILLIC_RUSSIAN = 'cp866';
const CP_GREEK2 = 'cp869';
public const CP_GREEK2 = 'cp869';
const CP_THAI = 'cp874';
public const CP_THAI = 'cp874';
/** @var string[] */
private static $CP_CHARSETS = [
private const CP_CHARSETS = [
self::CP_LATIN_US,
self::CP_GREEK,
self::CP_BALT_RIM,
@ -62,12 +66,9 @@ final class DosCodePage
];
/**
* @param string $str
* @param string $sourceEncoding
*
* @return string
* @noinspection PhpComposerExtensionStubsInspection
*/
public static function toUTF8($str, $sourceEncoding)
public static function toUTF8(string $str, string $sourceEncoding): string
{
$s = iconv($sourceEncoding, 'UTF-8', $str);
@ -79,12 +80,9 @@ final class DosCodePage
}
/**
* @param string $str
* @param string $destEncoding
*
* @return string
* @noinspection PhpComposerExtensionStubsInspection
*/
public static function fromUTF8($str, $destEncoding)
public static function fromUTF8(string $str, string $destEncoding): string
{
$s = iconv('UTF-8', $destEncoding, $str);
@ -98,8 +96,8 @@ final class DosCodePage
/**
* @return string[]
*/
public static function getCodePages()
public static function getCodePages(): array
{
return self::$CP_CHARSETS;
return self::CP_CHARSETS;
}
}

View File

@ -1,17 +1,23 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Constants;
/**
* General purpose bit flag constants.
*/
interface GeneralPurposeBitFlag
{
/**
* General Purpose Bit Flag mask for encrypted data.
* Bit 0: If set, indicates that the file is encrypted.
*/
const ENCRYPTION = 1; // 1 << 0
public const ENCRYPTION = 1 << 0;
/**
* Compression Flag Bit 1 for method Deflating.
@ -24,7 +30,7 @@ interface GeneralPurposeBitFlag
*
* @see GeneralPurposeBitFlag::COMPRESSION_FLAG2
*/
const COMPRESSION_FLAG1 = 2; // 1 << 1
public const COMPRESSION_FLAG1 = 1 << 1;
/**
* Compression Flag Bit 2 for method Deflating.
@ -37,7 +43,7 @@ interface GeneralPurposeBitFlag
*
* @see GeneralPurposeBitFlag::COMPRESSION_FLAG1
*/
const COMPRESSION_FLAG2 = 4; // 1 << 2
public const COMPRESSION_FLAG2 = 1 << 2;
/**
* General Purpose Bit Flag mask for data descriptor.
@ -47,7 +53,7 @@ interface GeneralPurposeBitFlag
* local header. The correct values are put in the data
* descriptor immediately following the compressed data.
*/
const DATA_DESCRIPTOR = 8; // 1 << 3
public const DATA_DESCRIPTOR = 1 << 3;
/**
* General Purpose Bit Flag mask for strong encryption.
@ -58,7 +64,7 @@ interface GeneralPurposeBitFlag
* If AES encryption is used, the version needed to extract value
* MUST be at least 51.
*/
const STRONG_ENCRYPTION = 64; // 1 << 6
public const STRONG_ENCRYPTION = 1 << 6;
/**
* General Purpose Bit Flag mask for UTF-8.
@ -67,5 +73,5 @@ interface GeneralPurposeBitFlag
* If this bit is set, the filename and comment fields
* for this file MUST be encoded using UTF-8. (see APPENDIX D)
*/
const UTF8 = 2048; // 1 << 11
public const UTF8 = 1 << 11;
}

View File

@ -1,84 +1,90 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Constants;
/**
* Unix stat constants.
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*/
interface UnixStat
{
/** @var int unix file type mask */
const UNX_IFMT = 0170000;
public const UNX_IFMT = 0170000;
/** @var int unix regular file */
const UNX_IFREG = 0100000;
public const UNX_IFREG = 0100000;
/** @var int unix socket (BSD, not SysV or Amiga) */
const UNX_IFSOCK = 0140000;
public const UNX_IFSOCK = 0140000;
/** @var int unix symbolic link (not SysV, Amiga) */
const UNX_IFLNK = 0120000;
public const UNX_IFLNK = 0120000;
/** @var int unix block special (not Amiga) */
const UNX_IFBLK = 0060000;
public const UNX_IFBLK = 0060000;
/** @var int unix directory */
const UNX_IFDIR = 0040000;
public const UNX_IFDIR = 0040000;
/** @var int unix character special (not Amiga) */
const UNX_IFCHR = 0020000;
public const UNX_IFCHR = 0020000;
/** @var int unix fifo (BCC, not MSC or Amiga) */
const UNX_IFIFO = 0010000;
public const UNX_IFIFO = 0010000;
/** @var int unix set user id on execution */
const UNX_ISUID = 04000;
public const UNX_ISUID = 04000;
/** @var int unix set group id on execution */
const UNX_ISGID = 02000;
public const UNX_ISGID = 02000;
/** @var int unix directory permissions control */
const UNX_ISVTX = 01000;
public const UNX_ISVTX = 01000;
/** @var int unix record locking enforcement flag */
const UNX_ENFMT = 02000;
public const UNX_ENFMT = 02000;
/** @var int unix read, write, execute: owner */
const UNX_IRWXU = 00700;
public const UNX_IRWXU = 00700;
/** @var int unix read permission: owner */
const UNX_IRUSR = 00400;
public const UNX_IRUSR = 00400;
/** @var int unix write permission: owner */
const UNX_IWUSR = 00200;
public const UNX_IWUSR = 00200;
/** @var int unix execute permission: owner */
const UNX_IXUSR = 00100;
public const UNX_IXUSR = 00100;
/** @var int unix read, write, execute: group */
const UNX_IRWXG = 00070;
public const UNX_IRWXG = 00070;
/** @var int unix read permission: group */
const UNX_IRGRP = 00040;
public const UNX_IRGRP = 00040;
/** @var int unix write permission: group */
const UNX_IWGRP = 00020;
public const UNX_IWGRP = 00020;
/** @var int unix execute permission: group */
const UNX_IXGRP = 00010;
public const UNX_IXGRP = 00010;
/** @var int unix read, write, execute: other */
const UNX_IRWXO = 00007;
public const UNX_IRWXO = 00007;
/** @var int unix read permission: other */
const UNX_IROTH = 00004;
public const UNX_IROTH = 00004;
/** @var int unix write permission: other */
const UNX_IWOTH = 00002;
public const UNX_IWOTH = 00002;
/** @var int unix execute permission: other */
const UNX_IXOTH = 00001;
public const UNX_IXOTH = 00001;
}

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Constants;
/**
@ -27,28 +36,28 @@ namespace PhpZip\Constants;
interface ZipCompressionLevel
{
/** @var int Compression level for super fast compression. */
const SUPER_FAST = 1;
public const SUPER_FAST = 1;
/** @var int compression level for fast compression */
const FAST = 2;
public const FAST = 2;
/** @var int compression level for normal compression */
const NORMAL = 5;
public const NORMAL = 5;
/** @var int compression level for maximum compression */
const MAXIMUM = 9;
public const MAXIMUM = 9;
/**
* @var int int Minimum compression level
*
* @internal
*/
const LEVEL_MIN = self::SUPER_FAST;
public const LEVEL_MIN = self::SUPER_FAST;
/**
* @var int int Maximum compression level
*
* @internal
*/
const LEVEL_MAX = self::MAXIMUM;
public const LEVEL_MAX = self::MAXIMUM;
}

View File

@ -1,28 +1,34 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Constants;
use PhpZip\Exception\ZipUnsupportMethodException;
/**
* Class ZipCompressionMethod.
*/
final class ZipCompressionMethod
{
/** @var int Compression method Store */
const STORED = 0;
public const STORED = 0;
/** @var int Compression method Deflate */
const DEFLATED = 8;
public const DEFLATED = 8;
/** @var int Compression method Bzip2 */
const BZIP2 = 12;
public const BZIP2 = 12;
/** @var int Compression method AES-Encryption */
const WINZIP_AES = 99;
public const WINZIP_AES = 99;
/** @var array Compression Methods */
private static $ZIP_COMPRESSION_METHODS = [
private const ZIP_COMPRESSION_METHODS = [
self::STORED => 'Stored',
1 => 'Shrunk',
2 => 'Reduced compression factor 1',
@ -49,22 +55,15 @@ final class ZipCompressionMethod
self::WINZIP_AES => 'AES Encryption',
];
/**
* @param int $value
*
* @return string
*/
public static function getCompressionMethodName($value)
public static function getCompressionMethodName(int $value): string
{
return isset(self::$ZIP_COMPRESSION_METHODS[$value]) ?
self::$ZIP_COMPRESSION_METHODS[$value] :
'Unknown Method';
return self::ZIP_COMPRESSION_METHODS[$value] ?? 'Unknown Method';
}
/**
* @return int[]
*/
public static function getSupportMethods()
public static function getSupportMethods(): array
{
static $methods;
@ -83,14 +82,10 @@ final class ZipCompressionMethod
}
/**
* @param int $compressionMethod
*
* @throws ZipUnsupportMethodException
*/
public static function checkSupport($compressionMethod)
public static function checkSupport(int $compressionMethod): void
{
$compressionMethod = (int) $compressionMethod;
if (!\in_array($compressionMethod, self::getSupportMethods(), true)) {
throw new ZipUnsupportMethodException(sprintf(
'Compression method %d (%s) is not supported.',

View File

@ -1,38 +1,44 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Constants;
/**
* Zip Constants.
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*/
interface ZipConstants
{
/** @var int End Of Central Directory Record signature. */
const END_CD = 0x06054B50; // "PK\005\006"
public const END_CD = 0x06054B50; // "PK\005\006"
/** @var int Zip64 End Of Central Directory Record. */
const ZIP64_END_CD = 0x06064B50; // "PK\006\006"
public const ZIP64_END_CD = 0x06064B50; // "PK\006\006"
/** @var int Zip64 End Of Central Directory Locator. */
const ZIP64_END_CD_LOC = 0x07064B50; // "PK\006\007"
public const ZIP64_END_CD_LOC = 0x07064B50; // "PK\006\007"
/** @var int Central File Header signature. */
const CENTRAL_FILE_HEADER = 0x02014B50; // "PK\001\002"
public const CENTRAL_FILE_HEADER = 0x02014B50; // "PK\001\002"
/** @var int Local File Header signature. */
const LOCAL_FILE_HEADER = 0x04034B50; // "PK\003\004"
public const LOCAL_FILE_HEADER = 0x04034B50; // "PK\003\004"
/** @var int Data Descriptor signature. */
const DATA_DESCRIPTOR = 0x08074B50; // "PK\007\008"
public const DATA_DESCRIPTOR = 0x08074B50; // "PK\007\008"
/**
* @var int value stored in four-byte size and similar fields
* if ZIP64 extensions are used
*/
const ZIP64_MAGIC = 0xFFFFFFFF;
public const ZIP64_MAGIC = 0xFFFFFFFF;
/**
* Local File Header signature 4
@ -47,7 +53,7 @@ interface ZipConstants
*
* @var int Local File Header filename position
*/
const LFH_FILENAME_LENGTH_POS = 26;
public const LFH_FILENAME_LENGTH_POS = 26;
/**
* The minimum length of the Local File Header record.
@ -64,13 +70,13 @@ interface ZipConstants
* file name length 2
* extra field length 2
*/
const LFH_FILENAME_POS = 30;
public const LFH_FILENAME_POS = 30;
/** @var int the length of the Zip64 End Of Central Directory Locator */
const ZIP64_END_CD_LOC_LEN = 20;
public const ZIP64_END_CD_LOC_LEN = 20;
/** @var int the minimum length of the End Of Central Directory Record */
const END_CD_MIN_LEN = 22;
public const END_CD_MIN_LEN = 22;
/**
* The minimum length of the Zip64 End Of Central Directory Record.
@ -95,5 +101,5 @@ interface ZipConstants
*
* @var int ZIP64 End Of Central Directory length
*/
const ZIP64_END_OF_CD_LEN = 56;
public const ZIP64_END_OF_CD_LEN = 56;
}

View File

@ -1,30 +1,36 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Constants;
use PhpZip\Exception\InvalidArgumentException;
/**
* Class ZipEncryptionMethod.
*/
final class ZipEncryptionMethod
{
const NONE = -1;
public const NONE = -1;
/** @var int Traditional PKWARE encryption. */
const PKWARE = 0;
public const PKWARE = 0;
/** @var int WinZip AES-256 */
const WINZIP_AES_256 = 1;
public const WINZIP_AES_256 = 1;
/** @var int WinZip AES-128 */
const WINZIP_AES_128 = 2;
public const WINZIP_AES_128 = 2;
/** @var int WinZip AES-192 */
const WINZIP_AES_192 = 3;
public const WINZIP_AES_192 = 3;
/** @var array<int, string> */
private static $ENCRYPTION_METHODS = [
private const ENCRYPTION_METHODS = [
self::NONE => 'no encryption',
self::PKWARE => 'Traditional PKWARE encryption',
self::WINZIP_AES_128 => 'WinZip AES-128',
@ -32,39 +38,20 @@ final class ZipEncryptionMethod
self::WINZIP_AES_256 => 'WinZip AES-256',
];
/**
* @param int $value
*
* @return string
*/
public static function getEncryptionMethodName($value)
public static function getEncryptionMethodName(int $value): string
{
$value = (int) $value;
return isset(self::$ENCRYPTION_METHODS[$value]) ?
self::$ENCRYPTION_METHODS[$value] :
'Unknown Encryption Method';
return self::ENCRYPTION_METHODS[$value] ?? 'Unknown Encryption Method';
}
/**
* @param int $encryptionMethod
*
* @return bool
*/
public static function hasEncryptionMethod($encryptionMethod)
public static function hasEncryptionMethod(int $encryptionMethod): bool
{
return isset(self::$ENCRYPTION_METHODS[$encryptionMethod]);
return isset(self::ENCRYPTION_METHODS[$encryptionMethod]);
}
/**
* @param int $encryptionMethod
*
* @return bool
*/
public static function isWinZipAesMethod($encryptionMethod)
public static function isWinZipAesMethod(int $encryptionMethod): bool
{
return \in_array(
(int) $encryptionMethod,
$encryptionMethod,
[
self::WINZIP_AES_256,
self::WINZIP_AES_192,
@ -75,14 +62,10 @@ final class ZipEncryptionMethod
}
/**
* @param int $encryptionMethod
*
* @throws InvalidArgumentException
*/
public static function checkSupport($encryptionMethod)
public static function checkSupport(int $encryptionMethod): void
{
$encryptionMethod = (int) $encryptionMethod;
if (!self::hasEncryptionMethod($encryptionMethod)) {
throw new InvalidArgumentException(sprintf(
'Encryption method %d is not supported.',

View File

@ -1,13 +1,19 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Constants;
use PhpZip\IO\ZipReader;
use PhpZip\ZipFile;
/**
* Interface ZipOptions.
*/
interface ZipOptions
{
/**
@ -15,7 +21,7 @@ interface ZipOptions
*
* @see ZipFile::addFromFinder()
*/
const STORE_ONLY_FILES = 'only_files';
public const STORE_ONLY_FILES = 'only_files';
/**
* Uses the specified compression method.
@ -23,7 +29,7 @@ interface ZipOptions
* @see ZipFile::addFromFinder()
* @see ZipFile::addSplFile()
*/
const COMPRESSION_METHOD = 'compression_method';
public const COMPRESSION_METHOD = 'compression_method';
/**
* Set the specified record modification time.
@ -33,7 +39,7 @@ interface ZipOptions
* @see ZipFile::addFromFinder()
* @see ZipFile::addSplFile()
*/
const MODIFIED_TIME = 'mtime';
public const MODIFIED_TIME = 'mtime';
/**
* Specifies the encoding of the record name for cases when the UTF-8
@ -48,7 +54,7 @@ interface ZipOptions
* @see ZipReader::getDefaultOptions()
* @see DosCodePage::getCodePages()
*/
const CHARSET = 'charset';
public const CHARSET = 'charset';
/**
* Allows ({@see true}) or denies ({@see false}) unpacking unix symlinks.
@ -58,5 +64,5 @@ interface ZipOptions
*
* @see https://josipfranjkovic.blogspot.com/2014/12/reading-local-files-from-facebooks.html
*/
const EXTRACT_SYMLINKS = 'extract_symlinks';
public const EXTRACT_SYMLINKS = 'extract_symlinks';
}

View File

@ -1,23 +1,29 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Constants;
/**
* Class ZipPlatform.
*/
final class ZipPlatform
{
/** @var int MS-DOS OS */
const OS_DOS = 0;
public const OS_DOS = 0;
/** @var int Unix OS */
const OS_UNIX = 3;
public const OS_UNIX = 3;
/** MacOS platform */
const OS_MAC_OSX = 19;
/** @var int MacOS platform */
public const OS_MAC_OSX = 19;
/** @var array Zip Platforms */
private static $platforms = [
private const PLATFORMS = [
self::OS_DOS => 'MS-DOS',
1 => 'Amiga',
2 => 'OpenVMS',
@ -41,13 +47,8 @@ final class ZipPlatform
30 => 'AtheOS/Syllable',
];
/**
* @param int $platform
*
* @return string
*/
public static function getPlatformName($platform)
public static function getPlatformName(int $platform): string
{
return isset(self::$platforms[$platform]) ? self::$platforms[$platform] : 'Unknown';
return self::PLATFORMS[$platform] ?? 'Unknown';
}
}

View File

@ -1,22 +1,28 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Constants;
/**
* Version needed to extract or software version.
*
* @see https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT Section 4.4.3
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*/
interface ZipVersion
{
/** @var int 1.0 - Default value */
const v10_DEFAULT_MIN = 10;
public const v10_DEFAULT_MIN = 10;
/** @var int 1.1 - File is a volume label */
const v11_FILE_VOLUME_LABEL = 11;
public const v11_FILE_VOLUME_LABEL = 11;
/**
* 2.0 - File is a folder (directory)
@ -25,22 +31,22 @@ interface ZipVersion
*
* @var int
*/
const v20_DEFLATED_FOLDER_ZIPCRYPTO = 20;
public const v20_DEFLATED_FOLDER_ZIPCRYPTO = 20;
/** @var int 2.1 - File is compressed using Deflate64(tm) */
const v21_DEFLATED64 = 21;
public const v21_DEFLATED64 = 21;
/** @var int 2.5 - File is compressed using PKWARE DCL Implode */
const v25_IMPLODED = 25;
public const v25_IMPLODED = 25;
/** @var int 2.7 - File is a patch data set */
const v27_PATCH_DATA = 27;
public const v27_PATCH_DATA = 27;
/** @var int 4.5 - File uses ZIP64 format extensions */
const v45_ZIP64_EXT = 45;
public const v45_ZIP64_EXT = 45;
/** @var int 4.6 - File is compressed using BZIP2 compression */
const v46_BZIP2 = 46;
public const v46_BZIP2 = 46;
/**
* 5.0 - File is encrypted using DES
@ -50,7 +56,7 @@ interface ZipVersion
*
* @var int
*/
const v50_ENCR_DES_3DES_RC2_ORIG_RC4 = 50;
public const v50_ENCR_DES_3DES_RC2_ORIG_RC4 = 50;
/**
* 5.1 - File is encrypted using AES encryption
@ -58,16 +64,16 @@ interface ZipVersion
*
* @var int
*/
const v51_ENCR_AES_RC2_CORRECT = 51;
public const v51_ENCR_AES_RC2_CORRECT = 51;
/** @var int 5.2 - File is encrypted using corrected RC2-64 encryption** */
const v52_ENCR_RC2_64_CORRECT = 52;
public const v52_ENCR_RC2_64_CORRECT = 52;
/** @var int 6.1 - File is encrypted using non-OAEP key wrapping*** */
const v61_ENCR_NON_OAE_KEY_WRAP = 61;
public const v61_ENCR_NON_OAE_KEY_WRAP = 61;
/** @var int 6.2 - Central directory encryption */
const v62_ENCR_CENTRAL_DIR = 62;
public const v62_ENCR_CENTRAL_DIR = 62;
/**
* 6.3 - File is compressed using LZMA
@ -77,5 +83,5 @@ interface ZipVersion
*
* @var int
*/
const v63_LZMA_PPMD_BLOWFISH_TWOFISH = 63;
public const v63_LZMA_PPMD_BLOWFISH_TWOFISH = 63;
}

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Exception;
/**
@ -8,34 +17,16 @@ namespace PhpZip\Exception;
* and the computed value from the decompressed data.
*
* The exception detail message is the name of the ZIP entry.
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*/
class Crc32Exception extends ZipException
{
/**
* Expected crc.
*
* @var int
*/
private $expectedCrc;
/** Expected crc. */
private int $expectedCrc;
/**
* Actual crc.
*
* @var int
*/
private $actualCrc;
/** Actual crc. */
private int $actualCrc;
/**
* Crc32Exception constructor.
*
* @param string $name
* @param int $expected
* @param int $actual
*/
public function __construct($name, $expected, $actual)
public function __construct(string $name, int $expected, int $actual)
{
parent::__construct(
sprintf(
@ -51,20 +42,16 @@ class Crc32Exception extends ZipException
/**
* Returns expected crc.
*
* @return int
*/
public function getExpectedCrc()
public function getExpectedCrc(): int
{
return $this->expectedCrc;
}
/**
* Returns actual crc.
*
* @return int
*/
public function getActualCrc()
public function getActualCrc(): int
{
return $this->actualCrc;
}

View File

@ -1,13 +1,19 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Exception;
/**
* Thrown to indicate that a method has been passed an illegal or
* inappropriate argument.
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*/
class InvalidArgumentException extends RuntimeException
{

View File

@ -1,13 +1,19 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Exception;
/**
* Runtime exception.
* Exception thrown if an error which can only be found on runtime occurs.
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*/
class RuntimeException extends \RuntimeException
{

View File

@ -1,12 +1,18 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Exception;
/**
* Thrown to indicate that an authenticated ZIP entry has been tampered with.
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*/
class ZipAuthenticationException extends ZipCryptoException
{

View File

@ -1,13 +1,19 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Exception;
/**
* Thrown if there is an issue when reading or writing an encrypted ZIP file
* or entry.
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*/
class ZipCryptoException extends ZipException
{

View File

@ -1,23 +1,26 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Exception;
use PhpZip\Model\ZipEntry;
/**
* Thrown if entry not found.
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*/
class ZipEntryNotFoundException extends ZipException
{
/** @var string */
private $entryName;
private string $entryName;
/**
* ZipEntryNotFoundException constructor.
*
* @param ZipEntry|string $entryName
*/
public function __construct($entryName)
@ -30,10 +33,7 @@ class ZipEntryNotFoundException extends ZipException
$this->entryName = $entryName;
}
/**
* @return string
*/
public function getEntryName()
public function getEntryName(): string
{
return $this->entryName;
}

View File

@ -1,13 +1,19 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Exception;
/**
* Signals that a Zip exception of some sort has occurred.
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*
* @see \Exception
*/
class ZipException extends \Exception

View File

@ -1,10 +1,16 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Exception;
/**
* Class ZipUnsupportMethodException.
*/
class ZipUnsupportMethodException extends ZipException
{
}

View File

@ -1,30 +1,36 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\IO\Filter\Cipher\Pkware;
use PhpZip\Exception\RuntimeException;
use PhpZip\Exception\ZipAuthenticationException;
use PhpZip\Util\PackUtil;
use PhpZip\Util\MathUtil;
/**
* Traditional PKWARE Encryption Engine.
*
* @see https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT .ZIP File Format Specification
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*/
class PKCryptContext
{
/** Encryption header size */
const STD_DEC_HDR_SIZE = 12;
/** @var int Encryption header size */
public const STD_DEC_HDR_SIZE = 12;
/**
* Crc table.
*
* @var int[]|array
*/
private static $CRC_TABLE = [
private const CRC_TABLE = [
0x00000000,
0x77073096,
0xee0e612c,
@ -283,19 +289,10 @@ class PKCryptContext
0x2d02ef8d,
];
/**
* Encryption keys.
*
* @var array
*/
private $keys;
/** @var array encryption keys */
private array $keys;
/**
* PKCryptContext constructor.
*
* @param string $password
*/
public function __construct($password)
public function __construct(string $password)
{
if (\PHP_INT_SIZE === 4) {
throw new RuntimeException('Traditional PKWARE Encryption is not supported in 32-bit PHP.');
@ -307,18 +304,15 @@ class PKCryptContext
878082192,
];
foreach (unpack('C*', $password) as $b) {
$this->updateKeys($b);
foreach (unpack('C*', $password) as $byte) {
$this->updateKeys($byte);
}
}
/**
* @param string $header
* @param int $checkByte
*
* @throws ZipAuthenticationException
*/
public function checkHeader($header, $checkByte)
public function checkHeader(string $header, int $checkByte): void
{
$byte = 0;
@ -328,16 +322,11 @@ class PKCryptContext
}
if ($byte !== $checkByte) {
throw new ZipAuthenticationException(sprintf('Invalid password'));
throw new ZipAuthenticationException('Invalid password');
}
}
/**
* @param string $content
*
* @return string
*/
public function decryptString($content)
public function decryptString(string $content): string
{
$decryptContent = '';
@ -352,10 +341,8 @@ class PKCryptContext
/**
* Decrypt byte.
*
* @return int
*/
private function decryptByte()
private function decryptByte(): int
{
$temp = $this->keys[2] | 2;
@ -364,36 +351,24 @@ class PKCryptContext
/**
* Update keys.
*
* @param int $charAt
*/
private function updateKeys($charAt)
private function updateKeys(int $charAt): void
{
$this->keys[0] = $this->crc32($this->keys[0], $charAt);
$this->keys[1] += ($this->keys[0] & 0xff);
$this->keys[1] = PackUtil::toSignedInt32($this->keys[1] * 134775813 + 1);
$this->keys[2] = PackUtil::toSignedInt32($this->crc32($this->keys[2], ($this->keys[1] >> 24) & 0xff));
$this->keys[1] = MathUtil::toSignedInt32($this->keys[1] * 134775813 + 1);
$this->keys[2] = MathUtil::toSignedInt32($this->crc32($this->keys[2], ($this->keys[1] >> 24) & 0xff));
}
/**
* Update crc.
*
* @param int $oldCrc
* @param int $charAt
*
* @return int
*/
private function crc32($oldCrc, $charAt)
private function crc32(int $oldCrc, int $charAt): int
{
return (($oldCrc >> 8) & 0xffffff) ^ self::$CRC_TABLE[($oldCrc ^ $charAt) & 0xff];
return (($oldCrc >> 8) & 0xffffff) ^ self::CRC_TABLE[($oldCrc ^ $charAt) & 0xff];
}
/**
* @param string $content
*
* @return string
*/
public function encryptString($content)
public function encryptString(string $content): string
{
$encryptContent = '';
@ -404,12 +379,7 @@ class PKCryptContext
return $encryptContent;
}
/**
* @param int $byte
*
* @return int
*/
private function encryptByte($byte)
private function encryptByte(int $byte): int
{
$tempVal = $byte ^ $this->decryptByte() & 0xff;
$this->updateKeys($byte);

View File

@ -1,8 +1,17 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\IO\Filter\Cipher\Pkware;
use PhpZip\Exception\ZipException;
use PhpZip\Exception\ZipAuthenticationException;
use PhpZip\Model\ZipEntry;
/**
@ -10,37 +19,27 @@ use PhpZip\Model\ZipEntry;
*/
class PKDecryptionStreamFilter extends \php_user_filter
{
const FILTER_NAME = 'phpzip.decryption.pkware';
public const FILTER_NAME = 'phpzip.decryption.pkware';
/** @var int */
private $checkByte = 0;
private int $checkByte = 0;
/** @var int */
private $readLength = 0;
private int $readLength = 0;
/** @var int */
private $size = 0;
private int $size = 0;
/** @var bool */
private $readHeader = false;
private bool $readHeader = false;
/** @var PKCryptContext */
private $context;
private PKCryptContext $context;
/**
* @return bool
*/
public static function register()
public static function register(): bool
{
return stream_filter_register(self::FILTER_NAME, __CLASS__);
}
/**
* @see https://php.net/manual/en/php-user-filter.oncreate.php
*
* @return bool
*/
public function onCreate()
public function onCreate(): bool
{
if (!isset($this->params['entry'])) {
return false;
@ -78,18 +77,12 @@ class PKDecryptionStreamFilter extends \php_user_filter
/**
* Decryption filter.
*
* @param resource $in
* @param resource $out
* @param int $consumed
* @param bool $closing
*
* @throws ZipException
*
* @return int
* @throws ZipAuthenticationException
*
* @todo USE FFI in php 7.4
* @noinspection PhpDocSignatureInspection
*/
public function filter($in, $out, &$consumed, $closing)
public function filter($in, $out, &$consumed, $closing): int
{
while ($bucket = stream_bucket_make_writeable($in)) {
$buffer = $bucket->data;

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\IO\Filter\Cipher\Pkware;
use PhpZip\Exception\RuntimeException;
@ -10,37 +19,27 @@ use PhpZip\Model\ZipEntry;
*/
class PKEncryptionStreamFilter extends \php_user_filter
{
const FILTER_NAME = 'phpzip.encryption.pkware';
public const FILTER_NAME = 'phpzip.encryption.pkware';
/** @var int */
private $size;
private int $size;
/** @var string */
private $headerBytes;
private string $headerBytes;
/** @var int */
private $writeLength;
private int $writeLength;
/** @var bool */
private $writeHeader;
private bool $writeHeader;
/** @var PKCryptContext */
private $context;
private PKCryptContext $context;
/**
* @return bool
*/
public static function register()
public static function register(): bool
{
return stream_filter_register(self::FILTER_NAME, __CLASS__);
}
/**
* @see https://php.net/manual/en/php-user-filter.oncreate.php
*
* @return bool
*/
public function onCreate()
public function onCreate(): bool
{
if (\PHP_INT_SIZE === 4) {
throw new RuntimeException('Traditional PKWARE Encryption is not supported in 32-bit PHP.');
@ -66,9 +65,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);
@ -89,16 +88,11 @@ class PKEncryptionStreamFilter extends \php_user_filter
/**
* Encryption filter.
*
* @param resource $in
* @param resource $out
* @param int $consumed
* @param bool $closing
*
* @return int
*
* @todo USE FFI in php 7.4
*
* @noinspection PhpDocSignatureInspection
*/
public function filter($in, $out, &$consumed, $closing)
public function filter($in, $out, &$consumed, $closing): int
{
while ($bucket = stream_bucket_make_writeable($in)) {
$buffer = $bucket->data;

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\IO\Filter\Cipher\WinZipAes;
use PhpZip\Exception\RuntimeException;
@ -12,51 +21,35 @@ use PhpZip\Util\CryptoUtil;
* @see https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT APPENDIX E
* @see https://www.winzip.com/win/en/aes_info.html
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*
* @internal
*/
class WinZipAesContext
{
/** @var int AES Block size */
const BLOCK_SIZE = self::IV_SIZE;
public const BLOCK_SIZE = self::IV_SIZE;
/** @var int Footer size */
const FOOTER_SIZE = 10;
public const FOOTER_SIZE = 10;
/** @var int The iteration count for the derived keys of the cipher, KLAC and MAC. */
const ITERATION_COUNT = 1000;
public const ITERATION_COUNT = 1000;
/** @var int Password verifier size */
const PASSWORD_VERIFIER_SIZE = 2;
public const PASSWORD_VERIFIER_SIZE = 2;
/** @var int IV size */
const IV_SIZE = 16;
public const IV_SIZE = 16;
/** @var string */
private $iv;
private string $iv;
/** @var string */
private $key;
private string $key;
/** @var \HashContext|resource */
private $hmacContext;
private \HashContext $hmacContext;
/** @var string */
private $passwordVerifier;
private string $passwordVerifier;
/**
* WinZipAesContext constructor.
*
* @param int $encryptionStrengthBits
* @param string $password
* @param string $salt
*/
public function __construct($encryptionStrengthBits, $password, $salt)
public function __construct(int $encryptionStrengthBits, string $password, string $salt)
{
$encryptionStrengthBits = (int) $encryptionStrengthBits;
if ($password === '') {
throw new RuntimeException('$password is empty');
}
@ -87,15 +80,12 @@ class WinZipAesContext
$this->passwordVerifier = substr($hash, 2 * $keyStrengthBytes, self::PASSWORD_VERIFIER_SIZE);
}
/**
* @return string
*/
public function getPasswordVerifier()
public function getPasswordVerifier(): string
{
return $this->passwordVerifier;
}
public function updateIv()
public function updateIv(): void
{
for ($ivCharIndex = 0; $ivCharIndex < self::IV_SIZE; $ivCharIndex++) {
$ivByte = \ord($this->iv[$ivCharIndex]);
@ -112,24 +102,14 @@ class WinZipAesContext
}
}
/**
* @param string $data
*
* @return string
*/
public function decryption($data)
public function decryption(string $data): string
{
hash_update($this->hmacContext, $data);
return CryptoUtil::decryptAesCtr($data, $this->key, $this->iv);
}
/**
* @param string $data
*
* @return string
*/
public function encrypt($data)
public function encrypt(string $data): string
{
$encryptionData = CryptoUtil::encryptAesCtr($data, $this->key, $this->iv);
hash_update($this->hmacContext, $encryptionData);
@ -138,11 +118,9 @@ class WinZipAesContext
}
/**
* @param string $authCode
*
* @throws ZipAuthenticationException
*/
public function checkAuthCode($authCode)
public function checkAuthCode(string $authCode): void
{
$hmac = $this->getHmac();
@ -152,10 +130,7 @@ class WinZipAesContext
}
}
/**
* @return string
*/
public function getHmac()
public function getHmac(): string
{
return substr(
hash_final($this->hmacContext, true),

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\IO\Filter\Cipher\WinZipAes;
use PhpZip\Exception\RuntimeException;
@ -12,43 +21,31 @@ use PhpZip\Model\ZipEntry;
*/
class WinZipAesDecryptionStreamFilter extends \php_user_filter
{
const FILTER_NAME = 'phpzip.decryption.winzipaes';
public const FILTER_NAME = 'phpzip.decryption.winzipaes';
/** @var string */
private $buffer;
private string $buffer;
/** @var string */
private $authenticationCode;
private ?string $authenticationCode = null;
/** @var int */
private $encBlockPosition = 0;
private int $encBlockPosition = 0;
/** @var int */
private $encBlockLength = 0;
private int $encBlockLength = 0;
/** @var int */
private $readLength = 0;
private int $readLength = 0;
/** @var ZipEntry */
private $entry;
private ZipEntry $entry;
/** @var WinZipAesContext|null */
private $context;
private ?WinZipAesContext $context = null;
/**
* @return bool
*/
public static function register()
public static function register(): bool
{
return stream_filter_register(self::FILTER_NAME, __CLASS__);
}
/**
* @return bool
*
* @noinspection DuplicatedCode
*/
public function onCreate()
public function onCreate(): bool
{
if (!isset($this->params['entry'])) {
return false;
@ -60,9 +57,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;
}
@ -73,16 +70,10 @@ class WinZipAesDecryptionStreamFilter extends \php_user_filter
}
/**
* @param resource $in
* @param resource $out
* @param int $consumed
* @param bool $closing
*
* @throws ZipAuthenticationException
*
* @return int
* @noinspection PhpDocSignatureInspection
*/
public function filter($in, $out, &$consumed, $closing)
public function filter($in, $out, &$consumed, $closing): int
{
while ($bucket = stream_bucket_make_writeable($in)) {
$this->buffer .= $bucket->data;
@ -156,8 +147,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 = '';
@ -176,11 +167,11 @@ class WinZipAesDecryptionStreamFilter extends \php_user_filter
*
* @throws ZipAuthenticationException
*/
public function onClose()
public function onClose(): void
{
$this->buffer = '';
if ($this->context !== null) {
if ($this->context !== null && $this->authenticationCode !== null) {
$this->context->checkAuthCode($this->authenticationCode);
}
}

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\IO\Filter\Cipher\WinZipAes;
use PhpZip\Exception\RuntimeException;
@ -11,37 +20,27 @@ use PhpZip\Model\ZipEntry;
*/
class WinZipAesEncryptionStreamFilter extends \php_user_filter
{
const FILTER_NAME = 'phpzip.encryption.winzipaes';
public const FILTER_NAME = 'phpzip.encryption.winzipaes';
/** @var string */
private $buffer;
private string $buffer;
/** @var int */
private $remaining = 0;
private int $remaining = 0;
/** @var ZipEntry */
private $entry;
private ZipEntry $entry;
/** @var int */
private $size;
private int $size;
/** @var WinZipAesContext|null */
private $context;
private ?WinZipAesContext $context = null;
/**
* @return bool
*/
public static function register()
public static function register(): bool
{
return stream_filter_register(self::FILTER_NAME, __CLASS__);
}
/**
* @return bool
*
* @noinspection DuplicatedCode
*/
public function onCreate()
public function onCreate(): bool
{
if (!isset($this->params['entry'])) {
return false;
@ -53,9 +52,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;
}
@ -67,15 +66,7 @@ class WinZipAesEncryptionStreamFilter extends \php_user_filter
return true;
}
/**
* @param resource $in
* @param resource $out
* @param int $consumed
* @param bool $closing
*
* @return int
*/
public function filter($in, $out, &$consumed, $closing)
public function filter($in, $out, &$consumed, $closing): int
{
while ($bucket = stream_bucket_make_writeable($in)) {
$this->buffer .= $bucket->data;

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\IO\Stream;
use Psr\Http\Message\StreamInterface;
@ -10,7 +19,7 @@ use Psr\Http\Message\StreamInterface;
class ResponseStream implements StreamInterface
{
/** @var array */
private static $readWriteHash = [
private const READ_WRITE_MAP = [
'read' => [
'r' => true,
'w+' => true,
@ -53,20 +62,15 @@ class ResponseStream implements StreamInterface
/** @var resource */
private $stream;
/** @var int|null */
private $size;
private ?int $size = null;
/** @var bool */
private $seekable;
private bool $seekable;
/** @var bool */
private $readable;
private bool $readable;
/** @var bool */
private $writable;
private bool $writable;
/** @var string|null */
private $uri;
private ?string $uri;
/**
* @param resource $stream stream resource to wrap
@ -81,24 +85,15 @@ class ResponseStream implements StreamInterface
$this->stream = $stream;
$meta = stream_get_meta_data($this->stream);
$this->seekable = $meta['seekable'];
$this->readable = isset(self::$readWriteHash['read'][$meta['mode']]);
$this->writable = isset(self::$readWriteHash['write'][$meta['mode']]);
$this->readable = isset(self::READ_WRITE_MAP['read'][$meta['mode']]);
$this->writable = isset(self::READ_WRITE_MAP['write'][$meta['mode']]);
$this->uri = $this->getMetadata('uri');
}
/**
* Get stream metadata as an associative array or retrieve a specific key.
* {@inheritdoc}
*
* 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.
* @noinspection PhpMissingReturnTypeInspection
*/
public function getMetadata($key = null)
{
@ -107,7 +102,7 @@ class ResponseStream implements StreamInterface
}
$meta = stream_get_meta_data($this->stream);
return isset($meta[$key]) ? $meta[$key] : null;
return $meta[$key] ?? null;
}
/**
@ -122,10 +117,8 @@ class ResponseStream implements StreamInterface
* string casting operations.
*
* @see http://php.net/manual/en/language.oop5.magic.php#object.tostring
*
* @return string
*/
public function __toString()
public function __toString(): string
{
if (!$this->stream) {
return '';
@ -146,7 +139,7 @@ class ResponseStream implements StreamInterface
* @see http://www.php.net/manual/en/function.fseek.php
* @see seek()
*/
public function rewind()
public function rewind(): void
{
$this->seekable && rewind($this->stream);
}
@ -156,7 +149,7 @@ class ResponseStream implements StreamInterface
*
* @return int|null returns the size in bytes if known, or null if unknown
*/
public function getSize()
public function getSize(): ?int
{
if ($this->size !== null) {
return $this->size;
@ -180,13 +173,6 @@ class ResponseStream implements StreamInterface
return null;
}
/**
* Returns the current position of the file read/write pointer.
*
* @throws \RuntimeException on error
*
* @return int Position of the file pointer
*/
public function tell()
{
return $this->stream ? ftell($this->stream) : false;
@ -194,61 +180,38 @@ class ResponseStream implements StreamInterface
/**
* Returns true if the stream is at the end of the stream.
*
* @return bool
*/
public function eof()
public function eof(): bool
{
return !$this->stream || feof($this->stream);
}
/**
* Returns whether or not the stream is seekable.
*
* @return bool
*/
public function isSeekable()
public function isSeekable(): bool
{
return $this->seekable;
}
/**
* Seek to a position in the stream.
*
* @see http://www.php.net/manual/en/function.fseek.php
*
* @param int $offset Stream offset
* @param int $whence Specifies how the cursor position will be calculated
* based on the seek offset. Valid values are identical to the built-in
* PHP $whence values for `fseek()`. SEEK_SET: Set position equal to
* offset bytes SEEK_CUR: Set position to current location plus offset
* SEEK_END: Set position to end-of-stream plus offset.
*
* @throws \RuntimeException on failure
* {@inheritdoc}
*/
public function seek($offset, $whence = \SEEK_SET)
public function seek($offset, $whence = \SEEK_SET): void
{
$this->seekable && fseek($this->stream, $offset, $whence);
}
/**
* Returns whether or not the stream is writable.
*
* @return bool
*/
public function isWritable()
public function isWritable(): bool
{
return $this->writable;
}
/**
* Write data to the stream.
*
* @param string $string the string that is to be written
*
* @throws \RuntimeException on failure
*
* @return int returns the number of bytes written to the stream
* {@inheritdoc}
*/
public function write($string)
{
@ -259,27 +222,16 @@ class ResponseStream implements StreamInterface
/**
* Returns whether or not the stream is readable.
*
* @return bool
*/
public function isReadable()
public function isReadable(): bool
{
return $this->readable;
}
/**
* Read data from the stream.
*
* @param int $length Read up to $length bytes from the object and return
* them. Fewer than $length bytes may be returned if underlying stream
* call returns fewer bytes.
*
* @throws \RuntimeException if an error occurs
*
* @return string returns the data read from the stream, or an empty string
* if no bytes are available
* {@inheritdoc}
*/
public function read($length)
public function read($length): string
{
return $this->readable ? fread($this->stream, $length) : '';
}
@ -289,10 +241,8 @@ class ResponseStream implements StreamInterface
*
* @throws \RuntimeException if unable to read or an error occurs while
* reading
*
* @return string
*/
public function getContents()
public function getContents(): string
{
return $this->stream ? stream_get_contents($this->stream) : '';
}
@ -308,7 +258,7 @@ class ResponseStream implements StreamInterface
/**
* Closes the stream and any underlying resources.
*/
public function close()
public function close(): void
{
if (\is_resource($this->stream)) {
fclose($this->stream);

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\IO\Stream;
use PhpZip\Exception\ZipException;
@ -15,7 +24,7 @@ use PhpZip\Model\ZipEntry;
final class ZipEntryStreamWrapper
{
/** @var string the registered protocol */
const PROTOCOL = 'zipentry';
public const PROTOCOL = 'zipentry';
/** @var resource */
public $context;
@ -23,10 +32,7 @@ final class ZipEntryStreamWrapper
/** @var resource */
private $fp;
/**
* @return bool
*/
public static function register()
public static function register(): bool
{
$protocol = self::PROTOCOL;
@ -41,14 +47,12 @@ final class ZipEntryStreamWrapper
return false;
}
public static function unregister()
public static function unregister(): void
{
stream_wrapper_unregister(self::PROTOCOL);
}
/**
* @param ZipEntry $entry
*
* @return resource
*/
public static function wrap(ZipEntry $entry)
@ -79,26 +83,24 @@ final class ZipEntryStreamWrapper
* This method is called immediately after the wrapper is
* initialized (f.e. by {@see fopen()} and {@see file_get_contents()}).
*
* @param string $path specifies the URL that was passed to
* the original function
* @param string $mode the mode used to open the file, as detailed
* for {@see fopen()}
* @param int $options Holds additional flags set by the streams
* API. It can hold one or more of the
* following values OR'd together.
* @param string $opened_path if the path is opened successfully, and
* STREAM_USE_PATH is set in options,
* opened_path should be set to the
* full path of the file/resource that
* was actually opened
* @param string $path specifies the URL that was passed to
* the original function
* @param string $mode the mode used to open the file, as detailed
* for {@see fopen()}
* @param int $options Holds additional flags set by the streams
* API. It can hold one or more of the
* following values OR'd together.
* @param string|null $opened_path if the path is opened successfully, and
* STREAM_USE_PATH is set in options,
* opened_path should be set to the
* full path of the file/resource that
* was actually opened
*
* @throws ZipException
*
* @return bool
*
* @see https://www.php.net/streamwrapper.stream-open
*/
public function stream_open($path, $mode, $options, &$opened_path)
public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool
{
if ($this->context === null) {
throw new \RuntimeException('stream context is null');
@ -142,7 +144,7 @@ final class ZipEntryStreamWrapper
*
* @see https://www.php.net/streamwrapper.stream-read
*/
public function stream_read($count)
public function stream_read(int $count)
{
return fread($this->fp, $count);
}
@ -164,7 +166,7 @@ final class ZipEntryStreamWrapper
*
* @see https://www.php.net/streamwrapper.stream-seek
*/
public function stream_seek($offset, $whence = \SEEK_SET)
public function stream_seek(int $offset, int $whence = \SEEK_SET): bool
{
return fseek($this->fp, $offset, $whence) === 0;
}
@ -179,7 +181,7 @@ final class ZipEntryStreamWrapper
*
* @see https://www.php.net/streamwrapper.stream-tell
*/
public function stream_tell()
public function stream_tell(): int
{
$pos = ftell($this->fp);
@ -201,7 +203,7 @@ final class ZipEntryStreamWrapper
*
* @see https://www.php.net/streamwrapper.stream-eof
*/
public function stream_eof()
public function stream_eof(): bool
{
return feof($this->fp);
}
@ -211,13 +213,11 @@ final class ZipEntryStreamWrapper
*
* This method is called in response to {@see fstat()}.
*
* @return array
*
* @see https://www.php.net/streamwrapper.stream-stat
* @see https://www.php.net/stat
* @see https://www.php.net/fstat
*/
public function stream_stat()
public function stream_stat(): array
{
return fstat($this->fp);
}
@ -237,7 +237,7 @@ final class ZipEntryStreamWrapper
*
* @see https://www.php.net/streamwrapper.stream-flush
*/
public function stream_flush()
public function stream_flush(): bool
{
return fflush($this->fp);
}
@ -247,15 +247,15 @@ final class ZipEntryStreamWrapper
*
* Will respond to truncation, e.g., through {@see ftruncate()}.
*
* @param int $new_size the new size
* @param int $newSize the new size
*
* @return bool returns TRUE on success or FALSE on failure
*
* @see https://www.php.net/streamwrapper.stream-truncate
*/
public function stream_truncate($new_size)
public function stream_truncate(int $newSize): bool
{
return ftruncate($this->fp, (int) $new_size);
return ftruncate($this->fp, $newSize);
}
/**
@ -272,7 +272,7 @@ final class ZipEntryStreamWrapper
*
* @see https://www.php.net/streamwrapper.stream-write
*/
public function stream_write($data)
public function stream_write(string $data): int
{
$bytes = fwrite($this->fp, $data);
@ -290,7 +290,7 @@ final class ZipEntryStreamWrapper
*
* @return resource
*/
public function stream_cast($cast_as)
public function stream_cast(int $cast_as)
{
return $this->fp;
}
@ -303,7 +303,7 @@ final class ZipEntryStreamWrapper
*
* @see https://www.php.net/streamwrapper.stream-close
*/
public function stream_close()
public function stream_close(): void
{
}
}

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\IO;
use PhpZip\Constants\DosCodePage;
@ -24,28 +33,22 @@ use PhpZip\Model\Extra\ZipExtraDriver;
use PhpZip\Model\Extra\ZipExtraField;
use PhpZip\Model\ImmutableZipContainer;
use PhpZip\Model\ZipEntry;
use PhpZip\Util\PackUtil;
/**
* Zip reader.
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*/
class ZipReader
{
/** @var int file size */
protected $size;
protected int $size;
/** @var resource */
protected $inStream;
/** @var array */
protected $options;
protected array $options;
/**
* @param resource $inStream
* @param array $options
*/
public function __construct($inStream, array $options = [])
{
@ -59,7 +62,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 +75,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,10 +97,7 @@ class ZipReader
$this->options = $options;
}
/**
* @return array
*/
protected function getDefaultOptions()
protected function getDefaultOptions(): array
{
return [
ZipOptions::CHARSET => null,
@ -106,10 +106,8 @@ class ZipReader
/**
* @throws ZipException
*
* @return ImmutableZipContainer
*/
public function read()
public function read(): ImmutableZipContainer
{
if ($this->size < ZipConstants::END_CD_MIN_LEN) {
throw new ZipException('Corrupt zip file');
@ -121,10 +119,7 @@ class ZipReader
return new ImmutableZipContainer($entries, $endOfCentralDirectory->getComment());
}
/**
* @return array
*/
public function getStreamMetaData()
public function getStreamMetaData(): array
{
return stream_get_meta_data($this->inStream);
}
@ -148,10 +143,8 @@ class ZipReader
* .ZIP file comment (variable size)
*
* @throws ZipException
*
* @return EndOfCentralDirectory
*/
protected function readEndOfCentralDirectory()
protected function readEndOfCentralDirectory(): EndOfCentralDirectory
{
if (!$this->findEndOfCentralDirectory()) {
throw new ZipException('Invalid zip file. The end of the central directory could not be found.');
@ -161,26 +154,34 @@ class ZipReader
$sizeECD = $this->size - ftell($this->inStream);
$buffer = fread($this->inStream, $sizeECD);
$unpack = unpack(
'vdiskNo/vcdDiskNo/vcdEntriesDisk/' .
'vcdEntries/VcdSize/VcdPos/vcommentLength',
[
'diskNo' => $diskNo,
'cdDiskNo' => $cdDiskNo,
'cdEntriesDisk' => $cdEntriesDisk,
'cdEntries' => $cdEntries,
'cdSize' => $cdSize,
'cdPos' => $cdPos,
'commentLength' => $commentLength,
] = unpack(
'vdiskNo/vcdDiskNo/vcdEntriesDisk/'
. 'vcdEntries/VcdSize/VcdPos/vcommentLength',
substr($buffer, 0, 18)
);
if (
$unpack['diskNo'] !== 0 ||
$unpack['cdDiskNo'] !== 0 ||
$unpack['cdEntriesDisk'] !== $unpack['cdEntries']
$diskNo !== 0
|| $cdDiskNo !== 0
|| $cdEntriesDisk !== $cdEntries
) {
throw new ZipException(
'ZIP file spanning/splitting is not supported!'
);
}
// .ZIP file comment (variable sizeECD)
$comment = null;
if ($unpack['commentLength'] > 0) {
$comment = substr($buffer, 18, $unpack['commentLength']);
if ($commentLength > 0) {
// .ZIP file comment (variable sizeECD)
$comment = substr($buffer, 18, $commentLength);
}
// Check for ZIP64 End Of Central Directory Locator exists.
@ -188,10 +189,10 @@ class ZipReader
fseek($this->inStream, $zip64ECDLocatorPosition);
// zip64 end of central dir locator
// signature 4 bytes (0x07064b50)
if ($zip64ECDLocatorPosition > 0 && unpack(
'V',
fread($this->inStream, 4)
)[1] === ZipConstants::ZIP64_END_CD_LOC) {
if (
$zip64ECDLocatorPosition > 0
&& unpack('V', fread($this->inStream, 4))[1] === ZipConstants::ZIP64_END_CD_LOC
) {
if (!$this->isZip64Support()) {
throw new ZipException('ZIP64 not supported this archive.');
}
@ -201,9 +202,9 @@ class ZipReader
$endCentralDirectory->setComment($comment);
} else {
$endCentralDirectory = new EndOfCentralDirectory(
$unpack['cdEntries'],
$unpack['cdPos'],
$unpack['cdSize'],
$cdEntries,
$cdPos,
$cdSize,
false,
$comment
);
@ -212,10 +213,7 @@ class ZipReader
return $endCentralDirectory;
}
/**
* @return bool
*/
protected function findEndOfCentralDirectory()
protected function findEndOfCentralDirectory(): bool
{
$max = $this->size - ZipConstants::END_CD_MIN_LEN;
$min = $max >= 0xffff ? $max - 0xffff : 0;
@ -248,11 +246,13 @@ class ZipReader
*
* @return int Zip64 End Of Central Directory position
*/
protected function findZip64ECDPosition()
protected function findZip64ECDPosition(): int
{
$diskNo = unpack('V', fread($this->inStream, 4))[1];
$zip64ECDPos = PackUtil::unpackLongLE(fread($this->inStream, 8));
$totalDisks = unpack('V', fread($this->inStream, 4))[1];
[
'diskNo' => $diskNo,
'zip64ECDPos' => $zip64ECDPos,
'totalDisks' => $totalDisks,
] = unpack('VdiskNo/Pzip64ECDPos/VtotalDisks', fread($this->inStream, 16));
if ($diskNo !== 0 || $totalDisks > 1) {
throw new ZipException('ZIP file spanning/splitting is not supported!');
@ -284,13 +284,9 @@ class ZipReader
* the starting disk number 8 bytes
* zip64 extensible data sector (variable size)
*
* @param int $zip64ECDPosition
*
* @throws ZipException
*
* @return EndOfCentralDirectory
*/
protected function readZip64EndOfCentralDirectory($zip64ECDPosition)
protected function readZip64EndOfCentralDirectory(int $zip64ECDPosition): EndOfCentralDirectory
{
fseek($this->inStream, $zip64ECDPosition);
@ -300,21 +296,26 @@ class ZipReader
throw new ZipException('Expected ZIP64 End Of Central Directory Record!');
}
$data = unpack(
// 'Psize/vversionMadeBy/vextractVersion/' .
'VdiskNo/VcdDiskNo',
substr($buffer, 16, 8)
[
// 'size' => $size,
// 'versionMadeBy' => $versionMadeBy,
// 'extractVersion' => $extractVersion,
'diskNo' => $diskNo,
'cdDiskNo' => $cdDiskNo,
'cdEntriesDisk' => $cdEntriesDisk,
'entryCount' => $entryCount,
'cdSize' => $cdSize,
'cdPos' => $cdPos,
] = unpack(
// 'Psize/vversionMadeBy/vextractVersion/'.
'VdiskNo/VcdDiskNo/PcdEntriesDisk/PentryCount/PcdSize/PcdPos',
substr($buffer, 16, 40)
);
$cdEntriesDisk = PackUtil::unpackLongLE(substr($buffer, 24, 8));
$entryCount = PackUtil::unpackLongLE(substr($buffer, 32, 8));
$cdSize = PackUtil::unpackLongLE(substr($buffer, 40, 8));
$cdPos = PackUtil::unpackLongLE(substr($buffer, 48, 8));
// $platform = ZipPlatform::fromValue(($versionMadeBy & 0xFF00) >> 8);
// $softwareVersion = $versionMadeBy & 0x00FF;
// $platform = ZipPlatform::fromValue(($data['versionMadeBy'] & 0xFF00) >> 8);
// $softwareVersion = $data['versionMadeBy'] & 0x00FF;
if ($data['diskNo'] !== 0 || $data['cdDiskNo'] !== 0 || $entryCount !== $cdEntriesDisk) {
if ($diskNo !== 0 || $cdDiskNo !== 0 || $entryCount !== $cdEntriesDisk) {
throw new ZipException('ZIP file spanning/splitting is not supported!');
}
@ -340,13 +341,11 @@ class ZipReader
* central directory alone, but not the data that requires the local
* file header or additional data to be read.
*
* @param EndOfCentralDirectory $endCD
*
* @throws ZipException
*
* @return ZipEntry[]
*/
protected function readCentralDirectory(EndOfCentralDirectory $endCD)
protected function readCentralDirectory(EndOfCentralDirectory $endCD): array
{
$entries = [];
@ -375,8 +374,8 @@ class ZipReader
$unicodePath = str_replace('\\', '/', $unicodePath);
if (
$unicodePath !== '' &&
substr_count($entryName, '/') === substr_count($unicodePath, '/')
$unicodePath !== ''
&& substr_count($entryName, '/') === substr_count($unicodePath, '/')
) {
$entryName = $unicodePath;
}
@ -417,46 +416,56 @@ class ZipReader
* @param resource $stream
*
* @throws ZipException
*
* @return ZipEntry
*/
protected function readZipEntry($stream)
protected function readZipEntry($stream): ZipEntry
{
if (unpack('V', fread($stream, 4))[1] !== ZipConstants::CENTRAL_FILE_HEADER) {
throw new ZipException('Corrupt zip file. Cannot read zip entry.');
}
$unpack = unpack(
'vversionMadeBy/vversionNeededToExtract/' .
'vgeneralPurposeBitFlag/vcompressionMethod/' .
'VlastModFile/Vcrc/VcompressedSize/' .
'VuncompressedSize/vfileNameLength/vextraFieldLength/' .
'vfileCommentLength/vdiskNumberStart/vinternalFileAttributes/' .
'VexternalFileAttributes/VoffsetLocalHeader',
[
'versionMadeBy' => $versionMadeBy,
'versionNeededToExtract' => $versionNeededToExtract,
'generalPurposeBitFlags' => $generalPurposeBitFlags,
'compressionMethod' => $compressionMethod,
'lastModFile' => $dosTime,
'crc' => $crc,
'compressedSize' => $compressedSize,
'uncompressedSize' => $uncompressedSize,
'fileNameLength' => $fileNameLength,
'extraFieldLength' => $extraFieldLength,
'fileCommentLength' => $fileCommentLength,
'diskNumberStart' => $diskNumberStart,
'internalFileAttributes' => $internalFileAttributes,
'externalFileAttributes' => $externalFileAttributes,
'offsetLocalHeader' => $offsetLocalHeader,
] = unpack(
'vversionMadeBy/vversionNeededToExtract/'
. 'vgeneralPurposeBitFlags/vcompressionMethod/'
. 'VlastModFile/Vcrc/VcompressedSize/'
. 'VuncompressedSize/vfileNameLength/vextraFieldLength/'
. 'vfileCommentLength/vdiskNumberStart/vinternalFileAttributes/'
. 'VexternalFileAttributes/VoffsetLocalHeader',
fread($stream, 42)
);
if ($unpack['diskNumberStart'] !== 0) {
if ($diskNumberStart !== 0) {
throw new ZipException('ZIP file spanning/splitting is not supported!');
}
$generalPurposeBitFlags = $unpack['generalPurposeBitFlag'];
$isUtf8 = ($generalPurposeBitFlags & GeneralPurposeBitFlag::UTF8) !== 0;
$name = fread($stream, $unpack['fileNameLength']);
$name = fread($stream, $fileNameLength);
$createdOS = ($unpack['versionMadeBy'] & 0xFF00) >> 8;
$softwareVersion = $unpack['versionMadeBy'] & 0x00FF;
$extractedOS = ($unpack['versionNeededToExtract'] & 0xFF00) >> 8;
$extractVersion = $unpack['versionNeededToExtract'] & 0x00FF;
$dosTime = $unpack['lastModFile'];
$createdOS = ($versionMadeBy & 0xFF00) >> 8;
$softwareVersion = $versionMadeBy & 0x00FF;
$extractedOS = ($versionNeededToExtract & 0xFF00) >> 8;
$extractVersion = $versionNeededToExtract & 0x00FF;
$comment = null;
if ($unpack['fileCommentLength'] > 0) {
$comment = fread($stream, $unpack['fileCommentLength']);
if ($fileCommentLength > 0) {
$comment = fread($stream, $fileCommentLength);
}
// decode code page names
@ -479,24 +488,23 @@ class ZipReader
$extractedOS,
$softwareVersion,
$extractVersion,
$unpack['compressionMethod'],
$compressionMethod,
$generalPurposeBitFlags,
$dosTime,
$unpack['crc'],
$unpack['compressedSize'],
$unpack['uncompressedSize'],
$unpack['internalFileAttributes'],
$unpack['externalFileAttributes'],
$unpack['offsetLocalHeader'],
$crc,
$compressedSize,
$uncompressedSize,
$internalFileAttributes,
$externalFileAttributes,
$offsetLocalHeader,
$comment,
$fallbackCharset
);
if ($unpack['extraFieldLength'] > 0) {
if ($extraFieldLength > 0) {
$this->parseExtraFields(
fread($stream, $unpack['extraFieldLength']),
$zipEntry,
false
fread($stream, $extraFieldLength),
$zipEntry
);
/** @var Zip64ExtraField|null $extraZip64 */
@ -514,33 +522,27 @@ class ZipReader
return $zipEntry;
}
/**
* @param string $buffer
* @param ZipEntry $zipEntry
* @param bool $local
*
* @return ExtraFieldsCollection
*/
protected function parseExtraFields($buffer, ZipEntry $zipEntry, $local = false)
protected function parseExtraFields(string $buffer, ZipEntry $zipEntry, bool $local = false): ExtraFieldsCollection
{
$collection = $local ?
$zipEntry->getLocalExtraFields() :
$zipEntry->getCdExtraFields();
$collection = $local
? $zipEntry->getLocalExtraFields()
: $zipEntry->getCdExtraFields();
if (!empty($buffer)) {
$pos = 0;
$endPos = \strlen($buffer);
while ($endPos - $pos >= 4) {
/** @var int[] $data */
$data = unpack('vheaderId/vdataSize', substr($buffer, $pos, 4));
[
'headerId' => $headerId,
'dataSize' => $dataSize,
] = unpack('vheaderId/vdataSize', substr($buffer, $pos, 4));
$pos += 4;
if ($endPos - $pos - $data['dataSize'] < 0) {
if ($endPos - $pos - $dataSize < 0) {
break;
}
$bufferData = substr($buffer, $pos, $data['dataSize']);
$headerId = $data['headerId'];
$bufferData = substr($buffer, $pos, $dataSize);
/** @var string|ZipExtraField|null $className */
$className = ZipExtraDriver::getClassNameOrNull($headerId);
@ -548,9 +550,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
? $className::unpackLocalFileData($bufferData, $zipEntry)
: $className::unpackCentralDirData($bufferData, $zipEntry);
} catch (\Throwable $e) {
// skip errors while parsing invalid data
continue;
@ -560,7 +562,7 @@ class ZipReader
}
$collection->add($extraField);
} finally {
$pos += $data['dataSize'];
$pos += $dataSize;
}
}
}
@ -568,11 +570,7 @@ class ZipReader
return $collection;
}
/**
* @param Zip64ExtraField $extraZip64
* @param ZipEntry $zipEntry
*/
protected function handleZip64Extra(Zip64ExtraField $extraZip64, ZipEntry $zipEntry)
protected function handleZip64Extra(Zip64ExtraField $extraZip64, ZipEntry $zipEntry): void
{
$uncompressedSize = $extraZip64->getUncompressedSize();
$compressedSize = $extraZip64->getCompressedSize();
@ -608,11 +606,9 @@ class ZipReader
* file name (variable size)
* extra field (variable size)
*
* @param ZipEntry $entry
*
* @throws ZipException
*/
protected function loadLocalExtraFields(ZipEntry $entry)
protected function loadLocalExtraFields(ZipEntry $entry): void
{
$offsetLocalHeader = $entry->getLocalHeaderOffset();
@ -623,16 +619,16 @@ class ZipReader
}
fseek($this->inStream, $offsetLocalHeader + ZipConstants::LFH_FILENAME_LENGTH_POS);
$unpack = unpack('vfileNameLength/vextraFieldLength', fread($this->inStream, 4));
$offsetData = ftell($this->inStream)
+ $unpack['fileNameLength']
+ $unpack['extraFieldLength'];
[
'fileNameLength' => $fileNameLength,
'extraFieldLength' => $extraFieldLength,
] = unpack('vfileNameLength/vextraFieldLength', fread($this->inStream, 4));
$offsetData = ftell($this->inStream) + $fileNameLength + $extraFieldLength;
fseek($this->inStream, $fileNameLength, \SEEK_CUR);
fseek($this->inStream, $unpack['fileNameLength'], \SEEK_CUR);
if ($unpack['extraFieldLength'] > 0) {
if ($extraFieldLength > 0) {
$this->parseExtraFields(
fread($this->inStream, $unpack['extraFieldLength']),
fread($this->inStream, $extraFieldLength),
$entry,
true
);
@ -643,11 +639,9 @@ class ZipReader
}
/**
* @param ZipEntry $zipEntry
*
* @throws ZipException
*/
private function handleExtraEncryptionFields(ZipEntry $zipEntry)
private function handleExtraEncryptionFields(ZipEntry $zipEntry): void
{
if ($zipEntry->isEncrypted()) {
if ($zipEntry->getCompressionMethod() === ZipCompressionMethod::WINZIP_AES) {
@ -676,16 +670,12 @@ class ZipReader
*
* This is a special method in which you can process ExtraField
* and make changes to ZipEntry.
*
* @param ZipEntry $zipEntry
*/
protected function handleExtraFields(ZipEntry $zipEntry)
protected function handleExtraFields(ZipEntry $zipEntry): void
{
}
/**
* @param ZipSourceFileData $zipFileData
*
* @throws ZipException
* @throws Crc32Exception
*
@ -701,13 +691,12 @@ class ZipReader
}
/**
* @param ZipSourceFileData $zipFileData
* @param resource $outStream
* @param resource $outStream
*
* @throws Crc32Exception
* @throws ZipException
*/
public function copyUncompressedDataToStream(ZipSourceFileData $zipFileData, $outStream)
public function copyUncompressedDataToStream(ZipSourceFileData $zipFileData, $outStream): void
{
if (!\is_resource($outStream)) {
throw new InvalidArgumentException('outStream is not resource');
@ -865,10 +854,9 @@ class ZipReader
}
/**
* @param ZipSourceFileData $zipData
* @param resource $outStream
* @param resource $outStream
*/
public function copyCompressedDataToStream(ZipSourceFileData $zipData, $outStream)
public function copyCompressedDataToStream(ZipSourceFileData $zipData, $outStream): void
{
if ($zipData->getCompressedSize() > 0) {
fseek($this->inStream, $zipData->getOffset());
@ -876,15 +864,12 @@ class ZipReader
}
}
/**
* @return bool
*/
protected function isZip64Support()
protected function isZip64Support(): bool
{
return \PHP_INT_SIZE === 8; // true for 64bit system
}
public function close()
public function close(): void
{
if (\is_resource($this->inStream)) {
fclose($this->inStream);

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\IO;
use PhpZip\Constants\DosCodePage;
@ -13,30 +22,18 @@ use PhpZip\Exception\ZipUnsupportMethodException;
use PhpZip\IO\Filter\Cipher\Pkware\PKEncryptionStreamFilter;
use PhpZip\IO\Filter\Cipher\WinZipAes\WinZipAesEncryptionStreamFilter;
use PhpZip\Model\Data\ZipSourceFileData;
use PhpZip\Model\Extra\Fields\ApkAlignmentExtraField;
use PhpZip\Model\Extra\Fields\WinZipAesExtraField;
use PhpZip\Model\Extra\Fields\Zip64ExtraField;
use PhpZip\Model\ZipContainer;
use PhpZip\Model\ZipEntry;
use PhpZip\Util\PackUtil;
use PhpZip\Util\StringUtil;
/**
* Class ZipWriter.
*/
class ZipWriter
{
/** @var int Chunk read size */
const CHUNK_SIZE = 8192;
public const CHUNK_SIZE = 8192;
/** @var ZipContainer */
protected $zipContainer;
protected ZipContainer $zipContainer;
/**
* ZipWriter constructor.
*
* @param ZipContainer $container
*/
public function __construct(ZipContainer $container)
{
// we clone the container so that the changes made to
@ -49,7 +46,7 @@ class ZipWriter
*
* @throws ZipException
*/
public function write($outStream)
public function write($outStream): void
{
if (!\is_resource($outStream)) {
throw new \InvalidArgumentException('$outStream must be resource');
@ -62,7 +59,7 @@ class ZipWriter
$this->writeEndOfCentralDirectoryBlock($outStream, $cdOffset, $cdSize);
}
protected function beforeWrite()
protected function beforeWrite(): void
{
}
@ -71,7 +68,7 @@ class ZipWriter
*
* @throws ZipException
*/
protected function writeLocalBlock($outStream)
protected function writeLocalBlock($outStream): void
{
$zipEntries = $this->zipContainer->getEntries();
@ -87,17 +84,11 @@ class ZipWriter
/**
* @param resource $outStream
* @param ZipEntry $entry
*
* @throws ZipException
*/
protected function writeLocalHeader($outStream, ZipEntry $entry)
protected function writeLocalHeader($outStream, ZipEntry $entry): void
{
// todo in 4.0 version move zipalign functional to ApkWriter class
if ($this->zipContainer->isZipAlign()) {
$this->zipAlign($outStream, $entry);
}
$relativeOffset = ftell($outStream);
$entry->setLocalHeaderOffset($relativeOffset);
@ -105,8 +96,8 @@ class ZipWriter
$entry->enableDataDescriptor(true);
}
$dd = $entry->isDataDescriptorRequired() ||
$entry->isDataDescriptorEnabled();
$dd = $entry->isDataDescriptorRequired()
|| $entry->isDataDescriptorEnabled();
$compressedSize = $entry->getCompressedSize();
$uncompressedSize = $entry->getUncompressedSize();
@ -202,75 +193,16 @@ class ZipWriter
}
}
/**
* @param resource $outStream
* @param ZipEntry $entry
*
* @throws ZipException
*/
private function zipAlign($outStream, ZipEntry $entry)
{
if (!$entry->isDirectory() && $entry->getCompressionMethod() === ZipCompressionMethod::STORED) {
$entry->removeExtraField(ApkAlignmentExtraField::HEADER_ID);
$extra = $this->getExtraFieldsContents($entry, true);
$extraLength = \strlen($extra);
$name = $entry->getName();
$dosCharset = $entry->getCharset();
if ($dosCharset !== null && !$entry->isUtf8Flag()) {
$name = DosCodePage::fromUTF8($name, $dosCharset);
}
$nameLength = \strlen($name);
$multiple = ApkAlignmentExtraField::ALIGNMENT_BYTES;
if (StringUtil::endsWith($name, '.so')) {
$multiple = ApkAlignmentExtraField::COMMON_PAGE_ALIGNMENT_BYTES;
}
$offset = ftell($outStream);
$dataMinStartOffset =
$offset +
ZipConstants::LFH_FILENAME_POS +
$extraLength +
$nameLength;
$padding =
($multiple - ($dataMinStartOffset % $multiple))
% $multiple;
if ($padding > 0) {
$dataMinStartOffset += ApkAlignmentExtraField::MIN_SIZE;
$padding =
($multiple - ($dataMinStartOffset % $multiple))
% $multiple;
$entry->getLocalExtraFields()->add(
new ApkAlignmentExtraField($multiple, $padding)
);
}
}
}
/**
* Merges the local file data fields of the given ZipExtraFields.
*
* @param ZipEntry $entry
* @param bool $local
*
* @throws ZipException
*
* @return string
*/
protected function getExtraFieldsContents(ZipEntry $entry, $local)
protected function getExtraFieldsContents(ZipEntry $entry, bool $local): string
{
$local = (bool) $local;
$collection = $local ?
$entry->getLocalExtraFields() :
$entry->getCdExtraFields();
$collection = $local
? $entry->getLocalExtraFields()
: $entry->getCdExtraFields();
$extraData = '';
foreach ($collection as $extraField) {
@ -304,11 +236,10 @@ class ZipWriter
/**
* @param resource $outStream
* @param ZipEntry $entry
*
* @throws ZipException
*/
protected function writeData($outStream, ZipEntry $entry)
protected function writeData($outStream, ZipEntry $entry): void
{
$zipData = $entry->getData();
@ -449,11 +380,8 @@ class ZipWriter
/**
* @param resource $inStream
* @param resource $outStream
* @param int $size
*
* @return int
*/
private function writeAndCountChecksum($inStream, $outStream, $size)
private function writeAndCountChecksum($inStream, $outStream, int $size): int
{
$contextHash = hash_init('crc32b');
$offset = 0;
@ -471,7 +399,6 @@ class ZipWriter
/**
* @param resource $outStream
* @param ZipEntry $entry
*
* @throws ZipUnsupportMethodException
*
@ -523,12 +450,10 @@ class ZipWriter
/**
* @param resource $outStream
* @param ZipEntry $entry
* @param int $size
*
* @return resource|null
*/
protected function appendEncryptionFilter($outStream, ZipEntry $entry, $size)
protected function appendEncryptionFilter($outStream, ZipEntry $entry, int $size)
{
$encContextFilter = null;
@ -560,9 +485,8 @@ class ZipWriter
/**
* @param resource $outStream
* @param ZipEntry $entry
*/
protected function writeDataDescriptor($outStream, ZipEntry $entry)
protected function writeDataDescriptor($outStream, ZipEntry $entry): void
{
$crc = $entry->getCrc();
@ -585,14 +509,16 @@ class ZipWriter
);
if (
$entry->isZip64ExtensionsRequired() ||
$entry->getLocalExtraFields()->has(Zip64ExtraField::HEADER_ID)
$entry->isZip64ExtensionsRequired()
|| $entry->getLocalExtraFields()->has(Zip64ExtraField::HEADER_ID)
) {
$dd =
$dd = pack(
'PP',
// compressed size 8 bytes
PackUtil::packLongLE($entry->getCompressedSize()) .
$entry->getCompressedSize(),
// uncompressed size 8 bytes
PackUtil::packLongLE($entry->getUncompressedSize());
$entry->getUncompressedSize()
);
} else {
$dd = pack(
'VV',
@ -611,7 +537,7 @@ class ZipWriter
*
* @throws ZipException
*/
protected function writeCentralDirectoryBlock($outStream)
protected function writeCentralDirectoryBlock($outStream): void
{
foreach ($this->zipContainer->getEntries() as $outputEntry) {
$this->writeCentralDirectoryHeader($outStream, $outputEntry);
@ -622,11 +548,10 @@ class ZipWriter
* Writes a Central File Header record.
*
* @param resource $outStream
* @param ZipEntry $entry
*
* @throws ZipException
*/
protected function writeCentralDirectoryHeader($outStream, ZipEntry $entry)
protected function writeCentralDirectoryHeader($outStream, ZipEntry $entry): void
{
$compressedSize = $entry->getCompressedSize();
$uncompressedSize = $entry->getUncompressedSize();
@ -635,9 +560,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();
@ -745,14 +670,12 @@ class ZipWriter
/**
* @param resource $outStream
* @param int $centralDirectoryOffset
* @param int $centralDirectorySize
*/
protected function writeEndOfCentralDirectoryBlock(
$outStream,
$centralDirectoryOffset,
$centralDirectorySize
) {
int $centralDirectoryOffset,
int $centralDirectorySize
): void {
$cdEntriesCount = \count($this->zipContainer);
$cdEntriesZip64 = $cdEntriesCount > 0xffff;
@ -767,7 +690,7 @@ class ZipWriter
$zip64EndOfCentralDirectoryOffset = ftell($outStream);
// find max software version, version needed to extract and most common platform
list($softwareVersion, $versionNeededToExtract) = array_reduce(
[$softwareVersion, $versionNeededToExtract] = array_reduce(
$this->zipContainer->getEntries(),
static function (array $carry, ZipEntry $entry) {
$carry[0] = max($carry[0], $entry->getSoftwareVersion() & 0xFF);
@ -786,18 +709,12 @@ class ZipWriter
fwrite(
$outStream,
pack(
'V',
'VPvvVVPPPPVVPV',
// signature 4 bytes (0x06064b50)
ZipConstants::ZIP64_END_CD
)
);
// size of zip64 end of central
// directory record 8 bytes
fwrite($outStream, PackUtil::packLongLE(ZipConstants::ZIP64_END_OF_CD_LEN - 12));
fwrite(
$outStream,
pack(
'vvVV',
ZipConstants::ZIP64_END_CD,
// size of zip64 end of central
// directory record 8 bytes
ZipConstants::ZIP64_END_OF_CD_LEN - 12,
// version made by 2 bytes
$versionMadeBy & 0xFFFF,
// version needed to extract 2 bytes
@ -806,44 +723,32 @@ class ZipWriter
0,
// number of the disk with the
// start of the central directory 4 bytes
0
)
);
fwrite(
$outStream,
// total number of entries in the
// central directory on this disk 8 bytes
PackUtil::packLongLE($cdEntriesCount) .
// total number of entries in the
// central directory 8 bytes
PackUtil::packLongLE($cdEntriesCount) .
// size of the central directory 8 bytes
PackUtil::packLongLE($centralDirectorySize) .
// offset of start of central
// directory with respect to
// the starting disk number 8 bytes
PackUtil::packLongLE($centralDirectoryOffset)
);
// write zip64 end of central directory locator
fwrite(
$outStream,
pack(
'VV',
0,
// total number of entries in the
// central directory on this disk 8 bytes
$cdEntriesCount,
// total number of entries in the
// central directory 8 bytes
$cdEntriesCount,
// size of the central directory 8 bytes
$centralDirectorySize,
// offset of start of central
// directory with respect to
// the starting disk number 8 bytes
$centralDirectoryOffset,
// zip64 end of central dir locator
// signature 4 bytes (0x07064b50)
ZipConstants::ZIP64_END_CD_LOC,
// number of the disk with the
// 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) .
// total number of disks 4 bytes
pack('V', 1)
0,
// relative offset of the zip64
// end of central directory record 8 bytes
$zip64EndOfCentralDirectoryOffset,
// total number of disks 4 bytes
1
)
);
}

View File

@ -1,25 +1,25 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Data;
use PhpZip\Exception\ZipException;
use PhpZip\Model\ZipData;
use PhpZip\Model\ZipEntry;
/**
* Class ZipFileData.
*/
class ZipFileData implements ZipData
{
/** @var \SplFileInfo */
private $file;
private \SplFileInfo $file;
/**
* ZipStringData constructor.
*
* @param ZipEntry $zipEntry
* @param \SplFileInfo $fileInfo
*
* @throws ZipException
*/
public function __construct(ZipEntry $zipEntry, \SplFileInfo $fileInfo)
@ -55,7 +55,7 @@ class ZipFileData implements ZipData
*
* @return string returns data as string
*/
public function getDataAsString()
public function getDataAsString(): string
{
if (!$this->file->isReadable()) {
throw new ZipException(sprintf('The %s file is no longer readable.', $this->file->getPathname()));
@ -69,7 +69,7 @@ class ZipFileData implements ZipData
*
* @throws ZipException
*/
public function copyDataToStream($outStream)
public function copyDataToStream($outStream): void
{
try {
$stream = $this->getDataAsStream();

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Data;
use PhpZip\Model\ZipData;
@ -17,19 +26,16 @@ class ZipNewData implements ZipData
*
* @var array<int, int> array of resource ids and the number of class clones
*/
private static $guardClonedStream = [];
private static array $guardClonedStream = [];
/** @var ZipEntry */
private $zipEntry;
private ZipEntry $zipEntry;
/** @var resource */
private $stream;
/**
* ZipStringData constructor.
*
* @param ZipEntry $zipEntry
* @param string|resource $data
* @param string|resource $data Raw string data or resource
* @noinspection PhpMissingParamTypeInspection
*/
public function __construct(ZipEntry $zipEntry, $data)
{
@ -51,10 +57,10 @@ 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;
}
/**
@ -72,7 +78,7 @@ class ZipNewData implements ZipData
/**
* @return string returns data as string
*/
public function getDataAsString()
public function getDataAsString(): string
{
$stream = $this->getDataAsStream();
$pos = ftell($stream);
@ -89,7 +95,7 @@ class ZipNewData implements ZipData
/**
* @param resource $outStream
*/
public function copyDataToStream($outStream)
public function copyDataToStream($outStream): void
{
$stream = $this->getDataAsStream();
rewind($stream);
@ -102,10 +108,10 @@ class ZipNewData implements ZipData
public function __clone()
{
$resourceId = (int) $this->stream;
self::$guardClonedStream[$resourceId] =
isset(self::$guardClonedStream[$resourceId]) ?
self::$guardClonedStream[$resourceId] + 1 :
1;
self::$guardClonedStream[$resourceId]
= isset(self::$guardClonedStream[$resourceId])
? self::$guardClonedStream[$resourceId] + 1
: 1;
}
/**

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Data;
use PhpZip\Exception\Crc32Exception;
@ -8,37 +17,22 @@ use PhpZip\IO\ZipReader;
use PhpZip\Model\ZipData;
use PhpZip\Model\ZipEntry;
/**
* Class ZipFileData.
*/
class ZipSourceFileData implements ZipData
{
/** @var ZipReader */
private $zipReader;
private ZipReader $zipReader;
/** @var resource|null */
private $stream;
/** @var ZipEntry */
private $sourceEntry;
private ZipEntry $sourceEntry;
/** @var int */
private $offset;
private int $offset;
/** @var int */
private $uncompressedSize;
private int $uncompressedSize;
/** @var int */
private $compressedSize;
private int $compressedSize;
/**
* ZipFileData constructor.
*
* @param ZipReader $zipReader
* @param ZipEntry $zipEntry
* @param int $offsetData
*/
public function __construct(ZipReader $zipReader, ZipEntry $zipEntry, $offsetData)
public function __construct(ZipReader $zipReader, ZipEntry $zipEntry, int $offsetData)
{
$this->zipReader = $zipReader;
$this->offset = $offsetData;
@ -47,21 +41,16 @@ class ZipSourceFileData implements ZipData
$this->uncompressedSize = $zipEntry->getUncompressedSize();
}
/**
* @param ZipEntry $entry
*
* @return bool
*/
public function hasRecompressData(ZipEntry $entry)
public function hasRecompressData(ZipEntry $entry): bool
{
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();
}
/**
@ -83,7 +72,7 @@ class ZipSourceFileData implements ZipData
*
* @return string returns data as string
*/
public function getDataAsString()
public function getDataAsString(): string
{
$autoClosable = $this->stream === null;
@ -105,64 +94,49 @@ class ZipSourceFileData implements ZipData
}
/**
* @param resource $outputStream Output stream
* @param resource $outStream Output stream
*
* @throws ZipException
* @throws Crc32Exception
*/
public function copyDataToStream($outputStream)
public function copyDataToStream($outStream): void
{
if (\is_resource($this->stream)) {
rewind($this->stream);
stream_copy_to_stream($this->stream, $outputStream);
stream_copy_to_stream($this->stream, $outStream);
} else {
$this->zipReader->copyUncompressedDataToStream($this, $outputStream);
$this->zipReader->copyUncompressedDataToStream($this, $outStream);
}
}
/**
* @param resource $outputStream Output stream
*/
public function copyCompressedDataToStream($outputStream)
public function copyCompressedDataToStream($outputStream): void
{
$this->zipReader->copyCompressedDataToStream($this, $outputStream);
}
/**
* @return ZipEntry
*/
public function getSourceEntry()
public function getSourceEntry(): ZipEntry
{
return $this->sourceEntry;
}
/**
* @return int
*/
public function getCompressedSize()
public function getCompressedSize(): int
{
return $this->compressedSize;
}
/**
* @return int
*/
public function getUncompressedSize()
public function getUncompressedSize(): int
{
return $this->uncompressedSize;
}
/**
* @return int
*/
public function getOffset()
public function getOffset(): int
{
return $this->offset;
}
/**
* {@inheritdoc}
*/
public function __destruct()
{
if (\is_resource($this->stream)) {

View File

@ -1,40 +1,36 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model;
/**
* End of Central Directory.
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*/
class EndOfCentralDirectory
{
/** @var int Count files. */
private $entryCount;
private int $entryCount;
/** @var int Central Directory Offset. */
private $cdOffset;
private int $cdOffset;
/** @var int */
private $cdSize;
private int $cdSize;
/** @var string|null The archive comment. */
private $comment;
private ?string $comment;
/** @var bool Zip64 extension */
private $zip64;
private bool $zip64;
/**
* EndOfCentralDirectory constructor.
*
* @param int $entryCount
* @param int $cdOffset
* @param int $cdSize
* @param bool $zip64
* @param string|null $comment
*/
public function __construct($entryCount, $cdOffset, $cdSize, $zip64, $comment = null)
public function __construct(int $entryCount, int $cdOffset, int $cdSize, bool $zip64, ?string $comment = null)
{
$this->entryCount = $entryCount;
$this->cdOffset = $cdOffset;
@ -43,50 +39,32 @@ class EndOfCentralDirectory
$this->comment = $comment;
}
/**
* @param string|null $comment
*/
public function setComment($comment)
public function setComment(?string $comment): void
{
$this->comment = $comment;
}
/**
* @return int
*/
public function getEntryCount()
public function getEntryCount(): int
{
return $this->entryCount;
}
/**
* @return int
*/
public function getCdOffset()
public function getCdOffset(): int
{
return $this->cdOffset;
}
/**
* @return int
*/
public function getCdSize()
public function getCdSize(): int
{
return $this->cdSize;
}
/**
* @return string|null
*/
public function getComment()
public function getComment(): ?string
{
return $this->comment;
}
/**
* @return bool
*/
public function isZip64()
public function isZip64(): bool
{
return $this->zip64;
}

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Extra;
/**
@ -16,14 +25,12 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator
*
* @var ZipExtraField[]
*/
protected $collection = [];
protected array $collection = [];
/**
* Returns the number of Extra Fields in this collection.
*
* @return int
*/
public function count()
public function count(): int
{
return \count($this->collection);
}
@ -37,17 +44,14 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator
* @return ZipExtraField|null the Extra Field with the given Header ID or
* if no such Extra Field exists
*/
public function get($headerId)
public function get(int $headerId): ?ZipExtraField
{
$this->validateHeaderId($headerId);
return isset($this->collection[$headerId]) ? $this->collection[$headerId] : null;
return $this->collection[$headerId] ?? null;
}
/**
* @param int $headerId
*/
private function validateHeaderId($headerId)
private function validateHeaderId(int $headerId): void
{
if ($headerId < 0 || $headerId > 0xffff) {
throw new \InvalidArgumentException('$headerId out of range');
@ -62,7 +66,7 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator
* @return ZipExtraField the Extra Field previously associated with the Header ID of
* of the given Extra Field or null if no such Extra Field existed
*/
public function add(ZipExtraField $extraField)
public function add(ZipExtraField $extraField): ZipExtraField
{
$headerId = $extraField->getHeaderId();
@ -75,7 +79,7 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator
/**
* @param ZipExtraField[] $extraFields
*/
public function addAll(array $extraFields)
public function addAll(array $extraFields): void
{
foreach ($extraFields as $extraField) {
$this->add($extraField);
@ -85,7 +89,7 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator
/**
* @param ExtraFieldsCollection $collection
*/
public function addCollection(self $collection)
public function addCollection(self $collection): void
{
$this->addAll($collection->collection);
}
@ -93,7 +97,7 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator
/**
* @return ZipExtraField[]
*/
public function getAll()
public function getAll(): array
{
return $this->collection;
}
@ -102,10 +106,8 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator
* Returns Extra Field exists.
*
* @param int $headerId the requested Header ID
*
* @return bool
*/
public function has($headerId)
public function has(int $headerId): bool
{
return isset($this->collection[$headerId]);
}
@ -118,7 +120,7 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator
* @return ZipExtraField|null the Extra Field with the given Header ID or null
* if no such Extra Field exists
*/
public function remove($headerId)
public function remove(int $headerId): ?ZipExtraField
{
$this->validateHeaderId($headerId);
@ -137,11 +139,11 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator
*
* @see http://php.net/manual/en/arrayaccess.offsetexists.php
*
* @param int $offset an offset to check for
* @param mixed $offset an offset to check for
*
* @return bool true on success or false on failure
*/
public function offsetExists($offset)
public function offsetExists($offset): bool
{
return isset($this->collection[(int) $offset]);
}
@ -151,13 +153,11 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator
*
* @see http://php.net/manual/en/arrayaccess.offsetget.php
*
* @param int $offset the offset to retrieve
*
* @return ZipExtraField|null
* @param mixed $offset the offset to retrieve
*/
public function offsetGet($offset)
public function offsetGet($offset): ?ZipExtraField
{
return isset($this->collection[$offset]) ? $this->collection[$offset] : null;
return $this->collection[(int) $offset] ?? null;
}
/**
@ -165,10 +165,10 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator
*
* @see http://php.net/manual/en/arrayaccess.offsetset.php
*
* @param mixed $offset the offset to assign the value to
* @param ZipExtraField $value the value to set
* @param mixed $offset the offset to assign the value to
* @param mixed $value the value to set
*/
public function offsetSet($offset, $value)
public function offsetSet($offset, $value): void
{
if (!$value instanceof ZipExtraField) {
throw new \InvalidArgumentException('value is not instanceof ' . ZipExtraField::class);
@ -183,7 +183,7 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator
*
* @param mixed $offset the offset to unset
*/
public function offsetUnset($offset)
public function offsetUnset($offset): void
{
$this->remove($offset);
}
@ -192,10 +192,8 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator
* Return the current element.
*
* @see http://php.net/manual/en/iterator.current.php
*
* @return ZipExtraField
*/
public function current()
public function current(): ZipExtraField
{
return current($this->collection);
}
@ -205,7 +203,7 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator
*
* @see http://php.net/manual/en/iterator.next.php
*/
public function next()
public function next(): void
{
next($this->collection);
}
@ -217,7 +215,7 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator
*
* @return int scalar on success, or null on failure
*/
public function key()
public function key(): int
{
return key($this->collection);
}
@ -230,7 +228,7 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator
* @return bool The return value will be casted to boolean and then evaluated.
* Returns true on success or false on failure.
*/
public function valid()
public function valid(): bool
{
return key($this->collection) !== null;
}
@ -240,20 +238,17 @@ class ExtraFieldsCollection implements \ArrayAccess, \Countable, \Iterator
*
* @see http://php.net/manual/en/iterator.rewind.php
*/
public function rewind()
public function rewind(): void
{
reset($this->collection);
}
public function clear()
public function clear(): void
{
$this->collection = [];
}
/**
* @return string
*/
public function __toString()
public function __toString(): string
{
$formats = [];

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Extra\Fields;
use PhpZip\Exception\ZipException;
@ -11,45 +20,33 @@ use PhpZip\Model\ZipEntry;
*/
abstract class AbstractUnicodeExtraField implements ZipExtraField
{
const DEFAULT_VERSION = 0x01;
public const DEFAULT_VERSION = 0x01;
/** @var int */
private $crc32;
private int $crc32;
/** @var string */
private $unicodeValue;
private string $unicodeValue;
/**
* @param int $crc32
* @param string $unicodeValue
*/
public function __construct($crc32, $unicodeValue)
public function __construct(int $crc32, string $unicodeValue)
{
$this->crc32 = (int) $crc32;
$this->unicodeValue = (string) $unicodeValue;
$this->crc32 = $crc32;
$this->unicodeValue = $unicodeValue;
}
/**
* @return int the CRC32 checksum of the filename or comment as
* encoded in the central directory of the zip file
*/
public function getCrc32()
public function getCrc32(): int
{
return $this->crc32;
}
/**
* @param int $crc32
*/
public function setCrc32($crc32)
public function setCrc32(int $crc32): void
{
$this->crc32 = (int) $crc32;
$this->crc32 = $crc32;
}
/**
* @return string
*/
public function getUnicodeValue()
public function getUnicodeValue(): string
{
return $this->unicodeValue;
}
@ -57,7 +54,7 @@ abstract class AbstractUnicodeExtraField implements ZipExtraField
/**
* @param string $unicodeValue the UTF-8 encoded name to set
*/
public function setUnicodeValue($unicodeValue)
public function setUnicodeValue(string $unicodeValue): void
{
$this->unicodeValue = $unicodeValue;
}
@ -65,41 +62,44 @@ abstract class AbstractUnicodeExtraField implements ZipExtraField
/**
* Populate data from this array as if it was in local file data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @throws ZipException on error
*
* @return static
*/
public static function unpackLocalFileData($buffer, ZipEntry $entry = null)
public static function unpackLocalFileData(string $buffer, ?ZipEntry $entry = null): self
{
if (\strlen($buffer) < 5) {
throw new ZipException('Unicode path extra data must have at least 5 bytes.');
}
$data = unpack('Cversion/Vcrc32', $buffer);
[
'version' => $version,
'crc32' => $crc32,
] = unpack('Cversion/Vcrc32', $buffer);
if ($data['version'] !== self::DEFAULT_VERSION) {
throw new ZipException(sprintf('Unsupported version [%d] for Unicode path extra data.', $data['version']));
if ($version !== self::DEFAULT_VERSION) {
throw new ZipException(sprintf('Unsupported version [%d] for Unicode path extra data.', $version));
}
$unicodeValue = substr($buffer, 5);
return new static($data['crc32'], $unicodeValue);
return new static($crc32, $unicodeValue);
}
/**
* Populate data from this array as if it was in central directory data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @throws ZipException on error
*
* @return static
*/
public static function unpackCentralDirData($buffer, ZipEntry $entry = null)
public static function unpackCentralDirData(string $buffer, ?ZipEntry $entry = null): self
{
return self::unpackLocalFileData($buffer, $entry);
}
@ -110,14 +110,14 @@ abstract class AbstractUnicodeExtraField implements ZipExtraField
*
* @return string the data
*/
public function packLocalFileData()
public function packLocalFileData(): string
{
return pack(
'CV',
self::DEFAULT_VERSION,
$this->crc32
) .
$this->unicodeValue;
)
. $this->unicodeValue;
}
/**
@ -126,7 +126,7 @@ abstract class AbstractUnicodeExtraField implements ZipExtraField
*
* @return string the data
*/
public function packCentralDirData()
public function packCentralDirData(): string
{
return $this->packLocalFileData();
}

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Extra\Fields;
use PhpZip\Exception\ZipException;
@ -20,31 +29,25 @@ class ApkAlignmentExtraField implements ZipExtraField
* well as for aligning the entries's data. See ZIP
* appnote.txt section 4.5 Extensible data fields.
*/
const HEADER_ID = 0xd935;
public const HEADER_ID = 0xd935;
/**
* @var int minimum size (in bytes) of the extensible data block/field used
* for alignment of uncompressed entries
*/
const MIN_SIZE = 6;
public const MIN_SIZE = 6;
/** @var int */
const ALIGNMENT_BYTES = 4;
public const ALIGNMENT_BYTES = 4;
/** @var int */
const COMMON_PAGE_ALIGNMENT_BYTES = 4096;
public const COMMON_PAGE_ALIGNMENT_BYTES = 4096;
/** @var int */
private $multiple;
private int $multiple;
/** @var int */
private $padding;
private int $padding;
/**
* @param int $multiple
* @param int $padding
*/
public function __construct($multiple, $padding)
public function __construct(int $multiple, int $padding)
{
$this->multiple = $multiple;
$this->padding = $padding;
@ -54,57 +57,43 @@ class ApkAlignmentExtraField implements ZipExtraField
* 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()
public function getHeaderId(): int
{
return self::HEADER_ID;
}
/**
* @return int
*/
public function getMultiple()
public function getMultiple(): int
{
return $this->multiple;
}
/**
* @return int
*/
public function getPadding()
public function getPadding(): int
{
return $this->padding;
}
/**
* @param int $multiple
*/
public function setMultiple($multiple)
public function setMultiple(int $multiple): void
{
$this->multiple = (int) $multiple;
$this->multiple = $multiple;
}
/**
* @param int $padding
*/
public function setPadding($padding)
public function setPadding(int $padding): void
{
$this->padding = (int) $padding;
$this->padding = $padding;
}
/**
* Populate data from this array as if it was in local file data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @throws ZipException
*
* @return ApkAlignmentExtraField
*/
public static function unpackLocalFileData($buffer, ZipEntry $entry = null)
public static function unpackLocalFileData(string $buffer, ?ZipEntry $entry = null): self
{
$length = \strlen($buffer);
@ -127,14 +116,14 @@ class ApkAlignmentExtraField implements ZipExtraField
/**
* Populate data from this array as if it was in central directory data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @throws ZipException on error
*
* @return ApkAlignmentExtraField
*/
public static function unpackCentralDirData($buffer, ZipEntry $entry = null)
public static function unpackCentralDirData(string $buffer, ?ZipEntry $entry = null): self
{
return self::unpackLocalFileData($buffer, $entry);
}
@ -145,7 +134,7 @@ class ApkAlignmentExtraField implements ZipExtraField
*
* @return string the data
*/
public function packLocalFileData()
public function packLocalFileData(): string
{
return pack('vx' . $this->padding, $this->multiple);
}
@ -156,15 +145,12 @@ class ApkAlignmentExtraField implements ZipExtraField
*
* @return string the data
*/
public function packCentralDirData()
public function packCentralDirData(): string
{
return $this->packLocalFileData();
}
/**
* @return string
*/
public function __toString()
public function __toString(): string
{
return sprintf(
'0x%04x APK Alignment: Multiple=%d Padding=%d',

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Extra\Fields;
use PhpZip\Constants\UnixStat;
@ -47,37 +56,29 @@ use PhpZip\Model\ZipEntry;
class AsiExtraField implements ZipExtraField
{
/** @var int Header id */
const HEADER_ID = 0x756e;
public const HEADER_ID = 0x756e;
const USER_GID_PID = 1000;
public const USER_GID_PID = 1000;
/** Bits used for permissions (and sticky bit). */
const PERM_MASK = 07777;
public const PERM_MASK = 07777;
/** @var int Standard Unix stat(2) file mode. */
private $mode;
private int $mode;
/** @var int User ID. */
private $uid;
private int $uid;
/** @var int Group ID. */
private $gid;
private int $gid;
/**
* @var string File this entry points to, if it is a symbolic link.
* Empty string - if entry is not a symbolic link.
*/
private $link;
private string $link;
/**
* AsiExtraField constructor.
*
* @param int $mode
* @param int $uid
* @param int $gid
* @param string $link
*/
public function __construct($mode, $uid = self::USER_GID_PID, $gid = self::USER_GID_PID, $link = '')
public function __construct(int $mode, int $uid = self::USER_GID_PID, int $gid = self::USER_GID_PID, string $link = '')
{
$this->mode = $mode;
$this->uid = $uid;
@ -89,10 +90,8 @@ class AsiExtraField implements ZipExtraField
* 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()
public function getHeaderId(): int
{
return self::HEADER_ID;
}
@ -100,14 +99,14 @@ class AsiExtraField implements ZipExtraField
/**
* Populate data from this array as if it was in local file data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @throws Crc32Exception
*
* @return static
*/
public static function unpackLocalFileData($buffer, ZipEntry $entry = null)
public static function unpackLocalFileData(string $buffer, ?ZipEntry $entry = null): self
{
$givenChecksum = unpack('V', $buffer)[1];
$buffer = substr($buffer, 4);
@ -117,27 +116,32 @@ class AsiExtraField implements ZipExtraField
throw new Crc32Exception('Asi Unix Extra Filed Data', $givenChecksum, $realChecksum);
}
$data = unpack('vmode/VlinkSize/vuid/vgid', $buffer);
[
'mode' => $mode,
'linkSize' => $linkSize,
'uid' => $uid,
'gid' => $gid,
] = unpack('vmode/VlinkSize/vuid/vgid', $buffer);
$link = '';
if ($data['linkSize'] > 0) {
if ($linkSize > 0) {
$link = substr($buffer, 10);
}
return new self($data['mode'], $data['uid'], $data['gid'], $link);
return new self($mode, $uid, $gid, $link);
}
/**
* Populate data from this array as if it was in central directory data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @throws Crc32Exception
*
* @return AsiExtraField
*/
public static function unpackCentralDirData($buffer, ZipEntry $entry = null)
public static function unpackCentralDirData(string $buffer, ?ZipEntry $entry = null): self
{
return self::unpackLocalFileData($buffer, $entry);
}
@ -148,7 +152,7 @@ class AsiExtraField implements ZipExtraField
*
* @return string the data
*/
public function packLocalFileData()
public function packLocalFileData(): string
{
$data = pack(
'vVvv',
@ -167,7 +171,7 @@ class AsiExtraField implements ZipExtraField
*
* @return string the data
*/
public function packCentralDirData()
public function packCentralDirData(): string
{
return $this->packLocalFileData();
}
@ -178,7 +182,7 @@ class AsiExtraField implements ZipExtraField
* @return string name of the file this entry links to if it is a
* symbolic link, the empty string otherwise
*/
public function getLink()
public function getLink(): string
{
return $this->link;
}
@ -189,9 +193,9 @@ class AsiExtraField implements ZipExtraField
* @param string $link name of the file this entry links to, empty
* string if it is not a symbolic link
*/
public function setLink($link)
public function setLink(string $link): void
{
$this->link = (string) $link;
$this->link = $link;
$this->mode = $this->getPermissionsMode($this->mode);
}
@ -200,7 +204,7 @@ class AsiExtraField implements ZipExtraField
*
* @return bool true if this is a symbolic link
*/
public function isLink()
public function isLink(): bool
{
return !empty($this->link);
}
@ -212,7 +216,7 @@ class AsiExtraField implements ZipExtraField
*
* @return int the type with the mode
*/
protected function getPermissionsMode($mode)
protected function getPermissionsMode(int $mode): int
{
$type = 0;
@ -232,63 +236,42 @@ class AsiExtraField implements ZipExtraField
*
* @return bool true if this entry is a directory
*/
public function isDirectory()
public function isDirectory(): bool
{
return ($this->mode & UnixStat::UNX_IFDIR) !== 0 && !$this->isLink();
}
/**
* @return int
*/
public function getMode()
public function getMode(): int
{
return $this->mode;
}
/**
* @param int $mode
*/
public function setMode($mode)
public function setMode(int $mode): void
{
$this->mode = $this->getPermissionsMode($mode);
}
/**
* @return int
*/
public function getUserId()
public function getUserId(): int
{
return $this->uid;
}
/**
* @param int $uid
*/
public function setUserId($uid)
public function setUserId(int $uid): void
{
$this->uid = (int) $uid;
$this->uid = $uid;
}
/**
* @return int
*/
public function getGroupId()
public function getGroupId(): int
{
return $this->gid;
}
/**
* @param int $gid
*/
public function setGroupId($gid)
public function setGroupId(int $gid): void
{
$this->gid = (int) $gid;
$this->gid = $gid;
}
/**
* @return string
*/
public function __toString()
public function __toString(): string
{
return sprintf(
'0x%04x ASI: Mode=%o UID=%d GID=%d Link="%s',

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Extra\Fields;
use PhpZip\Model\Extra\ZipExtraField;
@ -67,78 +76,69 @@ use PhpZip\Model\ZipEntry;
class ExtendedTimestampExtraField implements ZipExtraField
{
/** @var int Header id */
const HEADER_ID = 0x5455;
public const HEADER_ID = 0x5455;
/**
* @var int the bit set inside the flags by when the last modification time
* is present in this extra field
*/
const MODIFY_TIME_BIT = 1;
public const MODIFY_TIME_BIT = 1;
/**
* @var int the bit set inside the flags by when the last access time is
* present in this extra field
*/
const ACCESS_TIME_BIT = 2;
public const ACCESS_TIME_BIT = 2;
/**
* @var int the bit set inside the flags by when the original creation time
* is present in this extra field
*/
const CREATE_TIME_BIT = 4;
public const CREATE_TIME_BIT = 4;
/**
* @var int The 3 boolean fields (below) come from this flags byte. The remaining 5 bits
* are ignored according to the current version of the spec (December 2012).
*/
private $flags;
private int $flags;
/** @var int|null Modify time */
private $modifyTime;
private ?int $modifyTime;
/** @var int|null Access time */
private $accessTime;
private ?int $accessTime;
/** @var int|null Create time */
private $createTime;
private ?int $createTime;
/**
* @param int $flags
* @param int|null $modifyTime
* @param int|null $accessTime
* @param int|null $createTime
*/
public function __construct($flags, $modifyTime, $accessTime, $createTime)
public function __construct(int $flags, ?int $modifyTime, ?int $accessTime, ?int $createTime)
{
$this->flags = (int) $flags;
$this->flags = $flags;
$this->modifyTime = $modifyTime;
$this->accessTime = $accessTime;
$this->createTime = $createTime;
}
/**
* @param int|null $modifyTime
* @param int|null $accessTime
* @param int|null $createTime
* @param ?int $modifyTime
* @param ?int $accessTime
* @param ?int $createTime
*
* @return ExtendedTimestampExtraField
*/
public static function create($modifyTime, $accessTime, $createTime)
public static function create(?int $modifyTime, ?int $accessTime, ?int $createTime): self
{
$flags = 0;
if ($modifyTime !== null) {
$modifyTime = (int) $modifyTime;
$flags |= self::MODIFY_TIME_BIT;
}
if ($accessTime !== null) {
$accessTime = (int) $accessTime;
$flags |= self::ACCESS_TIME_BIT;
}
if ($createTime !== null) {
$createTime = (int) $createTime;
$flags |= self::CREATE_TIME_BIT;
}
@ -149,10 +149,8 @@ class ExtendedTimestampExtraField implements ZipExtraField
* 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()
public function getHeaderId(): int
{
return self::HEADER_ID;
}
@ -160,12 +158,12 @@ class ExtendedTimestampExtraField implements ZipExtraField
/**
* Populate data from this array as if it was in local file data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @return ExtendedTimestampExtraField
*/
public static function unpackLocalFileData($buffer, ZipEntry $entry = null)
public static function unpackLocalFileData(string $buffer, ?ZipEntry $entry = null): self
{
$length = \strlen($buffer);
$flags = unpack('C', $buffer)[1];
@ -197,12 +195,12 @@ class ExtendedTimestampExtraField implements ZipExtraField
/**
* Populate data from this array as if it was in central directory data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @return ExtendedTimestampExtraField
*/
public static function unpackCentralDirData($buffer, ZipEntry $entry = null)
public static function unpackCentralDirData(string $buffer, ?ZipEntry $entry = null): self
{
return self::unpackLocalFileData($buffer, $entry);
}
@ -213,7 +211,7 @@ class ExtendedTimestampExtraField implements ZipExtraField
*
* @return string the data
*/
public function packLocalFileData()
public function packLocalFileData(): string
{
$data = '';
@ -241,7 +239,7 @@ class ExtendedTimestampExtraField implements ZipExtraField
*
* @return string the data
*/
public function packCentralDirData()
public function packCentralDirData(): string
{
$cdLength = 1 + ($this->modifyTime !== null ? 4 : 0);
@ -263,7 +261,7 @@ class ExtendedTimestampExtraField implements ZipExtraField
* @return int flags byte indicating which of the
* three datestamp fields are present
*/
public function getFlags()
public function getFlags(): int
{
return $this->flags;
}
@ -274,7 +272,7 @@ class ExtendedTimestampExtraField implements ZipExtraField
*
* @return int|null modify time (seconds since epoch) or null
*/
public function getModifyTime()
public function getModifyTime(): ?int
{
return $this->modifyTime;
}
@ -285,7 +283,7 @@ class ExtendedTimestampExtraField implements ZipExtraField
*
* @return int|null access time (seconds since epoch) or null
*/
public function getAccessTime()
public function getAccessTime(): ?int
{
return $this->accessTime;
}
@ -301,7 +299,7 @@ class ExtendedTimestampExtraField implements ZipExtraField
*
* @return int|null create time (seconds since epoch) or null
*/
public function getCreateTime()
public function getCreateTime(): ?int
{
return $this->createTime;
}
@ -314,7 +312,7 @@ class ExtendedTimestampExtraField implements ZipExtraField
*
* @return \DateTimeInterface|null modify time as \DateTimeInterface or null
*/
public function getModifyDateTime()
public function getModifyDateTime(): ?\DateTimeInterface
{
return self::timestampToDateTime($this->modifyTime);
}
@ -327,7 +325,7 @@ class ExtendedTimestampExtraField implements ZipExtraField
*
* @return \DateTimeInterface|null access time as \DateTimeInterface or null
*/
public function getAccessDateTime()
public function getAccessDateTime(): ?\DateTimeInterface
{
return self::timestampToDateTime($this->accessTime);
}
@ -345,7 +343,7 @@ class ExtendedTimestampExtraField implements ZipExtraField
*
* @return \DateTimeInterface|null create time as \DateTimeInterface or null
*/
public function getCreateDateTime()
public function getCreateDateTime(): ?\DateTimeInterface
{
return self::timestampToDateTime($this->createTime);
}
@ -356,13 +354,13 @@ class ExtendedTimestampExtraField implements ZipExtraField
*
* @param int|null $unixTime unix time of the modify time (seconds per epoch) or null
*/
public function setModifyTime($unixTime)
public function setModifyTime(?int $unixTime): void
{
$this->modifyTime = $unixTime;
$this->updateFlags();
}
private function updateFlags()
private function updateFlags(): void
{
$flags = 0;
@ -386,7 +384,7 @@ class ExtendedTimestampExtraField implements ZipExtraField
*
* @param int|null $unixTime Unix time of the access time (seconds per epoch) or null
*/
public function setAccessTime($unixTime)
public function setAccessTime(?int $unixTime): void
{
$this->accessTime = $unixTime;
$this->updateFlags();
@ -398,18 +396,13 @@ class ExtendedTimestampExtraField implements ZipExtraField
*
* @param int|null $unixTime Unix time of the create time (seconds per epoch) or null
*/
public function setCreateTime($unixTime)
public function setCreateTime(?int $unixTime): void
{
$this->createTime = $unixTime;
$this->updateFlags();
}
/**
* @param int|null $timestamp
*
* @return \DateTimeInterface|null
*/
private static function timestampToDateTime($timestamp)
private static function timestampToDateTime(?int $timestamp): ?\DateTimeInterface
{
try {
return $timestamp !== null ? new \DateTimeImmutable('@' . $timestamp) : null;
@ -418,10 +411,7 @@ class ExtendedTimestampExtraField implements ZipExtraField
}
}
/**
* @return string
*/
public function __toString()
public function __toString(): string
{
$args = [self::HEADER_ID];
$format = '0x%04x ExtendedTimestamp:';

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Extra\Fields;
use PhpZip\Exception\ZipException;
@ -14,18 +23,13 @@ use PhpZip\Model\ZipEntry;
* by the extra field in the first file, which is hexadecimal in the 0xCAFE bytes series.
* If this extra field is added as the very first extra field of
* the archive, Solaris will consider it an executable jar file.
*
* @license MIT
*/
class JarMarkerExtraField implements ZipExtraField
{
/** @var int Header id. */
const HEADER_ID = 0xCAFE;
public const HEADER_ID = 0xCAFE;
/**
* @param ZipContainer $container
*/
public static function setJarMarker(ZipContainer $container)
public static function setJarMarker(ZipContainer $container): void
{
$zipEntries = $container->getEntries();
@ -44,10 +48,8 @@ class JarMarkerExtraField implements ZipExtraField
* 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()
public function getHeaderId(): int
{
return self::HEADER_ID;
}
@ -58,7 +60,7 @@ class JarMarkerExtraField implements ZipExtraField
*
* @return string the data
*/
public function packLocalFileData()
public function packLocalFileData(): string
{
return '';
}
@ -69,7 +71,7 @@ class JarMarkerExtraField implements ZipExtraField
*
* @return string the data
*/
public function packCentralDirData()
public function packCentralDirData(): string
{
return '';
}
@ -77,14 +79,14 @@ class JarMarkerExtraField implements ZipExtraField
/**
* Populate data from this array as if it was in local file data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @throws ZipException on error
*
* @return JarMarkerExtraField
*/
public static function unpackLocalFileData($buffer, ZipEntry $entry = null)
public static function unpackLocalFileData(string $buffer, ?ZipEntry $entry = null): self
{
if (!empty($buffer)) {
throw new ZipException("JarMarker doesn't expect any data");
@ -96,22 +98,19 @@ class JarMarkerExtraField implements ZipExtraField
/**
* Populate data from this array as if it was in central directory data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @throws ZipException on error
*
* @return JarMarkerExtraField
*/
public static function unpackCentralDirData($buffer, ZipEntry $entry = null)
public static function unpackCentralDirData(string $buffer, ?ZipEntry $entry = null): self
{
return self::unpackLocalFileData($buffer, $entry);
}
/**
* @return string
*/
public function __toString()
public function __toString(): string
{
return sprintf('0x%04x Jar Marker', self::HEADER_ID);
}

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Extra\Fields;
use PhpZip\Exception\ZipException;
@ -45,42 +54,33 @@ use PhpZip\Model\ZipEntry;
class NewUnixExtraField implements ZipExtraField
{
/** @var int header id */
const HEADER_ID = 0x7875;
public const HEADER_ID = 0x7875;
/** ID of the first non-root user created on a unix system. */
const USER_GID_PID = 1000;
public const USER_GID_PID = 1000;
/** @var int version of this extra field, currently 1 */
private $version = 1;
private int $version;
/** @var int User id */
private $uid;
private int $uid;
/** @var int Group id */
private $gid;
private int $gid;
/**
* NewUnixExtraField constructor.
*
* @param int $version
* @param int $uid
* @param int $gid
*/
public function __construct($version = 1, $uid = self::USER_GID_PID, $gid = self::USER_GID_PID)
public function __construct(int $version = 1, int $uid = self::USER_GID_PID, int $gid = self::USER_GID_PID)
{
$this->version = (int) $version;
$this->uid = (int) $uid;
$this->gid = (int) $gid;
$this->version = $version;
$this->uid = $uid;
$this->gid = $gid;
}
/**
* 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()
public function getHeaderId(): int
{
return self::HEADER_ID;
}
@ -88,14 +88,14 @@ class NewUnixExtraField implements ZipExtraField
/**
* Populate data from this array as if it was in local file data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @throws ZipException
*
* @return NewUnixExtraField
*/
public static function unpackLocalFileData($buffer, ZipEntry $entry = null)
public static function unpackLocalFileData(string $buffer, ?ZipEntry $entry = null): self
{
$length = \strlen($buffer);
@ -103,29 +103,31 @@ class NewUnixExtraField implements ZipExtraField
throw new ZipException(sprintf('X7875_NewUnix length is too short, only %s bytes', $length));
}
$offset = 0;
$data = unpack('Cversion/CuidSize', $buffer);
[
'version' => $version,
'uidSize' => $uidSize,
] = unpack('Cversion/CuidSize', $buffer);
$offset += 2;
$uidSize = $data['uidSize'];
$gid = self::readSizeIntegerLE(substr($buffer, $offset, $uidSize), $uidSize);
$offset += $uidSize;
$gidSize = unpack('C', $buffer[$offset])[1];
$offset++;
$uid = self::readSizeIntegerLE(substr($buffer, $offset, $gidSize), $gidSize);
return new self($data['version'], $gid, $uid);
return new self($version, $gid, $uid);
}
/**
* Populate data from this array as if it was in central directory data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @throws ZipException
*
* @return NewUnixExtraField
*/
public static function unpackCentralDirData($buffer, ZipEntry $entry = null)
public static function unpackCentralDirData(string $buffer, ?ZipEntry $entry = null): self
{
return self::unpackLocalFileData($buffer, $entry);
}
@ -136,7 +138,7 @@ class NewUnixExtraField implements ZipExtraField
*
* @return string the data
*/
public function packLocalFileData()
public function packLocalFileData(): string
{
return pack(
'CCVCV',
@ -154,20 +156,15 @@ class NewUnixExtraField implements ZipExtraField
*
* @return string the data
*/
public function packCentralDirData()
public function packCentralDirData(): string
{
return $this->packLocalFileData();
}
/**
* @param string $data
* @param int $size
*
* @throws ZipException
*
* @return int
*/
private static function readSizeIntegerLE($data, $size)
private static function readSizeIntegerLE(string $data, int $size): int
{
$format = [
1 => 'C', // unsigned byte
@ -182,50 +179,32 @@ class NewUnixExtraField implements ZipExtraField
return unpack($format[$size], $data)[1];
}
/**
* @return int
*/
public function getUid()
public function getUid(): int
{
return $this->uid;
}
/**
* @param int $uid
*/
public function setUid($uid)
public function setUid(int $uid): void
{
$this->uid = $uid & 0xffffffff;
}
/**
* @return int
*/
public function getGid()
public function getGid(): int
{
return $this->gid;
}
/**
* @param int $gid
*/
public function setGid($gid)
public function setGid(int $gid): void
{
$this->gid = $gid & 0xffffffff;
}
/**
* @return int
*/
public function getVersion()
public function getVersion(): int
{
return $this->version;
}
/**
* @return string
*/
public function __toString()
public function __toString(): string
{
return sprintf(
'0x%04x NewUnix: UID=%d GID=%d',

View File

@ -1,30 +1,36 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Extra\Fields;
use PhpZip\Exception\InvalidArgumentException;
use PhpZip\Exception\ZipException;
use PhpZip\Model\Extra\ZipExtraField;
use PhpZip\Model\ZipEntry;
use PhpZip\Util\PackUtil;
/**
* NTFS Extra Field.
*
* @see https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT .ZIP File Format Specification
*
* @license MIT
*/
class NtfsExtraField implements ZipExtraField
{
/** @var int Header id */
const HEADER_ID = 0x000a;
public const HEADER_ID = 0x000a;
/** @var int Tag ID */
const TIME_ATTR_TAG = 0x0001;
public const TIME_ATTR_TAG = 0x0001;
/** @var int Attribute size */
const TIME_ATTR_SIZE = 24; // 3 * 8
public const TIME_ATTR_SIZE = 24; // 3 * 8
/**
* @var int A file time is a 64-bit value that represents the number of
@ -32,41 +38,32 @@ class NtfsExtraField implements ZipExtraField
* A.M. January 1, 1601 Coordinated Universal Time (UTC).
* this is the offset of Windows time 0 to Unix epoch in 100-nanosecond intervals.
*/
const EPOCH_OFFSET = -116444736000000000;
public const EPOCH_OFFSET = -116444736000000000;
/** @var int Modify ntfs time */
private $modifyNtfsTime;
private int $modifyNtfsTime;
/** @var int Access ntfs time */
private $accessNtfsTime;
private int $accessNtfsTime;
/** @var int Create ntfs time */
private $createNtfsTime;
private int $createNtfsTime;
/**
* @param int $modifyNtfsTime
* @param int $accessNtfsTime
* @param int $createNtfsTime
*/
public function __construct($modifyNtfsTime, $accessNtfsTime, $createNtfsTime)
public function __construct(int $modifyNtfsTime, int $accessNtfsTime, int $createNtfsTime)
{
$this->modifyNtfsTime = (int) $modifyNtfsTime;
$this->accessNtfsTime = (int) $accessNtfsTime;
$this->createNtfsTime = (int) $createNtfsTime;
$this->modifyNtfsTime = $modifyNtfsTime;
$this->accessNtfsTime = $accessNtfsTime;
$this->createNtfsTime = $createNtfsTime;
}
/**
* @param \DateTimeInterface $modifyDateTime
* @param \DateTimeInterface $accessDateTime
* @param \DateTimeInterface $createNtfsTime
*
* @return NtfsExtraField
*/
public static function create(
\DateTimeInterface $modifyDateTime,
\DateTimeInterface $accessDateTime,
\DateTimeInterface $createNtfsTime
) {
): self {
return new self(
self::dateTimeToNtfsTime($modifyDateTime),
self::dateTimeToNtfsTime($accessDateTime),
@ -78,10 +75,8 @@ class NtfsExtraField implements ZipExtraField
* 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()
public function getHeaderId(): int
{
return self::HEADER_ID;
}
@ -89,14 +84,14 @@ class NtfsExtraField implements ZipExtraField
/**
* Populate data from this array as if it was in local file data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @throws ZipException
*
* @return NtfsExtraField
*/
public static function unpackLocalFileData($buffer, ZipEntry $entry = null)
public static function unpackLocalFileData(string $buffer, ?ZipEntry $entry = null): self
{
if (\PHP_INT_SIZE === 4) {
throw new ZipException('not supported for php-32bit');
@ -109,17 +104,21 @@ class NtfsExtraField implements ZipExtraField
$createTime = 0;
while ($buffer || $buffer !== '') {
$unpack = unpack('vtag/vsizeAttr', $buffer);
[
'tag' => $tag,
'sizeAttr' => $sizeAttr,
] = unpack('vtag/vsizeAttr', $buffer);
if ($unpack['tag'] === self::TIME_ATTR_TAG && $unpack['sizeAttr'] === self::TIME_ATTR_SIZE) {
// refactoring will be needed when php 5.5 support ends
$modifyTime = PackUtil::unpackLongLE(substr($buffer, 4, 8));
$accessTime = PackUtil::unpackLongLE(substr($buffer, 12, 8));
$createTime = PackUtil::unpackLongLE(substr($buffer, 20, 8));
if ($tag === self::TIME_ATTR_TAG && $sizeAttr === self::TIME_ATTR_SIZE) {
[
'modifyTime' => $modifyTime,
'accessTime' => $accessTime,
'createTime' => $createTime,
] = unpack('PmodifyTime/PaccessTime/PcreateTime', substr($buffer, 4, 24));
break;
}
$buffer = substr($buffer, 4 + $unpack['sizeAttr']);
$buffer = substr($buffer, 4 + $sizeAttr);
}
return new self($modifyTime, $accessTime, $createTime);
@ -128,14 +127,14 @@ class NtfsExtraField implements ZipExtraField
/**
* Populate data from this array as if it was in central directory data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @throws ZipException
*
* @return NtfsExtraField
*/
public static function unpackCentralDirData($buffer, ZipEntry $entry = null)
public static function unpackCentralDirData(string $buffer, ?ZipEntry $entry = null): self
{
return self::unpackLocalFileData($buffer, $entry);
}
@ -146,63 +145,47 @@ class NtfsExtraField implements ZipExtraField
*
* @return string the data
*/
public function packLocalFileData()
public function packLocalFileData(): string
{
$data = pack('Vvv', 0, self::TIME_ATTR_TAG, self::TIME_ATTR_SIZE);
// refactoring will be needed when php 5.5 support ends
$data .= PackUtil::packLongLE($this->modifyNtfsTime);
$data .= PackUtil::packLongLE($this->accessNtfsTime);
$data .= PackUtil::packLongLE($this->createNtfsTime);
return $data;
return pack(
'VvvPPP',
0,
self::TIME_ATTR_TAG,
self::TIME_ATTR_SIZE,
$this->modifyNtfsTime,
$this->accessNtfsTime,
$this->createNtfsTime
);
}
/**
* @return int
*/
public function getModifyNtfsTime()
public function getModifyNtfsTime(): int
{
return $this->modifyNtfsTime;
}
/**
* @param int $modifyNtfsTime
*/
public function setModifyNtfsTime($modifyNtfsTime)
public function setModifyNtfsTime(int $modifyNtfsTime): void
{
$this->modifyNtfsTime = (int) $modifyNtfsTime;
$this->modifyNtfsTime = $modifyNtfsTime;
}
/**
* @return int
*/
public function getAccessNtfsTime()
public function getAccessNtfsTime(): int
{
return $this->accessNtfsTime;
}
/**
* @param int $accessNtfsTime
*/
public function setAccessNtfsTime($accessNtfsTime)
public function setAccessNtfsTime(int $accessNtfsTime): void
{
$this->accessNtfsTime = (int) $accessNtfsTime;
$this->accessNtfsTime = $accessNtfsTime;
}
/**
* @return int
*/
public function getCreateNtfsTime()
public function getCreateNtfsTime(): int
{
return $this->createNtfsTime;
}
/**
* @param int $createNtfsTime
*/
public function setCreateNtfsTime($createNtfsTime)
public function setCreateNtfsTime(int $createNtfsTime): void
{
$this->createNtfsTime = (int) $createNtfsTime;
$this->createNtfsTime = $createNtfsTime;
}
/**
@ -211,95 +194,63 @@ class NtfsExtraField implements ZipExtraField
*
* @return string the data
*/
public function packCentralDirData()
public function packCentralDirData(): string
{
return $this->packLocalFileData();
}
/**
* @return \DateTimeInterface
*/
public function getModifyDateTime()
public function getModifyDateTime(): \DateTimeInterface
{
return self::ntfsTimeToDateTime($this->modifyNtfsTime);
}
/**
* @param \DateTimeInterface $modifyTime
*/
public function setModifyDateTime(\DateTimeInterface $modifyTime)
public function setModifyDateTime(\DateTimeInterface $modifyTime): void
{
$this->modifyNtfsTime = self::dateTimeToNtfsTime($modifyTime);
}
/**
* @return \DateTimeInterface
*/
public function getAccessDateTime()
public function getAccessDateTime(): \DateTimeInterface
{
return self::ntfsTimeToDateTime($this->accessNtfsTime);
}
/**
* @param \DateTimeInterface $accessTime
*/
public function setAccessDateTime(\DateTimeInterface $accessTime)
public function setAccessDateTime(\DateTimeInterface $accessTime): void
{
$this->accessNtfsTime = self::dateTimeToNtfsTime($accessTime);
}
/**
* @return \DateTimeInterface
*/
public function getCreateDateTime()
public function getCreateDateTime(): \DateTimeInterface
{
return self::ntfsTimeToDateTime($this->createNtfsTime);
}
/**
* @param \DateTimeInterface $createTime
*/
public function setCreateDateTime(\DateTimeInterface $createTime)
public function setCreateDateTime(\DateTimeInterface $createTime): void
{
$this->createNtfsTime = self::dateTimeToNtfsTime($createTime);
}
/**
* @param float $timestamp Float timestamp
*
* @return int
*/
public static function timestampToNtfsTime($timestamp)
public static function timestampToNtfsTime(float $timestamp): int
{
return (int) (((float) $timestamp * 10000000) - self::EPOCH_OFFSET);
return (int) (($timestamp * 10000000) - self::EPOCH_OFFSET);
}
/**
* @param \DateTimeInterface $dateTime
*
* @return int
*/
public static function dateTimeToNtfsTime(\DateTimeInterface $dateTime)
public static function dateTimeToNtfsTime(\DateTimeInterface $dateTime): int
{
return self::timestampToNtfsTime((float) $dateTime->format('U.u'));
}
/**
* @param int $ntfsTime
*
* @return float Float unix timestamp
*/
public static function ntfsTimeToTimestamp($ntfsTime)
public static function ntfsTimeToTimestamp(int $ntfsTime): float
{
return (float) (($ntfsTime + self::EPOCH_OFFSET) / 10000000);
}
/**
* @param int $ntfsTime
*
* @return \DateTimeInterface
*/
public static function ntfsTimeToDateTime($ntfsTime)
public static function ntfsTimeToDateTime(int $ntfsTime): \DateTimeInterface
{
$timestamp = self::ntfsTimeToTimestamp($ntfsTime);
$dateTime = \DateTimeImmutable::createFromFormat('U.u', sprintf('%.6f', $timestamp));
@ -311,10 +262,7 @@ class NtfsExtraField implements ZipExtraField
return $dateTime;
}
/**
* @return string
*/
public function __toString()
public function __toString(): string
{
$args = [self::HEADER_ID];
$format = '0x%04x NtfsExtra:';

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Extra\Fields;
use PhpZip\Model\Extra\ZipExtraField;
@ -56,27 +65,21 @@ use PhpZip\Model\ZipEntry;
class OldUnixExtraField implements ZipExtraField
{
/** @var int Header id */
const HEADER_ID = 0x5855;
public const HEADER_ID = 0x5855;
/** @var int|null Access timestamp */
private $accessTime;
private ?int $accessTime;
/** @var int|null Modify timestamp */
private $modifyTime;
private ?int $modifyTime;
/** @var int|null User id */
private $uid;
private ?int $uid;
/** @var int|null Group id */
private $gid;
private ?int $gid;
/**
* @param int|null $accessTime
* @param int|null $modifyTime
* @param int|null $uid
* @param int|null $gid
*/
public function __construct($accessTime, $modifyTime, $uid, $gid)
public function __construct(?int $accessTime, ?int $modifyTime, ?int $uid, ?int $gid)
{
$this->accessTime = $accessTime;
$this->modifyTime = $modifyTime;
@ -88,10 +91,8 @@ class OldUnixExtraField implements ZipExtraField
* 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()
public function getHeaderId(): int
{
return self::HEADER_ID;
}
@ -99,12 +100,12 @@ class OldUnixExtraField implements ZipExtraField
/**
* Populate data from this array as if it was in local file data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @return OldUnixExtraField
*/
public static function unpackLocalFileData($buffer, ZipEntry $entry = null)
public static function unpackLocalFileData(string $buffer, ?ZipEntry $entry = null): self
{
$length = \strlen($buffer);
@ -132,12 +133,12 @@ class OldUnixExtraField implements ZipExtraField
/**
* Populate data from this array as if it was in central directory data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @return OldUnixExtraField
*/
public static function unpackCentralDirData($buffer, ZipEntry $entry = null)
public static function unpackCentralDirData(string $buffer, ?ZipEntry $entry = null): self
{
$length = \strlen($buffer);
@ -160,7 +161,7 @@ class OldUnixExtraField implements ZipExtraField
*
* @return string the data
*/
public function packLocalFileData()
public function packLocalFileData(): string
{
$data = '';
@ -189,7 +190,7 @@ class OldUnixExtraField implements ZipExtraField
*
* @return string the data
*/
public function packCentralDirData()
public function packCentralDirData(): string
{
$data = '';
@ -204,100 +205,67 @@ class OldUnixExtraField implements ZipExtraField
return $data;
}
/**
* @return int|null
*/
public function getAccessTime()
public function getAccessTime(): ?int
{
return $this->accessTime;
}
/**
* @param int|null $accessTime
*/
public function setAccessTime($accessTime)
public function setAccessTime(?int $accessTime): void
{
$this->accessTime = $accessTime;
}
/**
* @return \DateTimeInterface|null
*/
public function getAccessDateTime()
public function getAccessDateTime(): ?\DateTimeInterface
{
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 int|null
*/
public function getModifyTime()
public function getModifyTime(): ?int
{
return $this->modifyTime;
}
/**
* @param int|null $modifyTime
*/
public function setModifyTime($modifyTime)
public function setModifyTime(?int $modifyTime): void
{
$this->modifyTime = $modifyTime;
}
/**
* @return \DateTimeInterface|null
*/
public function getModifyDateTime()
public function getModifyDateTime(): ?\DateTimeInterface
{
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 int|null
*/
public function getUid()
public function getUid(): ?int
{
return $this->uid;
}
/**
* @param int|null $uid
*/
public function setUid($uid)
public function setUid(?int $uid): void
{
$this->uid = $uid;
}
/**
* @return int|null
*/
public function getGid()
public function getGid(): ?int
{
return $this->gid;
}
/**
* @param int|null $gid
*/
public function setGid($gid)
public function setGid(?int $gid): void
{
$this->gid = $gid;
}
/**
* @return string
*/
public function __toString()
public function __toString(): string
{
$args = [self::HEADER_ID];
$format = '0x%04x OldUnix:';

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Extra\Fields;
/**
@ -48,24 +57,19 @@ namespace PhpZip\Model\Extra\Fields;
*/
class UnicodeCommentExtraField extends AbstractUnicodeExtraField
{
const HEADER_ID = 0x6375;
public 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()
public function getHeaderId(): int
{
return self::HEADER_ID;
}
/**
* @return string
*/
public function __toString()
public function __toString(): string
{
return sprintf(
'0x%04x UnicodeComment: "%s"',

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Extra\Fields;
/**
@ -49,24 +58,19 @@ namespace PhpZip\Model\Extra\Fields;
*/
class UnicodePathExtraField extends AbstractUnicodeExtraField
{
const HEADER_ID = 0x7075;
public 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()
public function getHeaderId(): int
{
return self::HEADER_ID;
}
/**
* @return string
*/
public function __toString()
public function __toString(): string
{
return sprintf(
'0x%04x UnicodePath: "%s"',

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Extra\Fields;
use PhpZip\Exception\RuntimeException;
@ -11,28 +20,18 @@ use PhpZip\Model\ZipEntry;
*/
class UnrecognizedExtraField implements ZipExtraField
{
/** @var int */
private $headerId;
private int $headerId;
/** @var string extra field data without Header-ID or length specifier */
private $data;
private string $data;
/**
* UnrecognizedExtraField constructor.
*
* @param int $headerId
* @param string $data
*/
public function __construct($headerId, $data)
public function __construct(int $headerId, string $data)
{
$this->headerId = (int) $headerId;
$this->data = (string) $data;
$this->headerId = $headerId;
$this->data = $data;
}
/**
* @param int $headerId
*/
public function setHeaderId($headerId)
public function setHeaderId(int $headerId): void
{
$this->headerId = $headerId;
}
@ -41,10 +40,8 @@ class UnrecognizedExtraField implements ZipExtraField
* 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()
public function getHeaderId(): int
{
return $this->headerId;
}
@ -52,10 +49,10 @@ class UnrecognizedExtraField implements ZipExtraField
/**
* Populate data from this array as if it was in local file data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*/
public static function unpackLocalFileData($buffer, ZipEntry $entry = null)
public static function unpackLocalFileData(string $buffer, ?ZipEntry $entry = null): ZipExtraField
{
throw new RuntimeException('Unsupport parse');
}
@ -63,10 +60,10 @@ class UnrecognizedExtraField implements ZipExtraField
/**
* Populate data from this array as if it was in central directory data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*/
public static function unpackCentralDirData($buffer, ZipEntry $entry = null)
public static function unpackCentralDirData(string $buffer, ?ZipEntry $entry = null): ZipExtraField
{
throw new RuntimeException('Unsupport parse');
}
@ -74,7 +71,7 @@ class UnrecognizedExtraField implements ZipExtraField
/**
* {@inheritdoc}
*/
public function packLocalFileData()
public function packLocalFileData(): string
{
return $this->data;
}
@ -82,31 +79,22 @@ class UnrecognizedExtraField implements ZipExtraField
/**
* {@inheritdoc}
*/
public function packCentralDirData()
public function packCentralDirData(): string
{
return $this->data;
}
/**
* @return string
*/
public function getData()
public function getData(): string
{
return $this->data;
}
/**
* @param string $data
*/
public function setData($data)
public function setData(string $data): void
{
$this->data = (string) $data;
$this->data = $data;
}
/**
* @return string
*/
public function __toString()
public function __toString(): string
{
$args = [$this->headerId, $this->data];
$format = '0x%04x Unrecognized Extra Field: "%s"';

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Extra\Fields;
use PhpZip\Constants\ZipCompressionMethod;
@ -18,69 +27,69 @@ use PhpZip\Model\ZipEntry;
class WinZipAesExtraField implements ZipExtraField
{
/** @var int Header id */
const HEADER_ID = 0x9901;
public const HEADER_ID = 0x9901;
/**
* @var int Data size (currently 7, but subject to possible increase
* in the future)
*/
const DATA_SIZE = 7;
public const DATA_SIZE = 7;
/**
* @var int The vendor ID field should always be set to the two ASCII
* characters "AE"
*/
const VENDOR_ID = 0x4541; // 'A' | ('E' << 8)
public const VENDOR_ID = 0x4541; // 'A' | ('E' << 8)
/**
* @var int Entries of this type do include the standard ZIP CRC-32 value.
* For use with {@see WinZipAesExtraField::setVendorVersion()}.
*/
const VERSION_AE1 = 1;
public const VERSION_AE1 = 1;
/**
* @var int Entries of this type do not include the standard ZIP CRC-32 value.
* For use with {@see WinZipAesExtraField::setVendorVersion().
*/
const VERSION_AE2 = 2;
public const VERSION_AE2 = 2;
/** @var int integer mode value indicating AES encryption 128-bit strength */
const KEY_STRENGTH_128BIT = 0x01;
public const KEY_STRENGTH_128BIT = 0x01;
/** @var int integer mode value indicating AES encryption 192-bit strength */
const KEY_STRENGTH_192BIT = 0x02;
public const KEY_STRENGTH_192BIT = 0x02;
/** @var int integer mode value indicating AES encryption 256-bit strength */
const KEY_STRENGTH_256BIT = 0x03;
public const KEY_STRENGTH_256BIT = 0x03;
/** @var int[] */
private static $allowVendorVersions = [
private const ALLOW_VENDOR_VERSIONS = [
self::VERSION_AE1,
self::VERSION_AE2,
];
/** @var array<int, int> */
private static $encryptionStrengths = [
private const ENCRYPTION_STRENGTHS = [
self::KEY_STRENGTH_128BIT => 128,
self::KEY_STRENGTH_192BIT => 192,
self::KEY_STRENGTH_256BIT => 256,
];
/** @var array<int, int> */
private static $MAP_KEY_STRENGTH_METHODS = [
private const MAP_KEY_STRENGTH_METHODS = [
self::KEY_STRENGTH_128BIT => ZipEncryptionMethod::WINZIP_AES_128,
self::KEY_STRENGTH_192BIT => ZipEncryptionMethod::WINZIP_AES_192,
self::KEY_STRENGTH_256BIT => ZipEncryptionMethod::WINZIP_AES_256,
];
/** @var int Integer version number specific to the zip vendor */
private $vendorVersion = self::VERSION_AE1;
private int $vendorVersion = self::VERSION_AE1;
/** @var int Integer mode value indicating AES encryption strength */
private $keyStrength = self::KEY_STRENGTH_256BIT;
private int $keyStrength = self::KEY_STRENGTH_256BIT;
/** @var int The actual compression method used to compress the file */
private $compressionMethod;
private int $compressionMethod;
/**
* @param int $vendorVersion Integer version number specific to the zip vendor
@ -89,7 +98,7 @@ class WinZipAesExtraField implements ZipExtraField
*
* @throws ZipUnsupportMethodException
*/
public function __construct($vendorVersion, $keyStrength, $compressionMethod)
public function __construct(int $vendorVersion, int $keyStrength, int $compressionMethod)
{
$this->setVendorVersion($vendorVersion);
$this->setKeyStrength($keyStrength);
@ -97,15 +106,13 @@ class WinZipAesExtraField implements ZipExtraField
}
/**
* @param ZipEntry $entry
*
* @throws ZipUnsupportMethodException
*
* @return WinZipAesExtraField
*/
public static function create(ZipEntry $entry)
public static function create(ZipEntry $entry): self
{
$keyStrength = array_search($entry->getEncryptionMethod(), self::$MAP_KEY_STRENGTH_METHODS, true);
$keyStrength = array_search($entry->getEncryptionMethod(), self::MAP_KEY_STRENGTH_METHODS, true);
if ($keyStrength === false) {
throw new InvalidArgumentException('Not support encryption method ' . $entry->getEncryptionMethod());
@ -118,11 +125,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());
@ -136,10 +143,8 @@ class WinZipAesExtraField implements ZipExtraField
* 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()
public function getHeaderId(): int
{
return self::HEADER_ID;
}
@ -147,14 +152,14 @@ class WinZipAesExtraField implements ZipExtraField
/**
* Populate data from this array as if it was in local file data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @throws ZipException on error
*
* @return WinZipAesExtraField
*/
public static function unpackLocalFileData($buffer, ZipEntry $entry = null)
public static function unpackLocalFileData(string $buffer, ?ZipEntry $entry = null): self
{
$size = \strlen($buffer);
@ -168,36 +173,37 @@ class WinZipAesExtraField implements ZipExtraField
);
}
$data = unpack('vvendorVersion/vvendorId/ckeyStrength/vcompressionMethod', $buffer);
[
'vendorVersion' => $vendorVersion,
'vendorId' => $vendorId,
'keyStrength' => $keyStrength,
'compressionMethod' => $compressionMethod,
] = unpack('vvendorVersion/vvendorId/ckeyStrength/vcompressionMethod', $buffer);
if ($data['vendorId'] !== self::VENDOR_ID) {
if ($vendorId !== self::VENDOR_ID) {
throw new ZipException(
sprintf(
'Vendor id invalid: %d. Must be %d',
$data['vendorId'],
$vendorId,
self::VENDOR_ID
)
);
}
return new self(
$data['vendorVersion'],
$data['keyStrength'],
$data['compressionMethod']
);
return new self($vendorVersion, $keyStrength, $compressionMethod);
}
/**
* Populate data from this array as if it was in central directory data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @throws ZipException
*
* @return WinZipAesExtraField
*/
public static function unpackCentralDirData($buffer, ZipEntry $entry = null)
public static function unpackCentralDirData(string $buffer, ?ZipEntry $entry = null): self
{
return self::unpackLocalFileData($buffer, $entry);
}
@ -208,7 +214,7 @@ class WinZipAesExtraField implements ZipExtraField
*
* @return string the data
*/
public function packLocalFileData()
public function packLocalFileData(): string
{
return pack(
'vvcv',
@ -225,7 +231,7 @@ class WinZipAesExtraField implements ZipExtraField
*
* @return string the data
*/
public function packCentralDirData()
public function packCentralDirData(): string
{
return $this->packLocalFileData();
}
@ -233,12 +239,10 @@ class WinZipAesExtraField implements ZipExtraField
/**
* Returns the vendor version.
*
* @return int
*
* @see WinZipAesExtraField::VERSION_AE2
* @see WinZipAesExtraField::VERSION_AE1
*/
public function getVendorVersion()
public function getVendorVersion(): int
{
return $this->vendorVersion;
}
@ -251,11 +255,9 @@ class WinZipAesExtraField implements ZipExtraField
* @see WinZipAesExtraField::VERSION_AE2
* @see WinZipAesExtraField::VERSION_AE1
*/
public function setVendorVersion($vendorVersion)
public function setVendorVersion(int $vendorVersion): void
{
$vendorVersion = (int) $vendorVersion;
if (!\in_array($vendorVersion, self::$allowVendorVersions, true)) {
if (!\in_array($vendorVersion, self::ALLOW_VENDOR_VERSIONS, true)) {
throw new InvalidArgumentException(
sprintf(
'Unsupport WinZip AES vendor version: %d',
@ -268,113 +270,80 @@ class WinZipAesExtraField implements ZipExtraField
/**
* Returns vendor id.
*
* @return int
*/
public function getVendorId()
public function getVendorId(): int
{
return self::VENDOR_ID;
}
/**
* @return int
*/
public function getKeyStrength()
public function getKeyStrength(): int
{
return $this->keyStrength;
}
/**
* Set key strength.
*
* @param int $keyStrength
*/
public function setKeyStrength($keyStrength)
public function setKeyStrength(int $keyStrength): void
{
$keyStrength = (int) $keyStrength;
if (!isset(self::$encryptionStrengths[$keyStrength])) {
if (!isset(self::ENCRYPTION_STRENGTHS[$keyStrength])) {
throw new InvalidArgumentException(
sprintf(
'Key strength %d not support value. Allow values: %s',
$keyStrength,
implode(', ', array_keys(self::$encryptionStrengths))
implode(', ', array_keys(self::ENCRYPTION_STRENGTHS))
)
);
}
$this->keyStrength = $keyStrength;
}
/**
* @return int
*/
public function getCompressionMethod()
public function getCompressionMethod(): int
{
return $this->compressionMethod;
}
/**
* @param int $compressionMethod
*
* @throws ZipUnsupportMethodException
*/
public function setCompressionMethod($compressionMethod)
public function setCompressionMethod(int $compressionMethod): void
{
$compressionMethod = (int) $compressionMethod;
ZipCompressionMethod::checkSupport($compressionMethod);
$this->compressionMethod = $compressionMethod;
}
/**
* @return int
*/
public function getEncryptionStrength()
public function getEncryptionStrength(): int
{
return self::$encryptionStrengths[$this->keyStrength];
return self::ENCRYPTION_STRENGTHS[$this->keyStrength];
}
/**
* @return int
*/
public function getEncryptionMethod()
public function getEncryptionMethod(): int
{
$keyStrength = $this->getKeyStrength();
if (!isset(self::$MAP_KEY_STRENGTH_METHODS[$keyStrength])) {
if (!isset(self::MAP_KEY_STRENGTH_METHODS[$keyStrength])) {
throw new InvalidArgumentException('Invalid encryption method');
}
return self::$MAP_KEY_STRENGTH_METHODS[$keyStrength];
return self::MAP_KEY_STRENGTH_METHODS[$keyStrength];
}
/**
* @return bool
*/
public function isV1()
public function isV1(): bool
{
return $this->vendorVersion === self::VERSION_AE1;
}
/**
* @return bool
*/
public function isV2()
public function isV2(): bool
{
return $this->vendorVersion === self::VERSION_AE2;
}
/**
* @return int
*/
public function getSaltSize()
public function getSaltSize(): int
{
return (int) ($this->getEncryptionStrength() / 8 / 2);
}
/**
* @return string
*/
public function __toString()
public function __toString(): string
{
return sprintf(
'0x%04x WINZIP AES: VendorVersion=%d KeyStrength=0x%02x CompressionMethod=%s',

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Extra\Fields;
use PhpZip\Constants\ZipConstants;
@ -7,7 +16,6 @@ use PhpZip\Exception\RuntimeException;
use PhpZip\Exception\ZipException;
use PhpZip\Model\Extra\ZipExtraField;
use PhpZip\Model\ZipEntry;
use PhpZip\Util\PackUtil;
/**
* ZIP64 Extra Field.
@ -17,33 +25,21 @@ use PhpZip\Util\PackUtil;
class Zip64ExtraField implements ZipExtraField
{
/** @var int The Header ID for a ZIP64 Extended Information Extra Field. */
const HEADER_ID = 0x0001;
public const HEADER_ID = 0x0001;
/** @var int|null */
private $uncompressedSize;
private ?int $uncompressedSize;
/** @var int|null */
private $compressedSize;
private ?int $compressedSize;
/** @var int|null */
private $localHeaderOffset;
private ?int $localHeaderOffset;
/** @var int|null */
private $diskStart;
private ?int $diskStart;
/**
* Zip64ExtraField constructor.
*
* @param int|null $uncompressedSize
* @param int|null $compressedSize
* @param int|null $localHeaderOffset
* @param int|null $diskStart
*/
public function __construct(
$uncompressedSize = null,
$compressedSize = null,
$localHeaderOffset = null,
$diskStart = null
?int $uncompressedSize = null,
?int $compressedSize = null,
?int $localHeaderOffset = null,
?int $diskStart = null
) {
$this->uncompressedSize = $uncompressedSize;
$this->compressedSize = $compressedSize;
@ -55,10 +51,8 @@ class Zip64ExtraField implements ZipExtraField
* 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()
public function getHeaderId(): int
{
return self::HEADER_ID;
}
@ -66,14 +60,14 @@ class Zip64ExtraField implements ZipExtraField
/**
* Populate data from this array as if it was in local file data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @throws ZipException on error
*
* @return Zip64ExtraField
*/
public static function unpackLocalFileData($buffer, ZipEntry $entry = null)
public static function unpackLocalFileData(string $buffer, ?ZipEntry $entry = null): self
{
$length = \strlen($buffer);
@ -91,8 +85,10 @@ class Zip64ExtraField implements ZipExtraField
);
}
$uncompressedSize = PackUtil::unpackLongLE(substr($buffer, 0, 8));
$compressedSize = PackUtil::unpackLongLE(substr($buffer, 8, 8));
[
'uncompressedSize' => $uncompressedSize,
'compressedSize' => $compressedSize,
] = unpack('PuncompressedSize/PcompressedSize', substr($buffer, 0, 16));
return new self($uncompressedSize, $compressedSize);
}
@ -100,14 +96,14 @@ class Zip64ExtraField implements ZipExtraField
/**
* Populate data from this array as if it was in central directory data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @throws ZipException
*
* @return Zip64ExtraField
*/
public static function unpackCentralDirData($buffer, ZipEntry $entry = null)
public static function unpackCentralDirData(string $buffer, ?ZipEntry $entry = null): self
{
if ($entry === null) {
throw new RuntimeException('zipEntry is null');
@ -125,7 +121,7 @@ class Zip64ExtraField implements ZipExtraField
if ($remaining < 8) {
throw new ZipException('ZIP64 extension corrupt (no uncompressed size).');
}
$uncompressedSize = PackUtil::unpackLongLE(substr($buffer, $length - $remaining, 8));
$uncompressedSize = unpack('P', substr($buffer, $length - $remaining, 8))[1];
$remaining -= 8;
}
@ -133,7 +129,7 @@ class Zip64ExtraField implements ZipExtraField
if ($remaining < 8) {
throw new ZipException('ZIP64 extension corrupt (no compressed size).');
}
$compressedSize = PackUtil::unpackLongLE(substr($buffer, $length - $remaining, 8));
$compressedSize = unpack('P', substr($buffer, $length - $remaining, 8))[1];
$remaining -= 8;
}
@ -141,7 +137,7 @@ class Zip64ExtraField implements ZipExtraField
if ($remaining < 8) {
throw new ZipException('ZIP64 extension corrupt (no relative local header offset).');
}
$localHeaderOffset = PackUtil::unpackLongLE(substr($buffer, $length - $remaining, 8));
$localHeaderOffset = unpack('P', substr($buffer, $length - $remaining, 8))[1];
$remaining -= 8;
}
@ -158,7 +154,7 @@ class Zip64ExtraField implements ZipExtraField
*
* @return string the data
*/
public function packLocalFileData()
public function packLocalFileData(): string
{
if ($this->uncompressedSize !== null || $this->compressedSize !== null) {
if ($this->uncompressedSize === null || $this->compressedSize === null) {
@ -173,19 +169,16 @@ class Zip64ExtraField implements ZipExtraField
return '';
}
/**
* @return string
*/
private function packSizes()
private function packSizes(): string
{
$data = '';
if ($this->uncompressedSize !== null) {
$data .= PackUtil::packLongLE($this->uncompressedSize);
$data .= pack('P', $this->uncompressedSize);
}
if ($this->compressedSize !== null) {
$data .= PackUtil::packLongLE($this->compressedSize);
$data .= pack('P', $this->compressedSize);
}
return $data;
@ -197,12 +190,12 @@ class Zip64ExtraField implements ZipExtraField
*
* @return string the data
*/
public function packCentralDirData()
public function packCentralDirData(): string
{
$data = $this->packSizes();
if ($this->localHeaderOffset !== null) {
$data .= PackUtil::packLongLE($this->localHeaderOffset);
$data .= pack('P', $this->localHeaderOffset);
}
if ($this->diskStart !== null) {
@ -212,74 +205,47 @@ class Zip64ExtraField implements ZipExtraField
return $data;
}
/**
* @return int|null
*/
public function getUncompressedSize()
public function getUncompressedSize(): ?int
{
return $this->uncompressedSize;
}
/**
* @param int|null $uncompressedSize
*/
public function setUncompressedSize($uncompressedSize)
public function setUncompressedSize(?int $uncompressedSize): void
{
$this->uncompressedSize = $uncompressedSize;
}
/**
* @return int|null
*/
public function getCompressedSize()
public function getCompressedSize(): ?int
{
return $this->compressedSize;
}
/**
* @param int|null $compressedSize
*/
public function setCompressedSize($compressedSize)
public function setCompressedSize(?int $compressedSize): void
{
$this->compressedSize = $compressedSize;
}
/**
* @return int|null
*/
public function getLocalHeaderOffset()
public function getLocalHeaderOffset(): ?int
{
return $this->localHeaderOffset;
}
/**
* @param int|null $localHeaderOffset
*/
public function setLocalHeaderOffset($localHeaderOffset)
public function setLocalHeaderOffset(?int $localHeaderOffset): void
{
$this->localHeaderOffset = $localHeaderOffset;
}
/**
* @return int|null
*/
public function getDiskStart()
public function getDiskStart(): ?int
{
return $this->diskStart;
}
/**
* @param int|null $diskStart
*/
public function setDiskStart($diskStart)
public function setDiskStart(?int $diskStart): void
{
$this->diskStart = $diskStart;
}
/**
* @return string
*/
public function __toString()
public function __toString(): string
{
$args = [self::HEADER_ID];
$format = '0x%04x ZIP64: ';

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Extra;
use PhpZip\Exception\InvalidArgumentException;
@ -22,9 +31,9 @@ final class ZipExtraDriver
{
/**
* @var array<int, string>
* @psalm-var array<int, class-string<\PhpZip\Model\Extra\ZipExtraField>>
* @psalm-var array<int, class-string<ZipExtraField>>
*/
private static $implementations = [
private static array $implementations = [
ApkAlignmentExtraField::HEADER_ID => ApkAlignmentExtraField::class,
AsiExtraField::HEADER_ID => AsiExtraField::class,
ExtendedTimestampExtraField::HEADER_ID => ExtendedTimestampExtraField::class,
@ -45,7 +54,7 @@ final class ZipExtraDriver
/**
* @param string|ZipExtraField $extraField ZipExtraField object or class name
*/
public static function register($extraField)
public static function register($extraField): void
{
if (!is_a($extraField, ZipExtraField::class, true)) {
throw new InvalidArgumentException(
@ -61,10 +70,8 @@ final class ZipExtraDriver
/**
* @param int|string|ZipExtraField $extraType ZipExtraField object or class name or extra header id
*
* @return bool
*/
public static function unregister($extraType)
public static function unregister($extraType): bool
{
$headerId = null;
@ -85,23 +92,12 @@ final class ZipExtraDriver
return false;
}
/**
* @param int $headerId
*
* @return string|null
*/
public static function getClassNameOrNull($headerId)
public static function getClassNameOrNull(int $headerId): ?string
{
$headerId = (int) $headerId;
if ($headerId < 0 || $headerId > 0xffff) {
throw new \InvalidArgumentException('$headerId out of range: ' . $headerId);
}
if (isset(self::$implementations[$headerId])) {
return self::$implementations[$headerId];
}
return null;
return self::$implementations[$headerId] ?? null;
}
}

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model\Extra;
use PhpZip\Model\ZipEntry;
@ -15,30 +24,28 @@ interface ZipExtraField
* 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();
public function getHeaderId(): int;
/**
* Populate data from this array as if it was in local file data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @return static
*/
public static function unpackLocalFileData($buffer, ZipEntry $entry = null);
public static function unpackLocalFileData(string $buffer, ?ZipEntry $entry = null): self;
/**
* Populate data from this array as if it was in central directory data.
*
* @param string $buffer the buffer to read data from
* @param ZipEntry|null $entry
* @param string $buffer the buffer to read data from
* @param ?ZipEntry $entry
*
* @return static
*/
public static function unpackCentralDirData($buffer, ZipEntry $entry = null);
public static function unpackCentralDirData(string $buffer, ?ZipEntry $entry = null): self;
/**
* The actual data to put into local file data - without Header-ID
@ -46,7 +53,7 @@ interface ZipExtraField
*
* @return string the data
*/
public function packLocalFileData();
public function packLocalFileData(): string;
/**
* The actual data to put into central directory - without Header-ID or
@ -54,10 +61,7 @@ interface ZipExtraField
*
* @return string the data
*/
public function packCentralDirData();
public function packCentralDirData(): string;
/**
* @return string
*/
public function __toString();
public function __toString(): string;
}

View File

@ -1,25 +1,29 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model;
/**
* Class ImmutableZipContainer.
*/
class ImmutableZipContainer implements \Countable
{
/** @var ZipEntry[] */
protected $entries;
protected array $entries;
/** @var string|null Archive comment */
protected $archiveComment;
protected ?string $archiveComment;
/**
* ZipContainer constructor.
*
* @param ZipEntry[] $entries
* @param string|null $archiveComment
* @param ZipEntry[] $entries
* @param ?string $archiveComment
*/
public function __construct(array $entries, $archiveComment)
public function __construct(array $entries, ?string $archiveComment = null)
{
$this->entries = $entries;
$this->archiveComment = $archiveComment;
@ -28,15 +32,12 @@ class ImmutableZipContainer implements \Countable
/**
* @return ZipEntry[]
*/
public function &getEntries()
public function &getEntries(): array
{
return $this->entries;
}
/**
* @return string|null
*/
public function getArchiveComment()
public function getArchiveComment(): ?string
{
return $this->archiveComment;
}
@ -49,7 +50,7 @@ class ImmutableZipContainer implements \Countable
* @return int The custom count as an integer.
* The return value is cast to an integer.
*/
public function count()
public function count(): int
{
return \count($this->entries);
}

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model;
use PhpZip\Constants\ZipEncryptionMethod;
@ -8,7 +17,7 @@ use PhpZip\Exception\ZipEntryNotFoundException;
use PhpZip\Exception\ZipException;
/**
* Class ZipContainer.
* Zip Container.
*/
class ZipContainer extends ImmutableZipContainer
{
@ -18,21 +27,9 @@ class ZipContainer extends ImmutableZipContainer
* it possible to undo changes in the archive.
* When cloning, this container is not cloned.
*/
private $sourceContainer;
private ?ImmutableZipContainer $sourceContainer;
/**
* @var int|null Apk zipalign value
*
* @todo remove and use in ApkFileWriter
*/
private $zipAlign;
/**
* MutableZipContainer constructor.
*
* @param ImmutableZipContainer|null $sourceContainer
*/
public function __construct(ImmutableZipContainer $sourceContainer = null)
public function __construct(?ImmutableZipContainer $sourceContainer = null)
{
$entries = [];
$archiveComment = null;
@ -47,28 +44,20 @@ class ZipContainer extends ImmutableZipContainer
$this->sourceContainer = $sourceContainer;
}
/**
* @return ImmutableZipContainer|null
*/
public function getSourceContainer()
public function getSourceContainer(): ?ImmutableZipContainer
{
return $this->sourceContainer;
}
/**
* @param ZipEntry $entry
*/
public function addEntry(ZipEntry $entry)
public function addEntry(ZipEntry $entry): void
{
$this->entries[$entry->getName()] = $entry;
}
/**
* @param string|ZipEntry $entry
*
* @return bool
*/
public function deleteEntry($entry)
public function deleteEntry($entry): bool
{
$entry = $entry instanceof ZipEntry ? $entry->getName() : (string) $entry;
@ -89,7 +78,7 @@ class ZipContainer extends ImmutableZipContainer
*
* @return ZipEntry New zip entry
*/
public function renameEntry($old, $new)
public function renameEntry($old, $new): ZipEntry
{
$old = $old instanceof ZipEntry ? $old->getName() : (string) $old;
$new = $new instanceof ZipEntry ? $new->getName() : (string) $new;
@ -111,10 +100,8 @@ class ZipContainer extends ImmutableZipContainer
* @param string|ZipEntry $entryName
*
* @throws ZipEntryNotFoundException
*
* @return ZipEntry
*/
public function getEntry($entryName)
public function getEntry($entryName): ZipEntry
{
$entry = $this->getEntryOrNull($entryName);
@ -127,22 +114,18 @@ class ZipContainer extends ImmutableZipContainer
/**
* @param string|ZipEntry $entryName
*
* @return ZipEntry|null
*/
public function getEntryOrNull($entryName)
public function getEntryOrNull($entryName): ?ZipEntry
{
$entryName = $entryName instanceof ZipEntry ? $entryName->getName() : (string) $entryName;
return isset($this->entries[$entryName]) ? $this->entries[$entryName] : null;
return $this->entries[$entryName] ?? null;
}
/**
* @param string|ZipEntry $entryName
*
* @return bool
*/
public function hasEntry($entryName)
public function hasEntry($entryName): bool
{
$entryName = $entryName instanceof ZipEntry ? $entryName->getName() : (string) $entryName;
@ -152,7 +135,7 @@ class ZipContainer extends ImmutableZipContainer
/**
* Delete all entries.
*/
public function deleteAll()
public function deleteAll(): void
{
$this->entries = [];
}
@ -164,7 +147,7 @@ class ZipContainer extends ImmutableZipContainer
*
* @return ZipEntry[] Deleted entries
*/
public function deleteByRegex($regexPattern)
public function deleteByRegex(string $regexPattern): array
{
if (empty($regexPattern)) {
throw new InvalidArgumentException('The regex pattern is not specified');
@ -189,7 +172,7 @@ class ZipContainer extends ImmutableZipContainer
/**
* Undo all changes done in the archive.
*/
public function unchangeAll()
public function unchangeAll(): void
{
$this->entries = [];
@ -204,7 +187,7 @@ class ZipContainer extends ImmutableZipContainer
/**
* Undo change archive comment.
*/
public function unchangeArchiveComment()
public function unchangeArchiveComment(): void
{
$this->archiveComment = null;
@ -217,16 +200,14 @@ class ZipContainer extends ImmutableZipContainer
* Revert all changes done to an entry with the given name.
*
* @param string|ZipEntry $entry Entry name or ZipEntry
*
* @return bool
*/
public function unchangeEntry($entry)
public function unchangeEntry($entry): bool
{
$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];
@ -245,10 +226,8 @@ class ZipContainer extends ImmutableZipContainer
* return strcmp($nameA, $nameB);
* });
* ```
*
* @param callable $cmp
*/
public function sortByName(callable $cmp)
public function sortByName(callable $cmp): void
{
uksort($this->entries, $cmp);
}
@ -262,21 +241,15 @@ class ZipContainer extends ImmutableZipContainer
* return strcmp($a->getName(), $b->getName());
* });
* ```
*
* @param callable $cmp
*/
public function sortByEntry(callable $cmp)
public function sortByEntry(callable $cmp): void
{
uasort($this->entries, $cmp);
}
/**
* @param string|null $archiveComment
*/
public function setArchiveComment($archiveComment)
public function setArchiveComment(?string $archiveComment): void
{
if ($archiveComment !== null && $archiveComment !== '') {
$archiveComment = (string) $archiveComment;
$length = \strlen($archiveComment);
if ($length > 0xffff) {
@ -286,10 +259,7 @@ class ZipContainer extends ImmutableZipContainer
$this->archiveComment = $archiveComment;
}
/**
* @return ZipEntryMatcher
*/
public function matcher()
public function matcher(): ZipEntryMatcher
{
return new ZipEntryMatcher($this);
}
@ -297,9 +267,9 @@ class ZipContainer extends ImmutableZipContainer
/**
* Specify a password for extracting files.
*
* @param string|null $password
* @param ?string $password
*/
public function setReadPassword($password)
public function setReadPassword(?string $password): void
{
if ($this->sourceContainer !== null) {
foreach ($this->sourceContainer->entries as $entry) {
@ -311,13 +281,10 @@ class ZipContainer extends ImmutableZipContainer
}
/**
* @param string $entryName
* @param string $password
*
* @throws ZipEntryNotFoundException
* @throws ZipException
*/
public function setReadPasswordEntry($entryName, $password)
public function setReadPasswordEntry(string $entryName, string $password): void
{
if (!isset($this->sourceContainer->entries[$entryName])) {
throw new ZipEntryNotFoundException($entryName);
@ -329,57 +296,39 @@ class ZipContainer extends ImmutableZipContainer
}
/**
* @return int|null
* @param ?string $writePassword
*
* @throws ZipEntryNotFoundException
*/
public function getZipAlign()
{
return $this->zipAlign;
}
/**
* @param int|null $zipAlign
*/
public function setZipAlign($zipAlign)
{
$this->zipAlign = $zipAlign === null ? null : (int) $zipAlign;
}
/**
* @return bool
*/
public function isZipAlign()
{
return $this->zipAlign !== null;
}
/**
* @param string|null $writePassword
*/
public function setWritePassword($writePassword)
public function setWritePassword(?string $writePassword): void
{
$this->matcher()->all()->setPassword($writePassword);
}
/**
* Remove password.
*
* @throws ZipEntryNotFoundException
*/
public function removePassword()
public function removePassword(): void
{
$this->matcher()->all()->setPassword(null);
}
/**
* @param string|ZipEntry $entryName
*
* @throws ZipEntryNotFoundException
*/
public function removePasswordEntry($entryName)
public function removePasswordEntry($entryName): void
{
$this->matcher()->add($entryName)->setPassword(null);
}
/**
* @param int $encryptionMethod
* @throws ZipEntryNotFoundException
*/
public function setEncryptionMethod($encryptionMethod = ZipEncryptionMethod::WINZIP_AES_256)
public function setEncryptionMethod(int $encryptionMethod = ZipEncryptionMethod::WINZIP_AES_256): void
{
$this->matcher()->all()->setEncryptionMethod($encryptionMethod);
}

View File

@ -1,18 +1,24 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model;
use PhpZip\Exception\ZipException;
/**
* Interface ZipData.
*/
interface ZipData
{
/**
* @return string returns data as string
*/
public function getDataAsString();
public function getDataAsString(): string;
/**
* @return resource returns stream data

File diff suppressed because it is too large Load Diff

View File

@ -1,24 +1,24 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Model;
/**
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*/
use PhpZip\Exception\ZipEntryNotFoundException;
class ZipEntryMatcher implements \Countable
{
/** @var ZipContainer */
protected $zipContainer;
protected ZipContainer $zipContainer;
/** @var array */
protected $matches = [];
protected array $matches = [];
/**
* ZipEntryMatcher constructor.
*
* @param ZipContainer $zipContainer
*/
public function __construct(ZipContainer $zipContainer)
{
$this->zipContainer = $zipContainer;
@ -29,13 +29,11 @@ class ZipEntryMatcher implements \Countable
*
* @return ZipEntryMatcher
*/
public function add($entries)
public function add($entries): self
{
$entries = (array) $entries;
$entries = array_map(
static function ($entry) {
return $entry instanceof ZipEntry ? $entry->getName() : (string) $entry;
},
static fn ($entry) => $entry instanceof ZipEntry ? $entry->getName() : (string) $entry,
$entries
);
$this->matches = array_values(
@ -59,23 +57,16 @@ class ZipEntryMatcher implements \Countable
}
/**
* @param string $regexp
*
* @return ZipEntryMatcher
*
* @noinspection PhpUnusedParameterInspection
*/
public function match($regexp)
public function match(string $regexp): self
{
array_walk(
$this->zipContainer->getEntries(),
/**
* @param ZipEntry $entry
* @param string $entryName
*/
function (ZipEntry $entry, $entryName) use ($regexp) {
function (ZipEntry $entry, string $entryName) use ($regexp): void {
if (preg_match($regexp, $entryName)) {
$this->matches[] = (string) $entryName;
$this->matches[] = $entryName;
}
}
);
@ -87,7 +78,7 @@ class ZipEntryMatcher implements \Countable
/**
* @return ZipEntryMatcher
*/
public function all()
public function all(): self
{
$this->matches = array_map(
'strval',
@ -102,36 +93,31 @@ class ZipEntryMatcher implements \Countable
*
* Callable function signature:
* function(string $entryName){}
*
* @param callable $callable
*/
public function invoke(callable $callable)
public function invoke(callable $callable): void
{
if (!empty($this->matches)) {
array_walk(
$this->matches,
/** @param string $entryName */
static function ($entryName) use ($callable) {
static function (string $entryName) use ($callable): void {
$callable($entryName);
}
);
}
}
/**
* @return array
*/
public function getMatches()
public function getMatches(): array
{
return $this->matches;
}
public function delete()
public function delete(): void
{
array_walk(
$this->matches,
/** @param string $entryName */
function ($entryName) {
function (string $entryName): void {
$this->zipContainer->deleteEntry($entryName);
}
);
@ -139,15 +125,17 @@ class ZipEntryMatcher implements \Countable
}
/**
* @param string|null $password
* @param int|null $encryptionMethod
* @param ?string $password
* @param ?int $encryptionMethod
*
* @throws ZipEntryNotFoundException
*/
public function setPassword($password, $encryptionMethod = null)
public function setPassword(?string $password, ?int $encryptionMethod = null): void
{
array_walk(
$this->matches,
/** @param string $entryName */
function ($entryName) use ($password, $encryptionMethod) {
function (string $entryName) use ($password, $encryptionMethod): void {
$entry = $this->zipContainer->getEntry($entryName);
if (!$entry->isDirectory()) {
@ -158,14 +146,14 @@ class ZipEntryMatcher implements \Countable
}
/**
* @param int $encryptionMethod
* @throws ZipEntryNotFoundException
*/
public function setEncryptionMethod($encryptionMethod)
public function setEncryptionMethod(int $encryptionMethod): void
{
array_walk(
$this->matches,
/** @param string $entryName */
function ($entryName) use ($encryptionMethod) {
function (string $entryName) use ($encryptionMethod): void {
$entry = $this->zipContainer->getEntry($entryName);
if (!$entry->isDirectory()) {
@ -175,12 +163,14 @@ class ZipEntryMatcher implements \Countable
);
}
public function disableEncryption()
/**
* @throws ZipEntryNotFoundException
*/
public function disableEncryption(): void
{
array_walk(
$this->matches,
/** @param string $entryName */
function ($entryName) {
function (string $entryName): void {
$entry = $this->zipContainer->getEntry($entryName);
if (!$entry->isDirectory()) {
@ -196,10 +186,8 @@ class ZipEntryMatcher implements \Countable
* @see http://php.net/manual/en/countable.count.php
*
* @return int the custom count as an integer
*
* @since 5.1.0
*/
public function count()
public function count(): int
{
return \count($this->matches);
}

View File

@ -1,266 +0,0 @@
<?php
namespace PhpZip\Model;
use PhpZip\Constants\ZipCompressionMethod;
use PhpZip\Constants\ZipEncryptionMethod;
use PhpZip\Constants\ZipPlatform;
use PhpZip\Util\FileAttribUtil;
use PhpZip\Util\FilesUtil;
/**
* Zip info.
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*
* @deprecated Use ZipEntry
*/
class ZipInfo
{
/** @var ZipEntry */
private $entry;
/**
* ZipInfo constructor.
*
* @param ZipEntry $entry
*/
public function __construct(ZipEntry $entry)
{
$this->entry = $entry;
}
/**
* @param ZipEntry $entry
*
* @return string
*
* @deprecated Use {@see ZipPlatform::getPlatformName()}
*/
public static function getPlatformName(ZipEntry $entry)
{
return ZipPlatform::getPlatformName($entry->getExtractedOS());
}
/**
* @return string
*/
public function getName()
{
return $this->entry->getName();
}
/**
* @return bool
*/
public function isFolder()
{
return $this->entry->isDirectory();
}
/**
* @return int
*/
public function getSize()
{
return $this->entry->getUncompressedSize();
}
/**
* @return int
*/
public function getCompressedSize()
{
return $this->entry->getCompressedSize();
}
/**
* @return int
*/
public function getMtime()
{
return $this->entry->getMTime()->getTimestamp();
}
/**
* @return int|null
*/
public function getCtime()
{
$ctime = $this->entry->getCTime();
return $ctime === null ? null : $ctime->getTimestamp();
}
/**
* @return int|null
*/
public function getAtime()
{
$atime = $this->entry->getATime();
return $atime === null ? null : $atime->getTimestamp();
}
/**
* @return string
*/
public function getAttributes()
{
$externalAttributes = $this->entry->getExternalAttributes();
if ($this->entry->getCreatedOS() === ZipPlatform::OS_UNIX) {
$permission = (($externalAttributes >> 16) & 0xFFFF);
return FileAttribUtil::getUnixMode($permission);
}
return FileAttribUtil::getDosMode($externalAttributes);
}
/**
* @return bool
*/
public function isEncrypted()
{
return $this->entry->isEncrypted();
}
/**
* @return string|null
*/
public function getComment()
{
return $this->entry->getComment();
}
/**
* @return int
*/
public function getCrc()
{
return $this->entry->getCrc();
}
/**
* @return string
*
* @deprecated use \PhpZip\Model\ZipInfo::getMethodName()
*/
public function getMethod()
{
return $this->getMethodName();
}
/**
* @return string
*/
public function getMethodName()
{
return ZipCompressionMethod::getCompressionMethodName($this->entry->getCompressionMethod());
}
/**
* @return string
*/
public function getEncryptionMethodName()
{
return ZipEncryptionMethod::getEncryptionMethodName($this->entry->getEncryptionMethod());
}
/**
* @return string
*/
public function getPlatform()
{
return ZipPlatform::getPlatformName($this->entry->getExtractedOS());
}
/**
* @return int
*/
public function getVersion()
{
return $this->entry->getExtractVersion();
}
/**
* @return int|null
*/
public function getEncryptionMethod()
{
$encryptionMethod = $this->entry->getEncryptionMethod();
return $encryptionMethod === ZipEncryptionMethod::NONE ? null : $encryptionMethod;
}
/**
* @return int|null
*/
public function getCompressionLevel()
{
return $this->entry->getCompressionLevel();
}
/**
* @return int
*/
public function getCompressionMethod()
{
return $this->entry->getCompressionMethod();
}
/**
* @return array
*/
public function toArray()
{
return [
'name' => $this->getName(),
'folder' => $this->isFolder(),
'size' => $this->getSize(),
'compressed_size' => $this->getCompressedSize(),
'modified' => $this->getMtime(),
'created' => $this->getCtime(),
'accessed' => $this->getAtime(),
'attributes' => $this->getAttributes(),
'encrypted' => $this->isEncrypted(),
'encryption_method' => $this->getEncryptionMethod(),
'encryption_method_name' => $this->getEncryptionMethodName(),
'comment' => $this->getComment(),
'crc' => $this->getCrc(),
'method_name' => $this->getMethodName(),
'compression_method' => $this->getCompressionMethod(),
'platform' => $this->getPlatform(),
'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()
. '}';
}
}

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Util;
use PhpZip\Exception\RuntimeException;
@ -9,24 +18,8 @@ use PhpZip\Exception\RuntimeException;
*
* @internal
*/
class CryptoUtil
final class CryptoUtil
{
/**
* Returns random bytes.
*
* @param int $length
*
* @throws \Exception
*
* @return string
*
* @deprecated Use random_bytes()
*/
final public static function randomBytes($length)
{
return random_bytes($length);
}
/**
* Decrypt AES-CTR.
*
@ -36,7 +29,7 @@ class CryptoUtil
*
* @return string Raw data
*/
public static function decryptAesCtr($data, $key, $iv)
public static function decryptAesCtr(string $data, string $key, string $iv): string
{
if (\extension_loaded('openssl')) {
$numBits = \strlen($key) * 8;
@ -44,11 +37,7 @@ class CryptoUtil
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');
}
/**
@ -60,7 +49,7 @@ class CryptoUtil
*
* @return string Encrypted data
*/
public static function encryptAesCtr($data, $key, $iv)
public static function encryptAesCtr(string $data, string $key, string $iv): string
{
if (\extension_loaded('openssl')) {
$numBits = \strlen($key) * 8;
@ -68,10 +57,6 @@ class CryptoUtil
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');
}
}

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Util;
/**
@ -20,9 +29,6 @@ namespace PhpZip\Util;
*
* @see https://docs.microsoft.com/ru-ru/windows/win32/api/winbase/nf-winbase-filetimetodosdatetime?redirectedfrom=MSDN
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*
* @internal
*/
class DateTimeConverter
@ -30,14 +36,18 @@ class DateTimeConverter
/**
* Smallest supported DOS date/time value in a ZIP file,
* which is January 1st, 1980 AD 00:00:00 local time.
*
* @var int
*/
const MIN_DOS_TIME = 0x210000; // (1 << 21) | (1 << 16)
public const MIN_DOS_TIME = (1 << 21) | (1 << 16);
/**
* Largest supported DOS date/time value in a ZIP file,
* which is December 31st, 2107 AD 23:59:58 local time.
*
* @var int
*/
const MAX_DOS_TIME = 0xff9fbf7d; // ((2107 - 1980) << 25) | (12 << 21) | (31 << 16) | (23 << 11) | (59 << 5) | (58 >> 1);
public const MAX_DOS_TIME = ((2107 - 1980) << 25) | (12 << 21) | (31 << 16) | (23 << 11) | (59 << 5) | (58 >> 1);
/**
* Convert a 32 bit integer DOS date/time value to a UNIX timestamp value.
@ -46,7 +56,7 @@ class DateTimeConverter
*
* @return int Unix timestamp
*/
public static function msDosToUnix($dosTime)
public static function msDosToUnix(int $dosTime): int
{
if ($dosTime <= self::MIN_DOS_TIME) {
$dosTime = 0;
@ -74,7 +84,7 @@ class DateTimeConverter
* rounded down to even seconds
* and is in between DateTimeConverter::MIN_DOS_TIME and DateTimeConverter::MAX_DOS_TIME
*/
public static function unixToMsDos($unixTimestamp)
public static function unixToMsDos(int $unixTimestamp): int
{
if ($unixTimestamp < 0) {
throw new \InvalidArgumentException('Negative unix timestamp: ' . $unixTimestamp);
@ -82,12 +92,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) {

View File

@ -1,28 +1,29 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Util;
use PhpZip\Constants\DosAttrs;
use PhpZip\Constants\UnixStat;
/**
* Class FileAttribUtil.
*
* @internal
*/
class FileAttribUtil implements DosAttrs, UnixStat
{
/**
* Get DOS mode,.
*
* @param int $xattr
*
* @return string
* Get DOS mode.
*/
public static function getDosMode($xattr)
public static function getDosMode(int $xattr): string
{
$xattr = (int) $xattr;
$mode = (($xattr & self::DOS_DIRECTORY) === self::DOS_DIRECTORY) ? 'd' : '-';
$mode .= (($xattr & self::DOS_ARCHIVE) === self::DOS_ARCHIVE) ? 'a' : '-';
$mode .= (($xattr & self::DOS_READ_ONLY) === self::DOS_READ_ONLY) ? 'r' : '-';
@ -34,14 +35,11 @@ class FileAttribUtil implements DosAttrs, UnixStat
}
/**
* @param int $permission
*
* @return string
* @noinspection DuplicatedCode
*/
public static function getUnixMode($permission)
public static function getUnixMode(int $permission): string
{
$mode = '';
$permission = (int) $permission;
switch ($permission & self::UNX_IFMT) {
case self::UNX_IFDIR:
$mode .= 'd';

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Util;
use PhpZip\Util\Iterator\IgnoreFilesFilterIterator;
@ -8,9 +17,6 @@ use PhpZip\Util\Iterator\IgnoreFilesRecursiveFilterIterator;
/**
* Files util.
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*
* @internal
*/
final class FilesUtil
@ -19,10 +25,8 @@ final class FilesUtil
* Is empty directory.
*
* @param string $dir Directory
*
* @return bool
*/
public static function isEmptyDir($dir)
public static function isEmptyDir(string $dir): bool
{
if (!is_readable($dir)) {
return false;
@ -36,7 +40,7 @@ final class FilesUtil
*
* @param string $dir directory path
*/
public static function removeDir($dir)
public static function removeDir(string $dir): void
{
$files = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS),
@ -53,12 +57,8 @@ final class FilesUtil
/**
* Convert glob pattern to regex pattern.
*
* @param string $globPattern
*
* @return string
*/
public static function convertGlobToRegEx($globPattern)
public static function convertGlobToRegEx(string $globPattern): string
{
// Remove beginning and ending * globs because they're useless
$globPattern = trim($globPattern, '*');
@ -144,13 +144,9 @@ final class FilesUtil
/**
* Search files.
*
* @param string $inputDir
* @param bool $recursive
* @param array $ignoreFiles
*
* @return array Searched file list
*/
public static function fileSearchWithIgnore($inputDir, $recursive = true, array $ignoreFiles = [])
public static function fileSearchWithIgnore(string $inputDir, bool $recursive = true, array $ignoreFiles = []): array
{
if ($recursive) {
$directoryIterator = new \RecursiveDirectoryIterator($inputDir);
@ -182,16 +178,10 @@ final class FilesUtil
/**
* Search files from glob pattern.
*
* @param string $globPattern
* @param int $flags
* @param bool $recursive
*
* @return array Searched file list
*/
public static function globFileSearch($globPattern, $flags = 0, $recursive = true)
public static function globFileSearch(string $globPattern, int $flags = 0, bool $recursive = true): array
{
$flags = (int) $flags;
$recursive = (bool) $recursive;
$files = glob($globPattern, $flags);
if (!$recursive) {
@ -210,13 +200,9 @@ final class FilesUtil
/**
* Search files from regex pattern.
*
* @param string $folder
* @param string $pattern
* @param bool $recursive
*
* @return array Searched file list
*/
public static function regexFileSearch($folder, $pattern, $recursive = true)
public static function regexFileSearch(string $folder, string $pattern, bool $recursive = true): array
{
if ($recursive) {
$directoryIterator = new \RecursiveDirectoryIterator($folder);
@ -243,10 +229,8 @@ final class FilesUtil
*
* @param int $size Size bytes
* @param string|null $unit Unit support 'GB', 'MB', 'KB'
*
* @return string
*/
public static function humanSize($size, $unit = null)
public static function humanSize(int $size, ?string $unit = null): string
{
if (($unit === null && $size >= 1 << 30) || $unit === 'GB') {
return number_format($size / (1 << 30), 2) . 'GB';
@ -267,18 +251,14 @@ final class FilesUtil
* Normalizes zip path.
*
* @param string $path Zip path
*
* @return string
*/
public static function normalizeZipPath($path)
public static function normalizeZipPath(string $path): string
{
return implode(
\DIRECTORY_SEPARATOR,
array_filter(
explode('/', (string) $path),
static function ($part) {
return $part !== '.' && $part !== '..';
}
explode('/', $path),
static fn ($part) => $part !== '.' && $part !== '..'
)
);
}
@ -288,11 +268,9 @@ final class FilesUtil
*
* @param string $file A file path
*
* @return bool
*
* @see source symfony filesystem component
*/
public static function isAbsolutePath($file)
public static function isAbsolutePath(string $file): bool
{
return strspn($file, '/\\', 0, 1)
|| (
@ -303,14 +281,7 @@ final class FilesUtil
|| parse_url($file, \PHP_URL_SCHEME) !== null;
}
/**
* @param string $target
* @param string $path
* @param bool $allowSymlink
*
* @return bool
*/
public static function symlink($target, $path, $allowSymlink)
public static function symlink(string $target, string $path, bool $allowSymlink): bool
{
if (\DIRECTORY_SEPARATOR === '\\' || !$allowSymlink) {
return file_put_contents($path, $target) !== false;
@ -319,12 +290,7 @@ final class FilesUtil
return symlink($target, $path);
}
/**
* @param string $file
*
* @return bool
*/
public static function isBadCompressionFile($file)
public static function isBadCompressionFile(string $file): bool
{
$badCompressFileExt = [
'dic',
@ -350,12 +316,7 @@ final class FilesUtil
return self::isBadCompressionMimeType($mimeType);
}
/**
* @param string $mimeType
*
* @return bool
*/
public static function isBadCompressionMimeType($mimeType)
public static function isBadCompressionMimeType(string $mimeType): bool
{
static $badDeflateCompMimeTypes = [
'application/epub+zip',
@ -406,21 +367,13 @@ final class FilesUtil
'x-epoc/x-sisx-app',
];
if (\in_array($mimeType, $badDeflateCompMimeTypes, true)) {
return true;
}
return false;
return \in_array($mimeType, $badDeflateCompMimeTypes, true);
}
/**
* @param string $file
*
* @return string
*
* @noinspection PhpComposerExtensionStubsInspection
*/
public static function getMimeTypeFromFile($file)
public static function getMimeTypeFromFile(string $file): string
{
if (\function_exists('mime_content_type')) {
return mime_content_type($file);
@ -430,14 +383,10 @@ final class FilesUtil
}
/**
* @param string $contents
*
* @return string
* @noinspection PhpComposerExtensionStubsInspection
*/
public static function getMimeTypeFromString($contents)
public static function getMimeTypeFromString(string $contents): string
{
$contents = (string) $contents;
$finfo = new \finfo(\FILEINFO_MIME);
$mimeType = $finfo->buffer($contents);

View File

@ -1,28 +1,26 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Util\Iterator;
use PhpZip\Util\StringUtil;
/**
* Iterator for ignore files.
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*/
class IgnoreFilesFilterIterator extends \FilterIterator
{
/**
* Ignore list files.
*
* @var array
*/
private $ignoreFiles = ['..'];
/** Ignore list files. */
private array $ignoreFiles = ['..'];
/**
* @param \Iterator $iterator
* @param array $ignoreFiles
*/
public function __construct(\Iterator $iterator, array $ignoreFiles)
{
parent::__construct($iterator);
@ -35,10 +33,8 @@ class IgnoreFilesFilterIterator extends \FilterIterator
* @see http://php.net/manual/en/filteriterator.accept.php
*
* @return bool true if the current element is acceptable, otherwise false
*
* @since 5.1.0
*/
public function accept()
public function accept(): bool
{
/**
* @var \SplFileInfo $fileInfo

View File

@ -1,28 +1,26 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Util\Iterator;
use PhpZip\Util\StringUtil;
/**
* Recursive iterator for ignore files.
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*/
class IgnoreFilesRecursiveFilterIterator extends \RecursiveFilterIterator
{
/**
* Ignore list files.
*
* @var array
*/
private $ignoreFiles = ['..'];
/** Ignore list files. */
private array $ignoreFiles = ['..'];
/**
* @param \RecursiveIterator $iterator
* @param array $ignoreFiles
*/
public function __construct(\RecursiveIterator $iterator, array $ignoreFiles)
{
parent::__construct($iterator);
@ -35,10 +33,8 @@ class IgnoreFilesRecursiveFilterIterator extends \RecursiveFilterIterator
* @see http://php.net/manual/en/filteriterator.accept.php
*
* @return bool true if the current element is acceptable, otherwise false
*
* @since 5.1.0
*/
public function accept()
public function accept(): bool
{
/**
* @var \SplFileInfo $fileInfo
@ -67,8 +63,9 @@ class IgnoreFilesRecursiveFilterIterator extends \RecursiveFilterIterator
/**
* @return IgnoreFilesRecursiveFilterIterator
*/
public function getChildren()
public function getChildren(): self
{
/** @noinspection PhpPossiblePolymorphicInvocationInspection */
return new self($this->getInnerIterator()->getChildren(), $this->ignoreFiles);
}
}

36
src/Util/MathUtil.php Normal file
View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Util;
/**
* Math util.
*
* @internal
*/
final class MathUtil
{
/**
* Cast to signed int 32-bit.
*/
public static function toSignedInt32(int $int): int
{
if (\PHP_INT_SIZE === 8) {
$int &= 0xffffffff;
if ($int & 0x80000000) {
return $int - 0x100000000;
}
}
return $int;
}
}

View File

@ -1,69 +0,0 @@
<?php
namespace PhpZip\Util;
/**
* Pack util.
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*
* @internal
*/
final class PackUtil
{
/**
* @param int $longValue
*
* @return string
*/
public static function packLongLE($longValue)
{
if (\PHP_VERSION_ID >= 506030) {
return pack('P', $longValue);
}
$left = 0xffffffff00000000;
$right = 0x00000000ffffffff;
$r = ($longValue & $left) >> 32;
$l = $longValue & $right;
return pack('VV', $l, $r);
}
/**
* @param string $value
*
* @return int
*/
public static function unpackLongLE($value)
{
if (\PHP_VERSION_ID >= 506030) {
return unpack('P', $value)[1];
}
$unpack = unpack('Va/Vb', $value);
return $unpack['a'] + ($unpack['b'] << 32);
}
/**
* Cast to signed int 32-bit.
*
* @param int $int
*
* @return int
*/
public static function toSignedInt32($int)
{
if (\PHP_INT_SIZE === 8) {
$int &= 0xffffffff;
if ($int & 0x80000000) {
return $int - 0x100000000;
}
}
return $int;
}
}

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Util;
/**
@ -9,40 +18,18 @@ namespace PhpZip\Util;
*/
final class StringUtil
{
/**
* @param string $haystack
* @param string $needle
*
* @return bool
*/
public static function endsWith($haystack, $needle)
public static function endsWith(string $haystack, string $needle): bool
{
$length = \strlen($needle);
if ($length === 0) {
return true;
}
return substr($haystack, -$length) === $needle;
return $needle === '' || ($haystack !== '' && substr_compare($haystack, $needle, -\strlen($needle)) === 0);
}
/**
* @param string $string
*
* @return bool
*/
public static function isBinary($string)
public static function isBinary(string $string): bool
{
return strpos($string, "\0") !== false;
}
/**
* @param string $name
*
* @return bool
*/
public static function isASCII($name)
public static function isASCII(string $name): bool
{
return preg_match('~[^\x20-\x7e]~', (string) $name) === 0;
return preg_match('~[^\x20-\x7e]~', $name) === 0;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,902 +0,0 @@
<?php
namespace PhpZip;
use PhpZip\Constants\ZipCompressionLevel;
use PhpZip\Constants\ZipCompressionMethod;
use PhpZip\Constants\ZipEncryptionMethod;
use PhpZip\Exception\ZipEntryNotFoundException;
use PhpZip\Exception\ZipException;
use PhpZip\Model\ZipEntry;
use PhpZip\Model\ZipEntryMatcher;
use PhpZip\Model\ZipInfo;
use Psr\Http\Message\ResponseInterface;
use Symfony\Component\Finder\Finder;
/**
* Create, open .ZIP files, modify, get info and extract files.
*
* Implemented support traditional PKWARE encryption and WinZip AES encryption.
* Implemented support ZIP64.
* Support ZipAlign functional.
*
* @see https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT .ZIP File Format Specification
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*
* @deprecated will be removed in version 4.0. Use the {@see ZipFile} class.
*/
interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator
{
/**
* Method for Stored (uncompressed) entries.
*
* @see ZipEntry::setCompressionMethod()
* @deprecated Use {@see ZipCompressionMethod::STORED}
*/
const METHOD_STORED = ZipCompressionMethod::STORED;
/**
* Method for Deflated compressed entries.
*
* @see ZipEntry::setCompressionMethod()
* @deprecated Use {@see ZipCompressionMethod::DEFLATED}
*/
const METHOD_DEFLATED = ZipCompressionMethod::DEFLATED;
/**
* Method for BZIP2 compressed entries.
* Require php extension bz2.
*
* @see ZipEntry::setCompressionMethod()
* @deprecated Use {@see ZipCompressionMethod::BZIP2}
*/
const METHOD_BZIP2 = ZipCompressionMethod::BZIP2;
/**
* @var int default compression level
*
* @deprecated Use {@see ZipCompressionLevel::NORMAL}
*/
const LEVEL_DEFAULT_COMPRESSION = ZipCompressionLevel::NORMAL;
/**
* Compression level for fastest compression.
*
* @deprecated Use {@see ZipCompressionLevel::FAST}
*/
const LEVEL_FAST = ZipCompressionLevel::FAST;
/**
* Compression level for fastest compression.
*
* @deprecated Use {@see ZipCompressionLevel::SUPER_FAST}
*/
const LEVEL_BEST_SPEED = ZipCompressionLevel::SUPER_FAST;
/** @deprecated Use {@see ZipCompressionLevel::SUPER_FAST} */
const LEVEL_SUPER_FAST = ZipCompressionLevel::SUPER_FAST;
/**
* Compression level for best compression.
*
* @deprecated Use {@see ZipCompressionLevel::MAXIMUM}
*/
const LEVEL_BEST_COMPRESSION = ZipCompressionLevel::MAXIMUM;
/**
* No specified method for set encryption method to Traditional PKWARE encryption.
*
* @deprecated Use {@see ZipEncryptionMethod::PKWARE}
*/
const ENCRYPTION_METHOD_TRADITIONAL = ZipEncryptionMethod::PKWARE;
/**
* No specified method for set encryption method to WinZip AES encryption.
* Default value 256 bit.
*
* @deprecated Use {@see ZipEncryptionMethod::WINZIP_AES_256}
*/
const ENCRYPTION_METHOD_WINZIP_AES = ZipEncryptionMethod::WINZIP_AES_256;
/**
* No specified method for set encryption method to WinZip AES encryption 128 bit.
*
* @deprecated Use {@see ZipEncryptionMethod::WINZIP_AES_128}
*/
const ENCRYPTION_METHOD_WINZIP_AES_128 = ZipEncryptionMethod::WINZIP_AES_128;
/**
* No specified method for set encryption method to WinZip AES encryption 194 bit.
*
* @deprecated Use {@see ZipEncryptionMethod::WINZIP_AES_192}
*/
const ENCRYPTION_METHOD_WINZIP_AES_192 = ZipEncryptionMethod::WINZIP_AES_192;
/**
* No specified method for set encryption method to WinZip AES encryption 256 bit.
*
* @deprecated Use {@see ZipEncryptionMethod::WINZIP_AES_256}
*/
const ENCRYPTION_METHOD_WINZIP_AES_256 = ZipEncryptionMethod::WINZIP_AES_256;
/**
* Open zip archive from file.
*
* @param string $filename
* @param array $options
*
* @throws ZipException if can't open file
*
* @return ZipFile
*/
public function openFile($filename, array $options = []);
/**
* Open zip archive from raw string data.
*
* @param string $data
* @param array $options
*
* @throws ZipException if can't open temp stream
*
* @return ZipFile
*/
public function openFromString($data, array $options = []);
/**
* Open zip archive from stream resource.
*
* @param resource $handle
* @param array $options
*
* @throws ZipException
*
* @return ZipFile
*/
public function openFromStream($handle, array $options = []);
/**
* @return string[] returns the list files
*/
public function getListFiles();
/**
* @return int returns the number of entries in this ZIP file
*/
public function count();
/**
* Returns the file comment.
*
* @return string|null the file comment
*/
public function getArchiveComment();
/**
* Set archive comment.
*
* @param string|null $comment
*
* @return ZipFile
*/
public function setArchiveComment($comment = null);
/**
* Checks if there is an entry in the archive.
*
* @param string $entryName
*
* @return bool
*/
public function hasEntry($entryName);
/**
* Returns ZipEntry object.
*
* @param string $entryName
*
* @throws ZipEntryNotFoundException
*
* @return ZipEntry
*/
public function getEntry($entryName);
/**
* Checks that the entry in the archive is a directory.
* Returns true if and only if this ZIP entry represents a directory entry
* (i.e. end with '/').
*
* @param string $entryName
*
* @throws ZipEntryNotFoundException
*
* @return bool
*/
public function isDirectory($entryName);
/**
* Returns entry comment.
*
* @param string $entryName
*
* @throws ZipException
* @throws ZipEntryNotFoundException
*
* @return string
*/
public function getEntryComment($entryName);
/**
* Set entry comment.
*
* @param string $entryName
* @param string|null $comment
*
* @throws ZipEntryNotFoundException
* @throws ZipException
*
* @return ZipFile
*/
public function setEntryComment($entryName, $comment = null);
/**
* Returns the entry contents.
*
* @param string $entryName
*
* @throws ZipEntryNotFoundException
* @throws ZipException
*
* @return string
*/
public function getEntryContents($entryName);
/**
* @param string $entryName
*
* @throws ZipEntryNotFoundException
* @throws ZipException
*
* @return resource
*/
public function getEntryStream($entryName);
/**
* Get info by entry.
*
* @param string|ZipEntry $entryName
*
* @throws ZipException
* @throws ZipEntryNotFoundException
*
* @return ZipInfo
*/
public function getEntryInfo($entryName);
/**
* Get info by all entries.
*
* @return ZipInfo[]
*/
public function getAllInfo();
/**
* @return ZipEntryMatcher
*/
public function matcher();
/**
* Extract the archive contents (unzip).
*
* Extract the complete archive or the given files to the specified destination.
*
* @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
* is present, then the specified
* array will be filled with
* information about the
* extracted entries
*
* @throws ZipException
*
* @return ZipFile
*/
public function extractTo($destDir, $entries = null, array $options = [], &$extractedEntries = []);
/**
* Add entry from the string.
*
* @param string $entryName zip entry name
* @param string $contents string contents
* @param int|null $compressionMethod Compression method.
* Use {@see ZipCompressionMethod::STORED},
* {@see ZipCompressionMethod::DEFLATED} or
* {@see ZipCompressionMethod::BZIP2}.
* If null, then auto choosing method.
*
* @throws ZipException
*
* @return ZipFile
*/
public function addFromString($entryName, $contents, $compressionMethod = null);
/**
* @param Finder $finder
* @param array $options
*
* @throws ZipException
*
* @return ZipEntry[]
*/
public function addFromFinder(Finder $finder, array $options = []);
/**
* @param \SplFileInfo $file
* @param string|null $entryName
* @param array $options
*
* @throws ZipException
*
* @return ZipEntry
*/
public function addSplFile(\SplFileInfo $file, $entryName = null, array $options = []);
/**
* Add entry from the file.
*
* @param string $filename destination file
* @param string|null $entryName zip Entry name
* @param int|null $compressionMethod Compression method.
* Use {@see ZipCompressionMethod::STORED},
* {@see ZipCompressionMethod::DEFLATED} or
* {@see ZipCompressionMethod::BZIP2}.
* If null, then auto choosing method.
*
* @throws ZipException
*
* @return ZipFile
*/
public function addFile($filename, $entryName = null, $compressionMethod = null);
/**
* Add entry from the stream.
*
* @param resource $stream stream resource
* @param string $entryName zip Entry name
* @param int|null $compressionMethod Compression method.
* Use {@see ZipCompressionMethod::STORED},
* {@see ZipCompressionMethod::DEFLATED} or
* {@see ZipCompressionMethod::BZIP2}.
* If null, then auto choosing method.
*
* @throws ZipException
*
* @return ZipFile
*/
public function addFromStream($stream, $entryName, $compressionMethod = null);
/**
* Add an empty directory in the zip archive.
*
* @param string $dirName
*
* @throws ZipException
*
* @return ZipFile
*/
public function addEmptyDir($dirName);
/**
* Add directory not recursively to the zip archive.
*
* @param string $inputDir Input directory
* @param string $localPath add files to this directory, or the root
* @param int|null $compressionMethod Compression method.
*
* Use {@see ZipCompressionMethod::STORED}, {@see
* ZipCompressionMethod::DEFLATED} or
* {@see ZipCompressionMethod::BZIP2}. If null, then auto choosing method.
*
* @throws ZipException
*
* @return ZipFile
*/
public function addDir($inputDir, $localPath = '/', $compressionMethod = null);
/**
* Add recursive directory to the zip archive.
*
* @param string $inputDir Input directory
* @param string $localPath add files to this directory, or the root
* @param int|null $compressionMethod Compression method.
* Use {@see ZipCompressionMethod::STORED}, {@see
* ZipCompressionMethod::DEFLATED} or
* {@see ZipCompressionMethod::BZIP2}. If null, then auto choosing method.
*
* @throws ZipException
*
* @return ZipFile
*
* @see ZipCompressionMethod::STORED
* @see ZipCompressionMethod::DEFLATED
* @see ZipCompressionMethod::BZIP2
*/
public function addDirRecursive($inputDir, $localPath = '/', $compressionMethod = null);
/**
* Add directories from directory iterator.
*
* @param \Iterator $iterator directory iterator
* @param string $localPath add files to this directory, or the root
* @param int|null $compressionMethod Compression method.
* Use {@see ZipCompressionMethod::STORED}, {@see
* ZipCompressionMethod::DEFLATED} or
* {@see ZipCompressionMethod::BZIP2}. If null, then auto choosing method.
*
* @throws ZipException
*
* @return ZipFile
*
* @see ZipCompressionMethod::STORED
* @see ZipCompressionMethod::DEFLATED
* @see ZipCompressionMethod::BZIP2
*/
public function addFilesFromIterator(\Iterator $iterator, $localPath = '/', $compressionMethod = null);
/**
* Add files from glob pattern.
*
* @param string $inputDir Input directory
* @param string $globPattern glob pattern
* @param string $localPath add files to this directory, or the root
* @param int|null $compressionMethod Compression method.
* Use {@see ZipCompressionMethod::STORED},
* {@see ZipCompressionMethod::DEFLATED} or
* {@see ZipCompressionMethod::BZIP2}. If null, then auto choosing method.
*
* @throws ZipException
*
* @return ZipFile
* @sse https://en.wikipedia.org/wiki/Glob_(programming) Glob pattern syntax
*/
public function addFilesFromGlob($inputDir, $globPattern, $localPath = '/', $compressionMethod = null);
/**
* Add files recursively from glob pattern.
*
* @param string $inputDir Input directory
* @param string $globPattern glob pattern
* @param string $localPath add files to this directory, or the root
* @param int|null $compressionMethod Compression method.
* Use {@see ZipCompressionMethod::STORED},
* {@see ZipCompressionMethod::DEFLATED} or
* {@see ZipCompressionMethod::BZIP2}. If null, then auto choosing method.
*
* @throws ZipException
*
* @return ZipFile
* @sse https://en.wikipedia.org/wiki/Glob_(programming) Glob pattern syntax
*/
public function addFilesFromGlobRecursive($inputDir, $globPattern, $localPath = '/', $compressionMethod = null);
/**
* Add files from regex pattern.
*
* @param string $inputDir search files in this directory
* @param string $regexPattern regex pattern
* @param string $localPath add files to this directory, or the root
* @param int|null $compressionMethod Compression method.
* Use {@see ZipCompressionMethod::STORED},
* {@see ZipCompressionMethod::DEFLATED} or
* {@see ZipCompressionMethod::BZIP2}. If null, then auto choosing method.
*
* @throws ZipException
*
* @return ZipFile
*
* @internal param bool $recursive Recursive search
*/
public function addFilesFromRegex($inputDir, $regexPattern, $localPath = '/', $compressionMethod = null);
/**
* Add files recursively from regex pattern.
*
* @param string $inputDir search files in this directory
* @param string $regexPattern regex pattern
* @param string $localPath add files to this directory, or the root
* @param int|null $compressionMethod Compression method.
* Use {@see ZipCompressionMethod::STORED},
* {@see ZipCompressionMethod::DEFLATED} or
* {@see ZipCompressionMethod::BZIP2}. If null, then auto choosing method.
*
* @throws ZipException
*
* @return ZipFile
*
* @internal param bool $recursive Recursive search
*/
public function addFilesFromRegexRecursive($inputDir, $regexPattern, $localPath = '/', $compressionMethod = null);
/**
* Add array data to archive.
* Keys is local names.
* Values is contents.
*
* @param array $mapData associative array for added to zip
*/
public function addAll(array $mapData);
/**
* Rename the entry.
*
* @param string $oldName old entry name
* @param string $newName new entry name
*
* @throws ZipException
*
* @return ZipFile
*/
public function rename($oldName, $newName);
/**
* Delete entry by name.
*
* @param string $entryName zip Entry name
*
* @throws ZipEntryNotFoundException if entry not found
*
* @return ZipFile
*/
public function deleteFromName($entryName);
/**
* Delete entries by glob pattern.
*
* @param string $globPattern Glob pattern
*
* @return ZipFile
* @sse https://en.wikipedia.org/wiki/Glob_(programming) Glob pattern syntax
*/
public function deleteFromGlob($globPattern);
/**
* Delete entries by regex pattern.
*
* @param string $regexPattern Regex pattern
*
* @return ZipFile
*/
public function deleteFromRegex($regexPattern);
/**
* Delete all entries.
*
* @return ZipFile
*/
public function deleteAll();
/**
* Set compression level for new entries.
*
* @param int $compressionLevel
*
* @return ZipFile
*
* @see ZipCompressionLevel::NORMAL
* @see ZipCompressionLevel::SUPER_FAST
* @see ZipCompressionLevel::FAST
* @see ZipCompressionLevel::MAXIMUM
*/
public function setCompressionLevel($compressionLevel = ZipCompressionLevel::NORMAL);
/**
* @param string $entryName
* @param int $compressionLevel
*
* @throws ZipException
*
* @return ZipFile
*
* @see ZipCompressionLevel::NORMAL
* @see ZipCompressionLevel::SUPER_FAST
* @see ZipCompressionLevel::FAST
* @see ZipCompressionLevel::MAXIMUM
*/
public function setCompressionLevelEntry($entryName, $compressionLevel);
/**
* @param string $entryName
* @param int $compressionMethod Compression method.
* Use {@see ZipCompressionMethod::STORED}, {@see ZipCompressionMethod::DEFLATED}
* or
* {@see ZipCompressionMethod::BZIP2}. If null, then auto choosing method.
*
* @throws ZipException
*
* @return ZipFile
*
* @see ZipCompressionMethod::STORED
* @see ZipCompressionMethod::DEFLATED
* @see ZipCompressionMethod::BZIP2
*/
public function setCompressionMethodEntry($entryName, $compressionMethod);
/**
* zipalign is optimization to Android application (APK) files.
*
* @param int|null $align
*
* @return ZipFile
*
* @see https://developer.android.com/studio/command-line/zipalign.html
*/
public function setZipAlign($align = null);
/**
* Set password to all input encrypted entries.
*
* @param string $password Password
*
* @return ZipFile
*/
public function setReadPassword($password);
/**
* Set password to concrete input entry.
*
* @param string $entryName
* @param string $password Password
*
* @throws ZipException
*
* @return ZipFile
*/
public function setReadPasswordEntry($entryName, $password);
/**
* Sets a new password for all files in the archive.
*
* @param string $password Password
* @param int|null $encryptionMethod Encryption method
*
* @return ZipFile
*/
public function setPassword($password, $encryptionMethod = ZipEncryptionMethod::WINZIP_AES_256);
/**
* Sets a new password of an entry defined by its name.
*
* @param string $entryName
* @param string $password
* @param int|null $encryptionMethod
*
* @throws ZipException
*
* @return ZipFile
*/
public function setPasswordEntry($entryName, $password, $encryptionMethod = null);
/**
* Disable encryption for all entries that are already in the archive.
*
* @return ZipFile
*/
public function disableEncryption();
/**
* Disable encryption of an entry defined by its name.
*
* @param string $entryName
*
* @return ZipFile
*/
public function disableEncryptionEntry($entryName);
/**
* Undo all changes done in the archive.
*
* @return ZipFile
*/
public function unchangeAll();
/**
* Undo change archive comment.
*
* @return ZipFile
*/
public function unchangeArchiveComment();
/**
* Revert all changes done to an entry with the given name.
*
* @param string|ZipEntry $entry Entry name or ZipEntry
*
* @return ZipFile
*/
public function unchangeEntry($entry);
/**
* Save as file.
*
* @param string $filename Output filename
*
* @throws ZipException
*
* @return ZipFile
*/
public function saveAsFile($filename);
/**
* Save as stream.
*
* @param resource $handle Output stream resource
*
* @throws ZipException
*
* @return ZipFile
*/
public function saveAsStream($handle);
/**
* Output .ZIP archive as attachment.
* Die after output.
*
* @param string $outputFilename Output filename
* @param string|null $mimeType Mime-Type
* @param bool $attachment Http Header 'Content-Disposition' if true then attachment otherwise inline
*
* @throws ZipException
*/
public function outputAsAttachment($outputFilename, $mimeType = null, $attachment = true);
/**
* Output .ZIP archive as PSR-7 Response.
*
* @param ResponseInterface $response Instance PSR-7 Response
* @param string $outputFilename Output filename
* @param string|null $mimeType Mime-Type
* @param bool $attachment Http Header 'Content-Disposition' if true then attachment otherwise inline
*
* @throws ZipException
*
* @return ResponseInterface
*/
public function outputAsResponse(
ResponseInterface $response,
$outputFilename,
$mimeType = null,
$attachment = true
);
/**
* Returns the zip archive as a string.
*
* @throws ZipException
*
* @return string
*/
public function outputAsString();
/**
* Close zip archive and release input stream.
*/
public function close();
/**
* Save and reopen zip archive.
*
* @throws ZipException
*
* @return ZipFile
*/
public function rewrite();
/**
* Offset to set.
*
* @see http://php.net/manual/en/arrayaccess.offsetset.php
*
* @param string $entryName the offset to assign the value to
* @param string|\DirectoryIterator|\SplFileInfo|resource $contents the value to set
*
* @throws ZipException
*
* @see ZipFile::addFromString
* @see ZipFile::addEmptyDir
* @see ZipFile::addFile
* @see ZipFile::addFilesFromIterator
*/
public function offsetSet($entryName, $contents);
/**
* Offset to unset.
*
* @see http://php.net/manual/en/arrayaccess.offsetunset.php
*
* @param string $entryName the offset to unset
*
* @throws ZipEntryNotFoundException
*/
public function offsetUnset($entryName);
/**
* Return the current element.
*
* @see http://php.net/manual/en/iterator.current.php
*
* @throws ZipException
*
* @return mixed can return any type
*
* @since 5.0.0
*/
public function current();
/**
* Offset to retrieve.
*
* @see http://php.net/manual/en/arrayaccess.offsetget.php
*
* @param string $entryName the offset to retrieve
*
* @throws ZipException
*
* @return string|null
*/
public function offsetGet($entryName);
/**
* Return the key of the current element.
*
* @see http://php.net/manual/en/iterator.key.php
*
* @return mixed scalar on success, or null on failure
*
* @since 5.0.0
*/
public function key();
/**
* Move forward to next element.
*
* @see http://php.net/manual/en/iterator.next.php
* @since 5.0.0
*/
public function next();
/**
* Checks if current position is valid.
*
* @see http://php.net/manual/en/iterator.valid.php
*
* @return bool The return value will be casted to boolean and then evaluated.
* Returns true on success or false on failure.
*
* @since 5.0.0
*/
public function valid();
/**
* Whether a offset exists.
*
* @see http://php.net/manual/en/arrayaccess.offsetexists.php
*
* @param string $entryName an offset to check for
*
* @return bool true on success or false on failure.
* The return value will be casted to boolean if non-boolean was returned.
*/
public function offsetExists($entryName);
/**
* Rewind the Iterator to the first element.
*
* @see http://php.net/manual/en/iterator.rewind.php
* @since 5.0.0
*/
public function rewind();
}

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests;
use PhpZip\Exception\ZipEntryNotFoundException;
@ -26,7 +35,7 @@ final class CustomZipFormatTest extends ZipTestCase
*
* @see http://www.epubtest.org/test-books source epub files
*/
public function testEpub()
public function testEpub(): void
{
$epubFile = new EpubFile();
$epubFile->openFile(__DIR__ . '/resources/Advanced-v1.0.0.epub');
@ -67,7 +76,7 @@ final class CustomZipFormatTest extends ZipTestCase
/**
* @throws \Exception
*/
public function testBeforeSaveInZipWriter()
public function testBeforeSaveInZipWriter(): void
{
$zipFile = new ZipFileCustomWriter();
for ($i = 0; $i < 10; $i++) {
@ -88,7 +97,7 @@ final class CustomZipFormatTest extends ZipTestCase
/**
* @throws \Exception
*/
public function testBeforeSaveInZipFile()
public function testBeforeSaveInZipFile(): void
{
$zipFile = new ZipFileWithBeforeSave();
for ($i = 0; $i < 10; $i++) {
@ -106,11 +115,7 @@ final class CustomZipFormatTest extends ZipTestCase
$zipFile->close();
}
/**
* @param ZipFile $zipFile
* @param bool $exists
*/
private function existsExtraFields(ZipFile $zipFile, $exists)
private function existsExtraFields(ZipFile $zipFile, bool $exists): void
{
foreach ($zipFile->getEntries() as $entry) {
$localExtras = $entry->getLocalExtraFields();

View File

@ -1,6 +1,13 @@
<?php
/** @noinspection PhpUndefinedMethodInspection */
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Extra\Fields;
@ -8,32 +15,22 @@ use PHPUnit\Framework\TestCase;
use PhpZip\Exception\ZipException;
use PhpZip\Model\Extra\Fields\AbstractUnicodeExtraField;
/**
* Class AbstractUnicodeExtraFieldTest.
*/
abstract class AbstractUnicodeExtraFieldTest extends TestCase
{
/**
* @return string|AbstractUnicodeExtraField
*
* @psalm-var class-string<\PhpZip\Model\Extra\Fields\AbstractUnicodeExtraField>
* @psalm-var class-string<AbstractUnicodeExtraField>
*/
abstract protected function getUnicodeExtraFieldClassName();
/**
* @dataProvider provideExtraField
*
* @param int $crc32
* @param string $unicodePath
* @param string $originalPath
* @param string $binaryData
*
* @throws ZipException
*/
public function testExtraField($crc32, $unicodePath, $originalPath, $binaryData)
public function testExtraField(int $crc32, string $unicodePath, string $originalPath, string $binaryData): void
{
$crc32 = (int) $crc32; // for php 32-bit
$className = $this->getUnicodeExtraFieldClassName();
/** @var AbstractUnicodeExtraField $extraField */
@ -48,12 +45,9 @@ abstract class AbstractUnicodeExtraFieldTest extends TestCase
static::assertEquals($className::unpackCentralDirData($binaryData), $extraField);
}
/**
* @return array
*/
abstract public function provideExtraField();
abstract public function provideExtraField(): array;
public function testSetter()
public function testSetter(): void
{
$className = $this->getUnicodeExtraFieldClassName();
$entryName = '11111';
@ -74,12 +68,10 @@ abstract class AbstractUnicodeExtraFieldTest extends TestCase
/**
* @throws ZipException
*/
public function testUnicodeErrorParse()
public function testUnicodeErrorParse(): void
{
$this->expectException(
ZipException::class,
'Unicode path extra data must have at least 5 bytes.'
);
$this->expectException(ZipException::class);
$this->expectExceptionMessage('Unicode path extra data must have at least 5 bytes.');
$className = $this->getUnicodeExtraFieldClassName();
$className::unpackLocalFileData('');
@ -88,12 +80,10 @@ abstract class AbstractUnicodeExtraFieldTest extends TestCase
/**
* @throws ZipException
*/
public function testUnknownVersionParse()
public function testUnknownVersionParse(): void
{
$this->expectException(
ZipException::class,
'Unsupported version [2] for Unicode path extra data.'
);
$this->expectException(ZipException::class);
$this->expectExceptionMessage('Unsupported version [2] for Unicode path extra data.');
$className = $this->getUnicodeExtraFieldClassName();
$className::unpackLocalFileData("\x02\x04a\xD28\xC3\xA4\\\xC3\xBC.txt");

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Extra\Fields;
use PHPUnit\Framework\TestCase;
@ -16,19 +25,14 @@ final class ApkAlignmentExtraFieldTest extends TestCase
/**
* @dataProvider provideExtraField
*
* @param int $multiple
* @param int $padding
* @param string $binaryData
* @param string $toString
*
* @throws ZipException
*/
public function testExtraField(
$multiple,
$padding,
$binaryData,
$toString
) {
int $multiple,
int $padding,
string $binaryData,
string $toString
): void {
$extraField = new ApkAlignmentExtraField($multiple, $padding);
self::assertSame($extraField->getHeaderId(), ApkAlignmentExtraField::HEADER_ID);
self::assertSame($extraField->getMultiple(), $multiple);
@ -43,10 +47,7 @@ final class ApkAlignmentExtraFieldTest extends TestCase
self::assertSame((string) $extraField, $toString);
}
/**
* @return array
*/
public function provideExtraField()
public function provideExtraField(): array
{
return [
[
@ -82,7 +83,7 @@ final class ApkAlignmentExtraFieldTest extends TestCase
];
}
public function testSetter()
public function testSetter(): void
{
$extraField = new ApkAlignmentExtraField(ApkAlignmentExtraField::ALIGNMENT_BYTES, 3);
$extraField->setMultiple(ApkAlignmentExtraField::COMMON_PAGE_ALIGNMENT_BYTES);
@ -94,12 +95,10 @@ final class ApkAlignmentExtraFieldTest extends TestCase
/**
* @throws ZipException
*/
public function testInvalidParse()
public function testInvalidParse(): void
{
$this->expectException(
ZipException::class,
'Minimum 6 bytes of the extensible data block/field used for alignment of uncompressed entries.'
);
$this->expectException(ZipException::class);
$this->expectExceptionMessage('Minimum 6 bytes of the extensible data block/field used for alignment of uncompressed entries.');
ApkAlignmentExtraField::unpackLocalFileData("\x04");
}

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Extra\Fields;
use PHPUnit\Framework\TestCase;
@ -17,15 +26,9 @@ final class AsiExtraFieldTest extends TestCase
/**
* @dataProvider provideExtraField
*
* @param int $mode
* @param int $uid
* @param int $gid
* @param string $link
* @param string $binaryData
*
* @throws ZipException
*/
public function testExtraField($mode, $uid, $gid, $link, $binaryData)
public function testExtraField(int $mode, int $uid, int $gid, string $link, string $binaryData): void
{
$asiExtraField = new AsiExtraField($mode, $uid, $gid, $link);
self::assertSame($asiExtraField->getHeaderId(), AsiExtraField::HEADER_ID);
@ -42,10 +45,7 @@ final class AsiExtraFieldTest extends TestCase
self::assertEquals(AsiExtraField::unpackCentralDirData($binaryData), $asiExtraField);
}
/**
* @return array
*/
public function provideExtraField()
public function provideExtraField(): array
{
return [
[
@ -65,7 +65,7 @@ final class AsiExtraFieldTest extends TestCase
];
}
public function testSetter()
public function testSetter(): void
{
$extraField = new AsiExtraField(0777);
$extraField->setMode(0100666);
@ -89,12 +89,10 @@ final class AsiExtraFieldTest extends TestCase
/**
* @throws Crc32Exception
*/
public function testInvalidParse()
public function testInvalidParse(): void
{
$this->expectException(
Crc32Exception::class,
'Asi Unix Extra Filed Data (expected CRC32 value'
);
$this->expectException(Crc32Exception::class);
$this->expectExceptionMessage('Asi Unix Extra Filed Data (expected CRC32 value');
AsiExtraField::unpackLocalFileData("\x01\x06\\\xF6\xEDA\x00\x00\x00\x00\xE8\x03\xE8\x03");
}

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Extra\Fields;
use PHPUnit\Framework\TestCase;
@ -17,23 +26,20 @@ final class ExtendedTimestampExtraFieldTest extends TestCase
/**
* @dataProvider provideExtraField
*
* @param int $flags
* @param int|null $modifyTime
* @param int|null $accessTime
* @param int|null $createTime
* @param string $localData
* @param string $cdData
*
* @noinspection PhpTooManyParametersInspection
*
* @param ?int $modifyTime
* @param ?int $accessTime
* @param ?int $createTime
*/
public function testExtraField(
$flags,
$modifyTime,
$accessTime,
$createTime,
$localData,
$cdData
) {
int $flags,
?int $modifyTime,
?int $accessTime,
?int $createTime,
string $localData,
string $cdData
): void {
$localExtraField = new ExtendedTimestampExtraField($flags, $modifyTime, $accessTime, $createTime);
self::assertSame($localExtraField->getHeaderId(), ExtendedTimestampExtraField::HEADER_ID);
self::assertSame($localExtraField->getFlags(), $flags);
@ -59,16 +65,13 @@ final class ExtendedTimestampExtraFieldTest extends TestCase
self::assertSame($localExtraField->packCentralDirData(), $cdData);
}
/**
* @return array
*/
public function provideExtraField()
public function provideExtraField(): array
{
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 +79,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,
@ -98,7 +101,7 @@ final class ExtendedTimestampExtraFieldTest extends TestCase
/**
* @throws \Exception
*/
public function testSetter()
public function testSetter(): void
{
$mtime = time();
$atime = null;
@ -115,8 +118,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 +130,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 +144,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);

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Extra\Fields;
use PHPUnit\Framework\TestCase;
@ -18,7 +27,7 @@ final class JarMarkerExtraFieldTest extends TestCase
/**
* @throws ZipException
*/
public function testExtraField()
public function testExtraField(): void
{
$jarField = new JarMarkerExtraField();
self::assertSame('', $jarField->packLocalFileData());
@ -30,12 +39,10 @@ final class JarMarkerExtraFieldTest extends TestCase
/**
* @throws ZipException
*/
public function testInvalidUnpackLocalData()
public function testInvalidUnpackLocalData(): void
{
$this->expectException(
ZipException::class,
"JarMarker doesn't expect any data"
);
$this->expectException(ZipException::class);
$this->expectExceptionMessage("JarMarker doesn't expect any data");
JarMarkerExtraField::unpackLocalFileData("\x02\x00\00");
}
@ -43,12 +50,10 @@ final class JarMarkerExtraFieldTest extends TestCase
/**
* @throws ZipException
*/
public function testInvalidUnpackCdData()
public function testInvalidUnpackCdData(): void
{
$this->expectException(
ZipException::class,
"JarMarker doesn't expect any data"
);
$this->expectException(ZipException::class);
$this->expectExceptionMessage("JarMarker doesn't expect any data");
JarMarkerExtraField::unpackCentralDirData("\x02\x00\00");
}

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Extra\Fields;
use PHPUnit\Framework\TestCase;
@ -18,14 +27,9 @@ final class NewUnixExtraFieldTest extends TestCase
/**
* @dataProvider provideExtraField
*
* @param int $version
* @param int $uid
* @param int $gid
* @param string $binaryData
*
* @throws ZipException
*/
public function testExtraField($version, $uid, $gid, $binaryData)
public function testExtraField(int $version, int $uid, int $gid, string $binaryData): void
{
$extraField = new NewUnixExtraField($version, $uid, $gid);
self::assertSame($extraField->getHeaderId(), NewUnixExtraField::HEADER_ID);
@ -40,10 +44,7 @@ final class NewUnixExtraFieldTest extends TestCase
self::assertSame($extraField->packCentralDirData(), $binaryData);
}
/**
* @return array
*/
public function provideExtraField()
public function provideExtraField(): array
{
return [
[
@ -79,7 +80,7 @@ final class NewUnixExtraFieldTest extends TestCase
];
}
public function testSetter()
public function testSetter(): void
{
$extraField = new NewUnixExtraField(1, 1000, 1000);
self::assertSame(1, $extraField->getVersion());

View File

@ -1,13 +1,20 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Extra\Fields;
use PHPUnit\Framework\TestCase;
use PhpZip\Model\Extra\Fields\NtfsExtraField;
/**
* Class NtfsExtraFieldTest.
*
* @internal
*
* @small
@ -24,27 +31,19 @@ final class NtfsExtraFieldTest extends TestCase
/**
* @dataProvider provideExtraField
*
* @param int $modifyNtfsTime
* @param int $accessNtfsTime
* @param int $createNtfsTime
* @param float $modifyTimestamp
* @param float $accessTimestamp
* @param float $createTimestamp
* @param string $binaryData
*
* @throws \Exception
*
* @noinspection PhpTooManyParametersInspection
*/
public function testExtraField(
$modifyNtfsTime,
$accessNtfsTime,
$createNtfsTime,
$modifyTimestamp,
$accessTimestamp,
$createTimestamp,
$binaryData
) {
int $modifyNtfsTime,
int $accessNtfsTime,
int $createNtfsTime,
float $modifyTimestamp,
float $accessTimestamp,
float $createTimestamp,
string $binaryData
): void {
$extraField = new NtfsExtraField($modifyNtfsTime, $accessNtfsTime, $createNtfsTime);
self::assertSame($extraField->getHeaderId(), NtfsExtraField::HEADER_ID);
@ -64,15 +63,24 @@ final class NtfsExtraFieldTest extends TestCase
$extraField->getCreateDateTime()
);
self::assertEqualsIntegerWithDelta($extraFieldFromDateTime->getModifyNtfsTime(), $extraField->getModifyNtfsTime(), 100);
self::assertEqualsIntegerWithDelta($extraFieldFromDateTime->getAccessNtfsTime(), $extraField->getAccessNtfsTime(), 100);
self::assertEqualsIntegerWithDelta($extraFieldFromDateTime->getCreateNtfsTime(), $extraField->getCreateNtfsTime(), 100);
self::assertEqualsIntegerWithDelta(
$extraFieldFromDateTime->getModifyNtfsTime(),
$extraField->getModifyNtfsTime(),
100
);
self::assertEqualsIntegerWithDelta(
$extraFieldFromDateTime->getAccessNtfsTime(),
$extraField->getAccessNtfsTime(),
100
);
self::assertEqualsIntegerWithDelta(
$extraFieldFromDateTime->getCreateNtfsTime(),
$extraField->getCreateNtfsTime(),
100
);
}
/**
* @return array
*/
public function provideExtraField()
public function provideExtraField(): array
{
return [
[
@ -105,18 +113,12 @@ final class NtfsExtraFieldTest extends TestCase
];
}
/**
* @param int $expected
* @param int $actual
* @param int $delta
* @param string $message
*/
private static function assertEqualsIntegerWithDelta(
$expected,
$actual,
$delta,
$message = ''
) {
int $expected,
int $actual,
int $delta,
string $message = ''
): void {
self::assertSame(
self::roundInt($expected, $delta),
self::roundInt($actual, $delta),
@ -124,13 +126,7 @@ final class NtfsExtraFieldTest extends TestCase
);
}
/**
* @param int $number
* @param int $delta
*
* @return int
*/
private static function roundInt($number, $delta)
private static function roundInt(int $number, int $delta): int
{
return (int) (floor($number / $delta) * $delta);
}
@ -138,27 +134,19 @@ final class NtfsExtraFieldTest extends TestCase
/**
* @dataProvider provideExtraField
*
* @param int $mtimeNtfs
* @param int $atimeNtfs
* @param int $ctimeNtfs
* @param float $mtimeTimestamp
* @param float $atimeTimestamp
* @param float $ctimeTimestamp
*
* @noinspection PhpTooManyParametersInspection
* @noinspection PhpUnitDeprecationsInspection
*/
public function testConverter(
$mtimeNtfs,
$atimeNtfs,
$ctimeNtfs,
$mtimeTimestamp,
$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);
int $mtimeNtfs,
int $atimeNtfs,
int $ctimeNtfs,
float $mtimeTimestamp,
float $atimeTimestamp,
float $ctimeTimestamp
): void {
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);
@ -168,7 +156,7 @@ final class NtfsExtraFieldTest extends TestCase
/**
* @throws \Exception
*/
public function testSetter()
public function testSetter(): void
{
$timeZone = new \DateTimeZone('UTC');
$initDateTime = new \DateTimeImmutable('-1 min', $timeZone);

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Extra\Fields;
use PHPUnit\Framework\TestCase;
@ -17,25 +26,23 @@ final class OldUnixExtraFieldTest extends TestCase
/**
* @dataProvider provideExtraField
*
* @param int|null $accessTime
* @param int|null $modifyTime
* @param int|null $uid
* @param int|null $gid
* @param string $localBinaryData
* @param string $cdBinaryData
*
* @noinspection PhpTooManyParametersInspection
*
* @param ?int $accessTime
* @param ?int $modifyTime
* @param ?int $uid
* @param ?int $gid
*
* @throws \Exception
*/
public function testExtraField(
$accessTime,
$modifyTime,
$uid,
$gid,
$localBinaryData,
$cdBinaryData
) {
?int $accessTime,
?int $modifyTime,
?int $uid,
?int $gid,
string $localBinaryData,
string $cdBinaryData
): void {
$extraField = new OldUnixExtraField($accessTime, $modifyTime, $uid, $gid);
self::assertSame($extraField->getHeaderId(), OldUnixExtraField::HEADER_ID);
@ -89,10 +96,7 @@ final class OldUnixExtraFieldTest extends TestCase
self::assertSame($extraField->packCentralDirData(), $cdBinaryData);
}
/**
* @return array
*/
public function provideExtraField()
public function provideExtraField(): array
{
return [
[
@ -130,7 +134,7 @@ final class OldUnixExtraFieldTest extends TestCase
];
}
public function testSetter()
public function testSetter(): void
{
$extraField = new OldUnixExtraField(null, null, null, null);

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Extra\Fields;
use PhpZip\Model\Extra\Fields\UnicodeCommentExtraField;
@ -19,10 +28,7 @@ final class UnicodeCommentExtraFieldTest extends AbstractUnicodeExtraFieldTest
return UnicodeCommentExtraField::class;
}
/**
* @return array
*/
public function provideExtraField()
public function provideExtraField(): array
{
return [
[

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Extra\Fields;
use PhpZip\Model\Extra\Fields\UnicodePathExtraField;
@ -21,10 +30,7 @@ final class UnicodePathExtraFieldTest extends AbstractUnicodeExtraFieldTest
return UnicodePathExtraField::class;
}
/**
* @return array
*/
public function provideExtraField()
public function provideExtraField(): array
{
return [
[

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Extra\Fields;
use PHPUnit\Framework\TestCase;
@ -15,7 +24,7 @@ use PhpZip\Model\Extra\Fields\UnrecognizedExtraField;
*/
final class UnrecognizedExtraFieldTest extends TestCase
{
public function testExtraField()
public function testExtraField(): void
{
$headerId = 0xF00D;
$binaryData = "\x01\x02\x03\x04\x05";
@ -35,22 +44,18 @@ final class UnrecognizedExtraFieldTest extends TestCase
self::assertSame($unrecognizedExtraField->packCentralDirData(), $newBinaryData);
}
public function testUnpackLocalData()
public function testUnpackLocalData(): void
{
$this->expectException(
RuntimeException::class,
'Unsupport parse'
);
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Unsupport parse');
UnrecognizedExtraField::unpackLocalFileData("\x01\x02");
}
public function testUnpackCentralDirData()
public function testUnpackCentralDirData(): void
{
$this->expectException(
RuntimeException::class,
'Unsupport parse'
);
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Unsupport parse');
UnrecognizedExtraField::unpackCentralDirData("\x01\x02");
}

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Extra\Fields;
use PHPUnit\Framework\TestCase;
@ -20,22 +29,16 @@ final class WinZipAesExtraFieldTest extends TestCase
/**
* @dataProvider provideExtraField
*
* @param int $vendorVersion
* @param int $keyStrength
* @param int $compressionMethod
* @param int $saltSize
* @param string $binaryData
*
* @throws ZipException
* @throws ZipUnsupportMethodException
*/
public function testExtraField(
$vendorVersion,
$keyStrength,
$compressionMethod,
$saltSize,
$binaryData
) {
int $vendorVersion,
int $keyStrength,
int $compressionMethod,
int $saltSize,
string $binaryData
): void {
$extraField = new WinZipAesExtraField($vendorVersion, $keyStrength, $compressionMethod);
self::assertSame($extraField->getHeaderId(), WinZipAesExtraField::HEADER_ID);
self::assertSame($extraField->getVendorVersion(), $vendorVersion);
@ -50,10 +53,7 @@ final class WinZipAesExtraFieldTest extends TestCase
self::assertEquals(WinZipAesExtraField::unpackCentralDirData($binaryData), $extraField);
}
/**
* @return array
*/
public function provideExtraField()
public function provideExtraField(): array
{
return [
[
@ -104,7 +104,7 @@ final class WinZipAesExtraFieldTest extends TestCase
/**
* @throws ZipUnsupportMethodException
*/
public function testSetter()
public function testSetter(): void
{
$extraField = new WinZipAesExtraField(
WinZipAesExtraField::VERSION_AE1,
@ -155,9 +155,10 @@ final class WinZipAesExtraFieldTest extends TestCase
/**
* @throws ZipUnsupportMethodException
*/
public function testConstructUnsupportVendorVersion()
public function testConstructUnsupportVendorVersion(): void
{
$this->expectException(InvalidArgumentException::class, 'Unsupport WinZip AES vendor version: 3');
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Unsupport WinZip AES vendor version: 3');
new WinZipAesExtraField(
3,
@ -166,12 +167,10 @@ final class WinZipAesExtraFieldTest extends TestCase
);
}
/**
* @throws ZipUnsupportMethodException
*/
public function testSetterUnsupportVendorVersion()
public function testSetterUnsupportVendorVersion(): void
{
$this->expectException(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,
@ -181,12 +180,10 @@ final class WinZipAesExtraFieldTest extends TestCase
$extraField->setVendorVersion(3);
}
/**
* @throws ZipUnsupportMethodException
*/
public function testConstructUnsupportCompressionMethod()
public function testConstructUnsupportCompressionMethod(): void
{
$this->expectException(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,
@ -195,12 +192,10 @@ final class WinZipAesExtraFieldTest extends TestCase
);
}
/**
* @throws ZipUnsupportMethodException
*/
public function testSetterUnsupportCompressionMethod()
public function testSetterUnsupportCompressionMethod(): void
{
$this->expectException(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,
@ -213,9 +208,10 @@ final class WinZipAesExtraFieldTest extends TestCase
/**
* @throws ZipUnsupportMethodException
*/
public function testConstructUnsupportKeyStrength()
public function testConstructUnsupportKeyStrength(): void
{
$this->expectException(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,
@ -225,11 +221,12 @@ final class WinZipAesExtraFieldTest extends TestCase
}
/**
* @throws ZipUnsupportMethodException
* @throws ZipException
*/
public function testSetterUnsupportKeyStrength()
public function testSetterUnsupportKeyStrength(): void
{
$this->expectException(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,

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Extra\Fields;
use PHPUnit\Framework\TestCase;
@ -25,25 +34,25 @@ final class Zip64ExtraFieldTest extends TestCase
/**
* @dataProvider provideExtraField
*
* @param int|null $uncompressedSize
* @param int|null $compressedSize
* @param int|null $localHeaderOffset
* @param int|null $diskStart
* @param string|null $localBinaryData
* @param string|null $cdBinaryData
* @noinspection PhpTooManyParametersInspection
*
* @param ?int $uncompressedSize
* @param ?int $compressedSize
* @param ?int $localHeaderOffset
* @param ?int $diskStart
* @param ?string $localBinaryData
* @param ?string $cdBinaryData
*
* @throws ZipException
*
* @noinspection PhpTooManyParametersInspection
*/
public function testExtraField(
$uncompressedSize,
$compressedSize,
$localHeaderOffset,
$diskStart,
$localBinaryData,
$cdBinaryData
) {
?int $uncompressedSize,
?int $compressedSize,
?int $localHeaderOffset,
?int $diskStart,
?string $localBinaryData,
?string $cdBinaryData
): void {
$extraField = new Zip64ExtraField(
$uncompressedSize,
$compressedSize,
@ -72,10 +81,7 @@ final class Zip64ExtraFieldTest extends TestCase
}
}
/**
* @return array
*/
public function provideExtraField()
public function provideExtraField(): array
{
return [
[
@ -105,7 +111,7 @@ final class Zip64ExtraFieldTest extends TestCase
];
}
public function testSetter()
public function testSetter(): void
{
$extraField = new Zip64ExtraField();
self::assertNull($extraField->getUncompressedSize());

View File

@ -1,30 +1,23 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Internal\CustomZip;
use PhpZip\IO\ZipWriter;
use PhpZip\Model\Extra\Fields\NewUnixExtraField;
use PhpZip\Model\Extra\Fields\NtfsExtraField;
use PhpZip\Model\ZipContainer;
/**
* Class CustomZipWriter.
*/
class CustomZipWriter extends ZipWriter
{
/**
* ZipWriter constructor.
*
* @param ZipContainer $container
*/
public function __construct(ZipContainer $container)
{
// dump($container);
parent::__construct($container);
// dd($this->zipContainer);
}
protected function beforeWrite()
protected function beforeWrite(): void
{
parent::beforeWrite();
$now = new \DateTimeImmutable();

View File

@ -1,19 +1,22 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Internal\CustomZip;
use PhpZip\IO\ZipWriter;
use PhpZip\ZipFile;
/**
* Class ZipFileCustomWriter.
*/
class ZipFileCustomWriter extends ZipFile
{
/**
* @return ZipWriter
*/
protected function createZipWriter()
protected function createZipWriter(): ZipWriter
{
return new CustomZipWriter($this->zipContainer);
}

View File

@ -1,20 +1,26 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Internal\CustomZip;
use PhpZip\Model\Extra\Fields\NewUnixExtraField;
use PhpZip\Model\Extra\Fields\NtfsExtraField;
use PhpZip\ZipFile;
/**
* Class ZipFileWithBeforeSave.
*/
class ZipFileWithBeforeSave extends ZipFile
{
/**
* Event before save or output.
*/
protected function onBeforeSave()
protected function onBeforeSave(): void
{
$now = new \DateTimeImmutable();
$ntfsTimeExtra = NtfsExtraField::create($now, $now->modify('-1 day'), $now->modify('-10 day'));

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Internal;
/**
@ -18,26 +27,24 @@ class DummyFileSystemStream
* This method is called immediately after the wrapper is
* initialized (f.e. by {@see fopen()} and {@see file_get_contents()}).
*
* @param string $path specifies the URL that was passed to
* the original function
* @param string $mode the mode used to open the file, as detailed
* for {@see fopen()}
* @param int $options Holds additional flags set by the streams
* API. It can hold one or more of the
* following values OR'd together.
* @param string $opened_path if the path is opened successfully, and
* STREAM_USE_PATH is set in options,
* opened_path should be set to the
* full path of the file/resource that
* was actually opened
*
* @return bool
* @param string $path specifies the URL that was passed to
* the original function
* @param string $mode the mode used to open the file, as detailed
* for {@see fopen()}
* @param int $options Holds additional flags set by the streams
* API. It can hold one or more of the
* following values OR'd together.
* @param string|null $opened_path if the path is opened successfully, and
* STREAM_USE_PATH is set in options,
* opened_path should be set to the
* full path of the file/resource that
* was actually opened
*
* @see https://www.php.net/streamwrapper.stream-open
*
* @noinspection PhpUsageOfSilenceOperatorInspection
*/
public function stream_open($path, $mode, $options, &$opened_path)
public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool
{
$parsedUrl = parse_url($path);
$uri = substr($parsedUrl['path'], 1);
@ -64,7 +71,7 @@ class DummyFileSystemStream
*
* @see https://www.php.net/streamwrapper.stream-read
*/
public function stream_read($count)
public function stream_read(int $count)
{
return fread($this->fp, $count);
}
@ -86,7 +93,7 @@ class DummyFileSystemStream
*
* @see https://www.php.net/streamwrapper.stream-seek
*/
public function stream_seek($offset, $whence = \SEEK_SET)
public function stream_seek(int $offset, int $whence = \SEEK_SET): bool
{
return fseek($this->fp, $offset, $whence) === 0;
}
@ -101,7 +108,7 @@ class DummyFileSystemStream
*
* @see https://www.php.net/streamwrapper.stream-tell
*/
public function stream_tell()
public function stream_tell(): int
{
$pos = ftell($this->fp);
@ -123,7 +130,7 @@ class DummyFileSystemStream
*
* @see https://www.php.net/streamwrapper.stream-eof
*/
public function stream_eof()
public function stream_eof(): bool
{
return feof($this->fp);
}
@ -133,13 +140,11 @@ class DummyFileSystemStream
*
* This method is called in response to {@see fstat()}.
*
* @return array
*
* @see https://www.php.net/streamwrapper.stream-stat
* @see https://www.php.net/stat
* @see https://www.php.net/fstat
*/
public function stream_stat()
public function stream_stat(): array
{
return fstat($this->fp);
}
@ -159,7 +164,7 @@ class DummyFileSystemStream
*
* @see https://www.php.net/streamwrapper.stream-flush
*/
public function stream_flush()
public function stream_flush(): bool
{
return fflush($this->fp);
}
@ -175,9 +180,9 @@ class DummyFileSystemStream
*
* @see https://www.php.net/streamwrapper.stream-truncate
*/
public function stream_truncate($new_size)
public function stream_truncate(int $new_size): bool
{
return ftruncate($this->fp, (int) $new_size);
return ftruncate($this->fp, $new_size);
}
/**
@ -194,7 +199,7 @@ class DummyFileSystemStream
*
* @see https://www.php.net/streamwrapper.stream-write
*/
public function stream_write($data)
public function stream_write(string $data): int
{
$bytes = fwrite($this->fp, $data);
@ -209,7 +214,7 @@ class DummyFileSystemStream
*
* @see https://www.php.net/streamwrapper.stream-close
*/
public function stream_close()
public function stream_close(): void
{
fclose($this->fp);
}

View File

@ -1,6 +1,13 @@
<?php
/** @noinspection PhpComposerExtensionStubsInspection */
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Internal\Epub;
@ -21,39 +28,25 @@ use PhpZip\ZipFile;
*/
class EpubFile extends ZipFile
{
/**
* @return ZipWriter
*/
protected function createZipWriter()
protected function createZipWriter(): ZipWriter
{
return new EpubWriter($this->zipContainer);
}
/**
* @param resource $inputStream
* @param array $options
*
* @return ZipReader
*/
protected function createZipReader($inputStream, array $options = [])
protected function createZipReader($inputStream, array $options = []): ZipReader
{
return new EpubReader($inputStream, $options);
}
/**
* @param ImmutableZipContainer|null $sourceContainer
*
* @return ZipContainer
*/
protected function createZipContainer(ImmutableZipContainer $sourceContainer = null)
protected function createZipContainer(?ImmutableZipContainer $sourceContainer = null): ZipContainer
{
return new EpubZipContainer($sourceContainer);
}
/**
* @param ZipEntry $zipEntry
*/
protected function addZipEntry(ZipEntry $zipEntry)
protected function addZipEntry(ZipEntry $zipEntry): void
{
$zipEntry->setCreatedOS(ZipPlatform::OS_DOS);
$zipEntry->setExtractedOS(ZipPlatform::OS_UNIX);
@ -62,25 +55,25 @@ class EpubFile extends ZipFile
/**
* @throws ZipEntryNotFoundException
*
* @return string
*/
public function getMimeType()
public function getMimeType(): string
{
return $this->zipContainer->getMimeType();
}
public function getEpubInfo()
/**
* @throws ZipException
* @throws ZipEntryNotFoundException
*/
public function getEpubInfo(): EpubInfo
{
return new EpubInfo($this->getEntryContents($this->getRootFile()));
}
/**
* @throws ZipException
*
* @return string
*/
public function getRootFile()
public function getRootFile(): string
{
$entryName = 'META-INF/container.xml';
$contents = $this->getEntryContents($entryName);

View File

@ -1,6 +1,13 @@
<?php
/** @noinspection PhpComposerExtensionStubsInspection */
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Internal\Epub;
@ -13,29 +20,21 @@ use PhpZip\Exception\ZipException;
*/
class EpubInfo
{
/** @var string|null */
private $title;
private ?string $title;
/** @var string|null */
private $creator;
private ?string $creator;
/** @var string|null */
private $language;
private ?string $language;
/** @var string|null */
private $publisher;
private ?string $publisher;
/** @var string|null */
private $description;
private ?string $description;
/** @var string|null */
private $rights;
private ?string $rights;
/** @var string|null */
private $date;
private ?string $date;
/** @var string|null */
private $subject;
private ?string $subject;
/**
* EpubInfo constructor.
@ -76,74 +75,47 @@ class EpubInfo
$this->subject = empty($subject) ? null : $subject;
}
/**
* @return string|null
*/
public function getTitle()
public function getTitle(): ?string
{
return $this->title;
}
/**
* @return string|null
*/
public function getCreator()
public function getCreator(): ?string
{
return $this->creator;
}
/**
* @return string|null
*/
public function getLanguage()
public function getLanguage(): ?string
{
return $this->language;
}
/**
* @return string|null
*/
public function getPublisher()
public function getPublisher(): ?string
{
return $this->publisher;
}
/**
* @return string|null
*/
public function getDescription()
public function getDescription(): ?string
{
return $this->description;
}
/**
* @return string|null
*/
public function getRights()
public function getRights(): ?string
{
return $this->rights;
}
/**
* @return string|null
*/
public function getDate()
public function getDate(): ?string
{
return $this->date;
}
/**
* @return string|null
*/
public function getSubject()
public function getSubject(): ?string
{
return $this->subject;
}
/**
* @return array
*/
public function toArray()
public function toArray(): array
{
return [
'title' => $this->title,

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Internal\Epub;
use PhpZip\IO\ZipReader;
@ -10,11 +19,9 @@ use PhpZip\IO\ZipReader;
class EpubReader extends ZipReader
{
/**
* @return bool
*
* @see https://github.com/w3c/epubcheck/issues/334
*/
protected function isZip64Support()
protected function isZip64Support(): bool
{
return false;
}

View File

@ -1,5 +1,14 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Internal\Epub;
use PhpZip\Constants\ZipCompressionMethod;
@ -19,7 +28,7 @@ class EpubWriter extends ZipWriter
/**
* @throws ZipUnsupportMethodException
*/
protected function beforeWrite()
protected function beforeWrite(): void
{
parent::beforeWrite();
@ -35,7 +44,7 @@ class EpubWriter extends ZipWriter
$this->sortEntries();
}
private function sortEntries()
private function sortEntries(): void
{
$this->zipContainer->sortByEntry(
static function (ZipEntry $a, ZipEntry $b) {

View File

@ -1,21 +1,25 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Internal\Epub;
use PhpZip\Exception\ZipEntryNotFoundException;
use PhpZip\Model\ZipContainer;
/**
* Class EpubZipContainer.
*/
class EpubZipContainer extends ZipContainer
{
/**
* @throws ZipEntryNotFoundException
*
* @return string
*/
public function getMimeType()
public function getMimeType(): string
{
return $this->getEntry('mimetype')->getData()->getDataAsString();
}

View File

@ -1,15 +1,21 @@
<?php
declare(strict_types=1);
/*
* This file is part of the nelexa/zip package.
* (c) Ne-Lexa <https://github.com/Ne-Lexa/php-zip>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpZip\Tests\Internal;
use PhpZip\ZipFile;
/**
* Class ZipFileExtended.
*/
class ZipFileExtended extends ZipFile
{
protected function onBeforeSave()
protected function onBeforeSave(): void
{
parent::onBeforeSave();
$this->deleteFromRegex('~^META\-INF/~i');

Some files were not shown because too many files have changed in this diff Show More