mirror of
https://github.com/Ne-Lexa/php-zip.git
synced 2025-07-23 16:51:12 +02:00
Merge branch 'release/3.3.0'
This commit is contained in:
@@ -2,15 +2,15 @@ language: php
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- ZIPALIGN_INSTALL=false
|
|
||||||
- COVERAGE=false
|
- COVERAGE=false
|
||||||
- PHPUNIT_FLAGS="-v -c phpunit.xml --testsuite only_fast_tests"
|
- PHPUNIT_FLAGS="-v -c phpunit.xml"
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- php: 5.5
|
- php: 5.5
|
||||||
os: linux
|
os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
|
env: ZIPALIGN_INSTALL=false
|
||||||
|
|
||||||
- php: 5.6
|
- php: 5.6
|
||||||
os: linux
|
os: linux
|
||||||
@@ -40,7 +40,7 @@ matrix:
|
|||||||
- php: 7.4
|
- php: 7.4
|
||||||
os: linux
|
os: linux
|
||||||
dist: xenial
|
dist: xenial
|
||||||
env: COVERAGE=true ZIPALIGN_INSTALL=true PHPUNIT_FLAGS="-v -c phpunit.xml --testsuite only_fast_tests --coverage-clover=coverage.clover"
|
env: COVERAGE=true ZIPALIGN_INSTALL=true PHPUNIT_FLAGS="-v -c phpunit.xml --coverage-clover=coverage.clover"
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- if [[ $COVERAGE != true ]]; then phpenv config-rm xdebug.ini || true; fi
|
- if [[ $COVERAGE != true ]]; then phpenv config-rm xdebug.ini || true; fi
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
"ext-bz2": "*",
|
"ext-bz2": "*",
|
||||||
"ext-openssl": "*",
|
"ext-openssl": "*",
|
||||||
"ext-fileinfo": "*",
|
"ext-fileinfo": "*",
|
||||||
|
"ext-xml": "*",
|
||||||
"guzzlehttp/psr7": "^1.6",
|
"guzzlehttp/psr7": "^1.6",
|
||||||
"phpunit/phpunit": "^4.8|^5.7",
|
"phpunit/phpunit": "^4.8|^5.7",
|
||||||
"symfony/var-dumper": "^3.0|^4.0|^5.0"
|
"symfony/var-dumper": "^3.0|^4.0|^5.0"
|
||||||
|
@@ -22,6 +22,12 @@
|
|||||||
</testsuite>
|
</testsuite>
|
||||||
</testsuites>
|
</testsuites>
|
||||||
|
|
||||||
|
<groups>
|
||||||
|
<exclude>
|
||||||
|
<group>large</group>
|
||||||
|
</exclude>
|
||||||
|
</groups>
|
||||||
|
|
||||||
<filter>
|
<filter>
|
||||||
<whitelist>
|
<whitelist>
|
||||||
<directory>src</directory>
|
<directory>src</directory>
|
||||||
|
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
namespace PhpZip\Constants;
|
namespace PhpZip\Constants;
|
||||||
|
|
||||||
|
use PhpZip\IO\ZipReader;
|
||||||
|
use PhpZip\ZipFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface ZipOptions.
|
* Interface ZipOptions.
|
||||||
*/
|
*/
|
||||||
@@ -10,20 +13,50 @@ interface ZipOptions
|
|||||||
/**
|
/**
|
||||||
* Boolean option for store just file names (skip directory names).
|
* Boolean option for store just file names (skip directory names).
|
||||||
*
|
*
|
||||||
* @var string
|
* @see ZipFile::addFromFinder()
|
||||||
*/
|
*/
|
||||||
const STORE_ONLY_FILES = 'only_files';
|
const STORE_ONLY_FILES = 'only_files';
|
||||||
|
|
||||||
/** @var string */
|
/**
|
||||||
|
* Uses the specified compression method.
|
||||||
|
*
|
||||||
|
* @see ZipFile::addFromFinder()
|
||||||
|
* @see ZipFile::addSplFile()
|
||||||
|
*/
|
||||||
const COMPRESSION_METHOD = 'compression_method';
|
const COMPRESSION_METHOD = 'compression_method';
|
||||||
|
|
||||||
/** @var string */
|
/**
|
||||||
|
* Set the specified record modification time.
|
||||||
|
* The value can be {@see \DateTimeInterface}, integer timestamp
|
||||||
|
* or a string of any format.
|
||||||
|
*
|
||||||
|
* @see ZipFile::addFromFinder()
|
||||||
|
* @see ZipFile::addSplFile()
|
||||||
|
*/
|
||||||
const MODIFIED_TIME = 'mtime';
|
const MODIFIED_TIME = 'mtime';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* Specifies the encoding of the record name for cases when the UTF-8
|
||||||
|
* usage flag is not set.
|
||||||
*
|
*
|
||||||
|
* The most commonly used encodings are compiled into the constants
|
||||||
|
* of the {@see DosCodePage} class.
|
||||||
|
*
|
||||||
|
* @see ZipFile::openFile()
|
||||||
|
* @see ZipFile::openFromString()
|
||||||
|
* @see ZipFile::openFromStream()
|
||||||
|
* @see ZipReader::getDefaultOptions()
|
||||||
* @see DosCodePage::getCodePages()
|
* @see DosCodePage::getCodePages()
|
||||||
*/
|
*/
|
||||||
const CHARSET = 'charset';
|
const CHARSET = 'charset';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows ({@see true}) or denies ({@see false}) unpacking unix symlinks.
|
||||||
|
*
|
||||||
|
* This is a potentially dangerous operation for uncontrolled zip files.
|
||||||
|
* By default is ({@see false}).
|
||||||
|
*
|
||||||
|
* @see https://josipfranjkovic.blogspot.com/2014/12/reading-local-files-from-facebooks.html
|
||||||
|
*/
|
||||||
|
const EXTRACT_SYMLINKS = 'extract_symlinks';
|
||||||
}
|
}
|
||||||
|
@@ -39,7 +39,9 @@ class ZipWriter
|
|||||||
*/
|
*/
|
||||||
public function __construct(ZipContainer $container)
|
public function __construct(ZipContainer $container)
|
||||||
{
|
{
|
||||||
$this->zipContainer = $container;
|
// we clone the container so that the changes made to
|
||||||
|
// it do not affect the data in the ZipFile class
|
||||||
|
$this->zipContainer = clone $container;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -4,18 +4,27 @@ namespace PhpZip\Model\Data;
|
|||||||
|
|
||||||
use PhpZip\Model\ZipData;
|
use PhpZip\Model\ZipData;
|
||||||
use PhpZip\Model\ZipEntry;
|
use PhpZip\Model\ZipEntry;
|
||||||
|
use PhpZip\ZipFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ZipNewData.
|
* The class contains a streaming resource with new content added to the ZIP archive.
|
||||||
*/
|
*/
|
||||||
class ZipNewData implements ZipData
|
class ZipNewData implements ZipData
|
||||||
{
|
{
|
||||||
/** @var resource */
|
/**
|
||||||
private $stream;
|
* A static variable allows closing the stream in the destructor
|
||||||
|
* only if it is its sole holder.
|
||||||
|
*
|
||||||
|
* @var array<int, int> array of resource ids and the number of class clones
|
||||||
|
*/
|
||||||
|
private static $guardClonedStream = [];
|
||||||
|
|
||||||
/** @var ZipEntry */
|
/** @var ZipEntry */
|
||||||
private $zipEntry;
|
private $zipEntry;
|
||||||
|
|
||||||
|
/** @var resource */
|
||||||
|
private $stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ZipStringData constructor.
|
* ZipStringData constructor.
|
||||||
*
|
*
|
||||||
@@ -38,6 +47,12 @@ class ZipNewData implements ZipData
|
|||||||
} elseif (\is_resource($data)) {
|
} elseif (\is_resource($data)) {
|
||||||
$this->stream = $data;
|
$this->stream = $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$resourceId = (int) $this->stream;
|
||||||
|
self::$guardClonedStream[$resourceId] =
|
||||||
|
isset(self::$guardClonedStream[$resourceId]) ?
|
||||||
|
self::$guardClonedStream[$resourceId] + 1 :
|
||||||
|
0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -79,8 +94,35 @@ class ZipNewData implements ZipData
|
|||||||
stream_copy_to_stream($stream, $outStream);
|
stream_copy_to_stream($stream, $outStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://php.net/manual/en/language.oop5.cloning.php
|
||||||
|
*/
|
||||||
|
public function __clone()
|
||||||
|
{
|
||||||
|
$resourceId = (int) $this->stream;
|
||||||
|
self::$guardClonedStream[$resourceId] =
|
||||||
|
isset(self::$guardClonedStream[$resourceId]) ?
|
||||||
|
self::$guardClonedStream[$resourceId] + 1 :
|
||||||
|
1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The stream will be closed when closing the zip archive.
|
||||||
|
*
|
||||||
|
* The method implements protection against closing the stream of the cloned object.
|
||||||
|
*
|
||||||
|
* @see ZipFile::close()
|
||||||
|
*/
|
||||||
public function __destruct()
|
public function __destruct()
|
||||||
{
|
{
|
||||||
|
$resourceId = (int) $this->stream;
|
||||||
|
|
||||||
|
if (isset(self::$guardClonedStream[$resourceId]) && self::$guardClonedStream[$resourceId] > 0) {
|
||||||
|
self::$guardClonedStream[$resourceId]--;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (\is_resource($this->stream)) {
|
if (\is_resource($this->stream)) {
|
||||||
fclose($this->stream);
|
fclose($this->stream);
|
||||||
}
|
}
|
||||||
|
@@ -53,4 +53,20 @@ class ImmutableZipContainer implements \Countable
|
|||||||
{
|
{
|
||||||
return \count($this->entries);
|
return \count($this->entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When an object is cloned, PHP 5 will perform a shallow copy of all of the object's properties.
|
||||||
|
* Any properties that are references to other variables, will remain references.
|
||||||
|
* Once the cloning is complete, if a __clone() method is defined,
|
||||||
|
* then the newly created object's __clone() method will be called, to allow any necessary properties that need to
|
||||||
|
* be changed. NOT CALLABLE DIRECTLY.
|
||||||
|
*
|
||||||
|
* @see https://php.net/manual/en/language.oop5.cloning.php
|
||||||
|
*/
|
||||||
|
public function __clone()
|
||||||
|
{
|
||||||
|
foreach ($this->entries as $key => $value) {
|
||||||
|
$this->entries[$key] = clone $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,12 @@ use PhpZip\Exception\ZipException;
|
|||||||
*/
|
*/
|
||||||
class ZipContainer extends ImmutableZipContainer
|
class ZipContainer extends ImmutableZipContainer
|
||||||
{
|
{
|
||||||
/** @var ImmutableZipContainer|null */
|
/**
|
||||||
|
* @var ImmutableZipContainer|null The source container contains zip entries from
|
||||||
|
* an open zip archive. The source container makes
|
||||||
|
* it possible to undo changes in the archive.
|
||||||
|
* When cloning, this container is not cloned.
|
||||||
|
*/
|
||||||
private $sourceContainer;
|
private $sourceContainer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -43,9 +43,10 @@ final class FilesUtil
|
|||||||
\RecursiveIteratorIterator::CHILD_FIRST
|
\RecursiveIteratorIterator::CHILD_FIRST
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** @var \SplFileInfo $fileInfo */
|
||||||
foreach ($files as $fileInfo) {
|
foreach ($files as $fileInfo) {
|
||||||
$function = ($fileInfo->isDir() ? 'rmdir' : 'unlink');
|
$function = ($fileInfo->isDir() ? 'rmdir' : 'unlink');
|
||||||
$function($fileInfo->getRealPath());
|
$function($fileInfo->getPathname());
|
||||||
}
|
}
|
||||||
rmdir($dir);
|
rmdir($dir);
|
||||||
}
|
}
|
||||||
@@ -303,36 +304,19 @@ final class FilesUtil
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $linkPath
|
|
||||||
* @param string $target
|
* @param string $target
|
||||||
|
* @param string $path
|
||||||
|
* @param bool $allowSymlink
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function symlink($target, $linkPath)
|
public static function symlink($target, $path, $allowSymlink)
|
||||||
{
|
{
|
||||||
if (\DIRECTORY_SEPARATOR === '\\') {
|
if (\DIRECTORY_SEPARATOR === '\\' || !$allowSymlink) {
|
||||||
$linkPath = str_replace('/', '\\', $linkPath);
|
return file_put_contents($path, $target) !== false;
|
||||||
$target = str_replace('/', '\\', $target);
|
|
||||||
$abs = null;
|
|
||||||
|
|
||||||
if (!self::isAbsolutePath($target)) {
|
|
||||||
$abs = realpath(\dirname($linkPath) . \DIRECTORY_SEPARATOR . $target);
|
|
||||||
|
|
||||||
if (\is_string($abs)) {
|
|
||||||
$target = $abs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!symlink($target, $linkPath)) {
|
return symlink($target, $path);
|
||||||
if (\DIRECTORY_SEPARATOR === '\\' && is_file($target)) {
|
|
||||||
return copy($target, $linkPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
namespace PhpZip;
|
namespace PhpZip;
|
||||||
|
|
||||||
|
use PhpZip\Constants\UnixStat;
|
||||||
use PhpZip\Constants\ZipCompressionLevel;
|
use PhpZip\Constants\ZipCompressionLevel;
|
||||||
use PhpZip\Constants\ZipCompressionMethod;
|
use PhpZip\Constants\ZipCompressionMethod;
|
||||||
use PhpZip\Constants\ZipEncryptionMethod;
|
use PhpZip\Constants\ZipEncryptionMethod;
|
||||||
@@ -20,6 +21,7 @@ use PhpZip\IO\ZipReader;
|
|||||||
use PhpZip\IO\ZipWriter;
|
use PhpZip\IO\ZipWriter;
|
||||||
use PhpZip\Model\Data\ZipFileData;
|
use PhpZip\Model\Data\ZipFileData;
|
||||||
use PhpZip\Model\Data\ZipNewData;
|
use PhpZip\Model\Data\ZipNewData;
|
||||||
|
use PhpZip\Model\ImmutableZipContainer;
|
||||||
use PhpZip\Model\ZipContainer;
|
use PhpZip\Model\ZipContainer;
|
||||||
use PhpZip\Model\ZipEntry;
|
use PhpZip\Model\ZipEntry;
|
||||||
use PhpZip\Model\ZipEntryMatcher;
|
use PhpZip\Model\ZipEntryMatcher;
|
||||||
@@ -68,7 +70,7 @@ class ZipFile implements ZipFileInterface
|
|||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->zipContainer = new ZipContainer();
|
$this->zipContainer = $this->createZipContainer(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,6 +92,16 @@ class ZipFile implements ZipFileInterface
|
|||||||
return new ZipWriter($this->zipContainer);
|
return new ZipWriter($this->zipContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ImmutableZipContainer|null $sourceContainer
|
||||||
|
*
|
||||||
|
* @return ZipContainer
|
||||||
|
*/
|
||||||
|
protected function createZipContainer(ImmutableZipContainer $sourceContainer = null)
|
||||||
|
{
|
||||||
|
return new ZipContainer($sourceContainer);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open zip archive from file.
|
* Open zip archive from file.
|
||||||
*
|
*
|
||||||
@@ -130,7 +142,9 @@ class ZipFile implements ZipFileInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!($handle = fopen('php://temp', 'r+b'))) {
|
if (!($handle = fopen('php://temp', 'r+b'))) {
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
throw new ZipException("Can't open temp stream.");
|
throw new ZipException("Can't open temp stream.");
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
}
|
}
|
||||||
fwrite($handle, $data);
|
fwrite($handle, $data);
|
||||||
rewind($handle);
|
rewind($handle);
|
||||||
@@ -151,7 +165,7 @@ class ZipFile implements ZipFileInterface
|
|||||||
public function openFromStream($handle, array $options = [])
|
public function openFromStream($handle, array $options = [])
|
||||||
{
|
{
|
||||||
$this->reader = $this->createZipReader($handle, $options);
|
$this->reader = $this->createZipReader($handle, $options);
|
||||||
$this->zipContainer = new ZipContainer($this->reader->read());
|
$this->zipContainer = $this->createZipContainer($this->reader->read());
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@@ -363,15 +377,20 @@ class ZipFile implements ZipFileInterface
|
|||||||
*
|
*
|
||||||
* Extract the complete archive or the given files to the specified destination.
|
* Extract the complete archive or the given files to the specified destination.
|
||||||
*
|
*
|
||||||
* @param string $destDir location where to extract the files
|
* @param string $destDir location where to extract the files
|
||||||
* @param array|string|null $entries The entries to extract. It accepts either
|
* @param array|string|null $entries entries to extract
|
||||||
* a single entry name or an array of names.
|
* @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
|
* @throws ZipException
|
||||||
*
|
*
|
||||||
* @return ZipFile
|
* @return ZipFile
|
||||||
*/
|
*/
|
||||||
public function extractTo($destDir, $entries = null)
|
public function extractTo($destDir, $entries = null, array $options = [], &$extractedEntries = [])
|
||||||
{
|
{
|
||||||
if (!file_exists($destDir)) {
|
if (!file_exists($destDir)) {
|
||||||
throw new ZipException(sprintf('Destination %s not found', $destDir));
|
throw new ZipException(sprintf('Destination %s not found', $destDir));
|
||||||
@@ -385,7 +404,14 @@ class ZipFile implements ZipFileInterface
|
|||||||
throw new ZipException('Destination is not writable directory');
|
throw new ZipException('Destination is not writable directory');
|
||||||
}
|
}
|
||||||
|
|
||||||
$extractedEntries = [];
|
if ($extractedEntries === null) {
|
||||||
|
$extractedEntries = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$defaultOptions = [
|
||||||
|
ZipOptions::EXTRACT_SYMLINKS => false,
|
||||||
|
];
|
||||||
|
$options += $defaultOptions;
|
||||||
|
|
||||||
$zipEntries = $this->zipContainer->getEntries();
|
$zipEntries = $this->zipContainer->getEntries();
|
||||||
|
|
||||||
@@ -435,7 +461,9 @@ class ZipFile implements ZipFileInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!mkdir($dir, $dirMode, true) && !is_dir($dir)) {
|
if (!mkdir($dir, $dirMode, true) && !is_dir($dir)) {
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
throw new \RuntimeException(sprintf('Directory "%s" was not created', $dir));
|
throw new \RuntimeException(sprintf('Directory "%s" was not created', $dir));
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
}
|
}
|
||||||
chmod($dir, $dirMode);
|
chmod($dir, $dirMode);
|
||||||
}
|
}
|
||||||
@@ -471,6 +499,7 @@ class ZipFile implements ZipFileInterface
|
|||||||
|
|
||||||
/** @noinspection PhpUsageOfSilenceOperatorInspection */
|
/** @noinspection PhpUsageOfSilenceOperatorInspection */
|
||||||
if (!($handle = @fopen($file, 'w+b'))) {
|
if (!($handle = @fopen($file, 'w+b'))) {
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
throw new ZipException(
|
throw new ZipException(
|
||||||
sprintf(
|
sprintf(
|
||||||
'Cannot extract zip entry %s. File %s cannot open for write.',
|
'Cannot extract zip entry %s. File %s cannot open for write.',
|
||||||
@@ -478,6 +507,7 @@ class ZipFile implements ZipFileInterface
|
|||||||
$file
|
$file
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -486,9 +516,8 @@ class ZipFile implements ZipFileInterface
|
|||||||
unlink($file);
|
unlink($file);
|
||||||
|
|
||||||
throw $e;
|
throw $e;
|
||||||
} finally {
|
|
||||||
fclose($handle);
|
|
||||||
}
|
}
|
||||||
|
fclose($handle);
|
||||||
|
|
||||||
if ($unixMode === 0) {
|
if ($unixMode === 0) {
|
||||||
$unixMode = 0644;
|
$unixMode = 0644;
|
||||||
@@ -503,8 +532,10 @@ class ZipFile implements ZipFileInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$allowSymlink = (bool) $options[ZipOptions::EXTRACT_SYMLINKS];
|
||||||
|
|
||||||
foreach ($symlinks as $linkPath => $target) {
|
foreach ($symlinks as $linkPath => $target) {
|
||||||
if (!FilesUtil::symlink($target, $linkPath)) {
|
if (!FilesUtil::symlink($target, $linkPath, $allowSymlink)) {
|
||||||
unset($extractedEntries[$linkPath]);
|
unset($extractedEntries[$linkPath]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -515,7 +546,7 @@ class ZipFile implements ZipFileInterface
|
|||||||
touch($dir, $lastMod);
|
touch($dir, $lastMod);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ksort($extractedEntries);
|
ksort($extractedEntries);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@@ -652,9 +683,24 @@ class ZipFile implements ZipFileInterface
|
|||||||
$entryName = $file->isDir() ? rtrim($entryName, '/\\') . '/' : $entryName;
|
$entryName = $file->isDir() ? rtrim($entryName, '/\\') . '/' : $entryName;
|
||||||
|
|
||||||
$zipEntry = new ZipEntry($entryName);
|
$zipEntry = new ZipEntry($entryName);
|
||||||
$zipData = null;
|
$zipEntry->setCreatedOS(ZipPlatform::OS_UNIX);
|
||||||
|
$zipEntry->setExtractedOS(ZipPlatform::OS_UNIX);
|
||||||
|
|
||||||
if ($file->isFile()) {
|
$zipData = null;
|
||||||
|
$filePerms = $file->getPerms();
|
||||||
|
|
||||||
|
if ($file->isLink()) {
|
||||||
|
$linkTarget = $file->getLinkTarget();
|
||||||
|
$lengthLinkTarget = \strlen($linkTarget);
|
||||||
|
|
||||||
|
$zipEntry->setCompressionMethod(ZipCompressionMethod::STORED);
|
||||||
|
$zipEntry->setUncompressedSize($lengthLinkTarget);
|
||||||
|
$zipEntry->setCompressedSize($lengthLinkTarget);
|
||||||
|
$zipEntry->setCrc(crc32($linkTarget));
|
||||||
|
$filePerms |= UnixStat::UNX_IFLNK;
|
||||||
|
|
||||||
|
$zipData = new ZipNewData($zipEntry, $linkTarget);
|
||||||
|
} elseif ($file->isFile()) {
|
||||||
if (isset($options[ZipOptions::COMPRESSION_METHOD])) {
|
if (isset($options[ZipOptions::COMPRESSION_METHOD])) {
|
||||||
$compressionMethod = $options[ZipOptions::COMPRESSION_METHOD];
|
$compressionMethod = $options[ZipOptions::COMPRESSION_METHOD];
|
||||||
} elseif ($file->getSize() < 512) {
|
} elseif ($file->getSize() < 512) {
|
||||||
@@ -673,21 +719,9 @@ class ZipFile implements ZipFileInterface
|
|||||||
$zipEntry->setUncompressedSize(0);
|
$zipEntry->setUncompressedSize(0);
|
||||||
$zipEntry->setCompressedSize(0);
|
$zipEntry->setCompressedSize(0);
|
||||||
$zipEntry->setCrc(0);
|
$zipEntry->setCrc(0);
|
||||||
} elseif ($file->isLink()) {
|
|
||||||
$linkTarget = $file->getLinkTarget();
|
|
||||||
$lengthLinkTarget = \strlen($linkTarget);
|
|
||||||
|
|
||||||
$zipEntry->setCompressionMethod(ZipCompressionMethod::STORED);
|
|
||||||
$zipEntry->setUncompressedSize($lengthLinkTarget);
|
|
||||||
$zipEntry->setCompressedSize($lengthLinkTarget);
|
|
||||||
$zipEntry->setCrc(crc32($linkTarget));
|
|
||||||
|
|
||||||
$zipData = new ZipNewData($zipEntry, $linkTarget);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$zipEntry->setCreatedOS(ZipPlatform::OS_UNIX);
|
$zipEntry->setUnixMode($filePerms);
|
||||||
$zipEntry->setExtractedOS(ZipPlatform::OS_UNIX);
|
|
||||||
$zipEntry->setUnixMode($file->getPerms());
|
|
||||||
|
|
||||||
$timestamp = null;
|
$timestamp = null;
|
||||||
|
|
||||||
@@ -1768,8 +1802,9 @@ class ZipFile implements ZipFileInterface
|
|||||||
if ($this->reader !== null) {
|
if ($this->reader !== null) {
|
||||||
$this->reader->close();
|
$this->reader->close();
|
||||||
$this->reader = null;
|
$this->reader = null;
|
||||||
$this->zipContainer = new ZipContainer();
|
|
||||||
}
|
}
|
||||||
|
$this->zipContainer = $this->createZipContainer(null);
|
||||||
|
gc_collect_cycles();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -292,15 +292,20 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator
|
|||||||
*
|
*
|
||||||
* Extract the complete archive or the given files to the specified destination.
|
* Extract the complete archive or the given files to the specified destination.
|
||||||
*
|
*
|
||||||
* @param string $destDir location where to extract the files
|
* @param string $destDir location where to extract the files
|
||||||
* @param array|string|null $entries The entries to extract. It accepts either
|
* @param array|string|null $entries entries to extract
|
||||||
* a single entry name or an array of names.
|
* @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
|
* @throws ZipException
|
||||||
*
|
*
|
||||||
* @return ZipFile
|
* @return ZipFile
|
||||||
*/
|
*/
|
||||||
public function extractTo($destDir, $entries = null);
|
public function extractTo($destDir, $entries = null, array $options = [], &$extractedEntries = []);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add entry from the string.
|
* Add entry from the string.
|
||||||
|
126
tests/CustomZipFormatTest.php
Normal file
126
tests/CustomZipFormatTest.php
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpZip\Tests;
|
||||||
|
|
||||||
|
use PhpZip\Exception\ZipEntryNotFoundException;
|
||||||
|
use PhpZip\Exception\ZipException;
|
||||||
|
use PhpZip\Model\Extra\Fields\NewUnixExtraField;
|
||||||
|
use PhpZip\Model\Extra\Fields\NtfsExtraField;
|
||||||
|
use PhpZip\Tests\Internal\CustomZip\ZipFileCustomWriter;
|
||||||
|
use PhpZip\Tests\Internal\CustomZip\ZipFileWithBeforeSave;
|
||||||
|
use PhpZip\Tests\Internal\Epub\EpubFile;
|
||||||
|
use PhpZip\ZipFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the ability to create own file-type class, reader, writer and container.
|
||||||
|
**.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @small
|
||||||
|
*/
|
||||||
|
final class CustomZipFormatTest extends ZipTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws ZipException
|
||||||
|
*
|
||||||
|
* @see http://www.epubtest.org/test-books source epub files
|
||||||
|
*/
|
||||||
|
public function testEpub()
|
||||||
|
{
|
||||||
|
$epubFile = new EpubFile();
|
||||||
|
$epubFile->openFile(__DIR__ . '/resources/Advanced-v1.0.0.epub');
|
||||||
|
self::assertSame($epubFile->getRootFile(), 'EPUB/package.opf');
|
||||||
|
self::assertSame($epubFile->getMimeType(), 'application/epub+zip');
|
||||||
|
$epubInfo = $epubFile->getEpubInfo();
|
||||||
|
self::assertSame($epubInfo->toArray(), [
|
||||||
|
'title' => 'Advanced Accessibility Tests: Extended Descriptions',
|
||||||
|
'creator' => 'DAISY Consortium Transition to EPUB 3 and DIAGRAM Standards WG',
|
||||||
|
'language' => 'en-US',
|
||||||
|
'publisher' => 'DAISY Consortium and DIAGRAM Center',
|
||||||
|
'description' => 'Tests for accessible extended descriptions of images in EPUBs',
|
||||||
|
'rights' => 'This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike (CC BY-NC-SA) license.',
|
||||||
|
'date' => '2019-01-03',
|
||||||
|
'subject' => 'extended-descriptions',
|
||||||
|
]);
|
||||||
|
$epubFile->deleteFromName('mimetype');
|
||||||
|
self::assertFalse($epubFile->hasEntry('mimetype'));
|
||||||
|
|
||||||
|
try {
|
||||||
|
$epubFile->getMimeType();
|
||||||
|
self::fail('deleted mimetype');
|
||||||
|
} catch (ZipEntryNotFoundException $e) {
|
||||||
|
self::assertSame('Zip Entry "mimetype" was not found in the archive.', $e->getMessage());
|
||||||
|
}
|
||||||
|
$epubFile->saveAsFile($this->outputFilename);
|
||||||
|
self::assertFalse($epubFile->hasEntry('mimetype'));
|
||||||
|
$epubFile->close();
|
||||||
|
|
||||||
|
self::assertCorrectZipArchive($this->outputFilename);
|
||||||
|
|
||||||
|
$epubFile->openFile($this->outputFilename);
|
||||||
|
// file appended in EpubWriter before write
|
||||||
|
self::assertTrue($epubFile->hasEntry('mimetype'));
|
||||||
|
$epubFile->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function testBeforeSaveInZipWriter()
|
||||||
|
{
|
||||||
|
$zipFile = new ZipFileCustomWriter();
|
||||||
|
for ($i = 0; $i < 10; $i++) {
|
||||||
|
$zipFile['file ' . $i] = 'contents file ' . $i;
|
||||||
|
}
|
||||||
|
$this->existsExtraFields($zipFile, false);
|
||||||
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
|
$this->existsExtraFields($zipFile, false);
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertCorrectZipArchive($this->outputFilename);
|
||||||
|
|
||||||
|
$zipFile->openFile($this->outputFilename);
|
||||||
|
$this->existsExtraFields($zipFile, true);
|
||||||
|
$zipFile->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function testBeforeSaveInZipFile()
|
||||||
|
{
|
||||||
|
$zipFile = new ZipFileWithBeforeSave();
|
||||||
|
for ($i = 0; $i < 10; $i++) {
|
||||||
|
$zipFile['file ' . $i] = 'contents file ' . $i;
|
||||||
|
}
|
||||||
|
$this->existsExtraFields($zipFile, false);
|
||||||
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
|
$this->existsExtraFields($zipFile, true);
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertCorrectZipArchive($this->outputFilename);
|
||||||
|
|
||||||
|
$zipFile->openFile($this->outputFilename);
|
||||||
|
$this->existsExtraFields($zipFile, true);
|
||||||
|
$zipFile->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ZipFile $zipFile
|
||||||
|
* @param bool $exists
|
||||||
|
*/
|
||||||
|
private function existsExtraFields(ZipFile $zipFile, $exists)
|
||||||
|
{
|
||||||
|
foreach ($zipFile->getEntries() as $entry) {
|
||||||
|
$localExtras = $entry->getLocalExtraFields();
|
||||||
|
$cdExtras = $entry->getCdExtraFields();
|
||||||
|
|
||||||
|
self::assertSame(isset($localExtras[NtfsExtraField::HEADER_ID]), $exists);
|
||||||
|
self::assertSame(isset($cdExtras[NtfsExtraField::HEADER_ID]), $exists);
|
||||||
|
|
||||||
|
self::assertSame(isset($localExtras[NewUnixExtraField::HEADER_ID]), $exists);
|
||||||
|
self::assertSame(isset($cdExtras[NewUnixExtraField::HEADER_ID]), $exists);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
101
tests/Extra/Fields/AbstractUnicodeExtraFieldTest.php
Normal file
101
tests/Extra/Fields/AbstractUnicodeExtraFieldTest.php
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/** @noinspection PhpUndefinedMethodInspection */
|
||||||
|
|
||||||
|
namespace PhpZip\Tests\Extra\Fields;
|
||||||
|
|
||||||
|
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>
|
||||||
|
*/
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
$crc32 = (int) $crc32; // for php 32-bit
|
||||||
|
|
||||||
|
$className = $this->getUnicodeExtraFieldClassName();
|
||||||
|
|
||||||
|
/** @var AbstractUnicodeExtraField $extraField */
|
||||||
|
$extraField = new $className($crc32, $unicodePath);
|
||||||
|
static::assertSame($extraField->getCrc32(), $crc32);
|
||||||
|
static::assertSame($extraField->getUnicodeValue(), $unicodePath);
|
||||||
|
static::assertSame(crc32($originalPath), $crc32);
|
||||||
|
|
||||||
|
static::assertSame($binaryData, $extraField->packLocalFileData());
|
||||||
|
static::assertSame($binaryData, $extraField->packCentralDirData());
|
||||||
|
static::assertEquals($className::unpackLocalFileData($binaryData), $extraField);
|
||||||
|
static::assertEquals($className::unpackCentralDirData($binaryData), $extraField);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
abstract public function provideExtraField();
|
||||||
|
|
||||||
|
public function testSetter()
|
||||||
|
{
|
||||||
|
$className = $this->getUnicodeExtraFieldClassName();
|
||||||
|
$entryName = '11111';
|
||||||
|
|
||||||
|
/** @var AbstractUnicodeExtraField $extraField */
|
||||||
|
$extraField = new $className(crc32($entryName), '22222');
|
||||||
|
static::assertSame($extraField->getHeaderId(), $className::HEADER_ID);
|
||||||
|
static::assertSame($extraField->getCrc32(), crc32($entryName));
|
||||||
|
static::assertSame($extraField->getUnicodeValue(), '22222');
|
||||||
|
|
||||||
|
$crc32 = 1234567;
|
||||||
|
$extraField->setCrc32($crc32);
|
||||||
|
static::assertSame($extraField->getCrc32(), $crc32);
|
||||||
|
$extraField->setUnicodeValue('44444');
|
||||||
|
static::assertSame($extraField->getUnicodeValue(), '44444');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipException
|
||||||
|
*/
|
||||||
|
public function testUnicodeErrorParse()
|
||||||
|
{
|
||||||
|
$this->setExpectedException(
|
||||||
|
ZipException::class,
|
||||||
|
'Unicode path extra data must have at least 5 bytes.'
|
||||||
|
);
|
||||||
|
|
||||||
|
$className = $this->getUnicodeExtraFieldClassName();
|
||||||
|
$className::unpackLocalFileData('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipException
|
||||||
|
*/
|
||||||
|
public function testUnknownVersionParse()
|
||||||
|
{
|
||||||
|
$this->setExpectedException(
|
||||||
|
ZipException::class,
|
||||||
|
'Unsupported version [2] for Unicode path extra data.'
|
||||||
|
);
|
||||||
|
|
||||||
|
$className = $this->getUnicodeExtraFieldClassName();
|
||||||
|
$className::unpackLocalFileData("\x02\x04a\xD28\xC3\xA4\\\xC3\xBC.txt");
|
||||||
|
}
|
||||||
|
}
|
106
tests/Extra/Fields/ApkAlignmentExtraFieldTest.php
Normal file
106
tests/Extra/Fields/ApkAlignmentExtraFieldTest.php
Normal file
File diff suppressed because one or more lines are too long
101
tests/Extra/Fields/AsiExtraFieldTest.php
Normal file
101
tests/Extra/Fields/AsiExtraFieldTest.php
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpZip\Tests\Extra\Fields;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use PhpZip\Exception\Crc32Exception;
|
||||||
|
use PhpZip\Exception\ZipException;
|
||||||
|
use PhpZip\Model\Extra\Fields\AsiExtraField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @small
|
||||||
|
*/
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
$asiExtraField = new AsiExtraField($mode, $uid, $gid, $link);
|
||||||
|
self::assertSame($asiExtraField->getHeaderId(), AsiExtraField::HEADER_ID);
|
||||||
|
|
||||||
|
self::assertSame($asiExtraField->getMode(), $mode);
|
||||||
|
self::assertSame($asiExtraField->getUserId(), $uid);
|
||||||
|
self::assertSame($asiExtraField->getGroupId(), $uid);
|
||||||
|
self::assertSame($asiExtraField->getLink(), $link);
|
||||||
|
|
||||||
|
self::assertSame($asiExtraField->packLocalFileData(), $binaryData);
|
||||||
|
self::assertSame($asiExtraField->packCentralDirData(), $binaryData);
|
||||||
|
|
||||||
|
self::assertEquals(AsiExtraField::unpackLocalFileData($binaryData), $asiExtraField);
|
||||||
|
self::assertEquals(AsiExtraField::unpackCentralDirData($binaryData), $asiExtraField);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideExtraField()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
040755,
|
||||||
|
AsiExtraField::USER_GID_PID,
|
||||||
|
AsiExtraField::USER_GID_PID,
|
||||||
|
'',
|
||||||
|
"#\x06\\\xF6\xEDA\x00\x00\x00\x00\xE8\x03\xE8\x03",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0100644,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'sites-enabled/example.conf',
|
||||||
|
"_\xB8\xC7b\xA4\x81\x1A\x00\x00\x00\x00\x00\x00\x00sites-enabled/example.conf",
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetter()
|
||||||
|
{
|
||||||
|
$extraField = new AsiExtraField(0777);
|
||||||
|
$extraField->setMode(0100666);
|
||||||
|
self::assertSame(0100666, $extraField->getMode());
|
||||||
|
$extraField->setUserId(700);
|
||||||
|
self::assertSame(700, $extraField->getUserId());
|
||||||
|
$extraField->setGroupId(500);
|
||||||
|
self::assertSame(500, $extraField->getGroupId());
|
||||||
|
$extraField->setLink('link.txt');
|
||||||
|
self::assertSame($extraField->getLink(), 'link.txt');
|
||||||
|
self::assertSame(0120666, $extraField->getMode());
|
||||||
|
|
||||||
|
// dir mode
|
||||||
|
$extraField->setMode(0755);
|
||||||
|
self::assertSame(0120755, $extraField->getMode());
|
||||||
|
$extraField->setLink('');
|
||||||
|
self::assertSame($extraField->getLink(), '');
|
||||||
|
self::assertSame(0100755, $extraField->getMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Crc32Exception
|
||||||
|
*/
|
||||||
|
public function testInvalidParse()
|
||||||
|
{
|
||||||
|
$this->setExpectedException(
|
||||||
|
Crc32Exception::class,
|
||||||
|
'Asi Unix Extra Filed Data (expected CRC32 value'
|
||||||
|
);
|
||||||
|
|
||||||
|
AsiExtraField::unpackLocalFileData("\x01\x06\\\xF6\xEDA\x00\x00\x00\x00\xE8\x03\xE8\x03");
|
||||||
|
}
|
||||||
|
}
|
158
tests/Extra/Fields/ExtendedTimestampExtraFieldTest.php
Normal file
158
tests/Extra/Fields/ExtendedTimestampExtraFieldTest.php
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpZip\Tests\Extra\Fields;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use PhpZip\Model\Extra\Fields\ExtendedTimestampExtraField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ExtendedTimestampExtraFieldTest.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @small
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
public function testExtraField(
|
||||||
|
$flags,
|
||||||
|
$modifyTime,
|
||||||
|
$accessTime,
|
||||||
|
$createTime,
|
||||||
|
$localData,
|
||||||
|
$cdData
|
||||||
|
) {
|
||||||
|
$localExtraField = new ExtendedTimestampExtraField($flags, $modifyTime, $accessTime, $createTime);
|
||||||
|
self::assertSame($localExtraField->getHeaderId(), ExtendedTimestampExtraField::HEADER_ID);
|
||||||
|
self::assertSame($localExtraField->getFlags(), $flags);
|
||||||
|
self::assertSame($localExtraField->getModifyTime(), $modifyTime);
|
||||||
|
self::assertSame($localExtraField->getAccessTime(), $accessTime);
|
||||||
|
self::assertSame($localExtraField->getCreateTime(), $createTime);
|
||||||
|
self::assertSame($localExtraField->packLocalFileData(), $localData);
|
||||||
|
self::assertEquals(ExtendedTimestampExtraField::unpackLocalFileData($localData), $localExtraField);
|
||||||
|
|
||||||
|
$extTimeField = ExtendedTimestampExtraField::create($modifyTime, $accessTime, $createTime);
|
||||||
|
self::assertEquals($extTimeField, $localExtraField);
|
||||||
|
|
||||||
|
$accessTime = null;
|
||||||
|
$createTime = null;
|
||||||
|
$cdExtraField = new ExtendedTimestampExtraField($flags, $modifyTime, $accessTime, $createTime);
|
||||||
|
self::assertSame($cdExtraField->getHeaderId(), ExtendedTimestampExtraField::HEADER_ID);
|
||||||
|
self::assertSame($cdExtraField->getFlags(), $flags);
|
||||||
|
self::assertSame($cdExtraField->getModifyTime(), $modifyTime);
|
||||||
|
self::assertSame($cdExtraField->getAccessTime(), $accessTime);
|
||||||
|
self::assertSame($cdExtraField->getCreateTime(), $createTime);
|
||||||
|
self::assertSame($cdExtraField->packCentralDirData(), $cdData);
|
||||||
|
self::assertEquals(ExtendedTimestampExtraField::unpackCentralDirData($cdData), $cdExtraField);
|
||||||
|
self::assertSame($localExtraField->packCentralDirData(), $cdData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideExtraField()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
ExtendedTimestampExtraField::MODIFY_TIME_BIT |
|
||||||
|
ExtendedTimestampExtraField::ACCESS_TIME_BIT |
|
||||||
|
ExtendedTimestampExtraField::CREATE_TIME_BIT,
|
||||||
|
911512006,
|
||||||
|
911430000,
|
||||||
|
893709400,
|
||||||
|
"\x07\xC6\x91T6pQS6X\xECD5",
|
||||||
|
"\x07\xC6\x91T6",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
ExtendedTimestampExtraField::MODIFY_TIME_BIT |
|
||||||
|
ExtendedTimestampExtraField::ACCESS_TIME_BIT,
|
||||||
|
1492955702,
|
||||||
|
1492955638,
|
||||||
|
null,
|
||||||
|
"\x036\xB2\xFCX\xF6\xB1\xFCX",
|
||||||
|
"\x036\xB2\xFCX",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
ExtendedTimestampExtraField::MODIFY_TIME_BIT,
|
||||||
|
1470494391,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
"\x01\xB7\xF6\xA5W",
|
||||||
|
"\x01\xB7\xF6\xA5W",
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function testSetter()
|
||||||
|
{
|
||||||
|
$mtime = time();
|
||||||
|
$atime = null;
|
||||||
|
$ctime = null;
|
||||||
|
|
||||||
|
$field = ExtendedTimestampExtraField::create($mtime, $atime, $ctime);
|
||||||
|
self::assertSame($field->getFlags(), ExtendedTimestampExtraField::MODIFY_TIME_BIT);
|
||||||
|
self::assertSame($field->getModifyTime(), $mtime);
|
||||||
|
self::assertEquals($field->getModifyDateTime(), new \DateTimeImmutable('@' . $mtime));
|
||||||
|
self::assertSame($field->getAccessTime(), $atime);
|
||||||
|
self::assertSame($field->getCreateTime(), $ctime);
|
||||||
|
|
||||||
|
$atime = strtotime('-1 min');
|
||||||
|
$field->setAccessTime($atime);
|
||||||
|
self::assertSame(
|
||||||
|
$field->getFlags(),
|
||||||
|
ExtendedTimestampExtraField::MODIFY_TIME_BIT |
|
||||||
|
ExtendedTimestampExtraField::ACCESS_TIME_BIT
|
||||||
|
);
|
||||||
|
self::assertSame($field->getModifyTime(), $mtime);
|
||||||
|
self::assertSame($field->getAccessTime(), $atime);
|
||||||
|
self::assertEquals($field->getAccessDateTime(), new \DateTimeImmutable('@' . $atime));
|
||||||
|
self::assertSame($field->getCreateTime(), $ctime);
|
||||||
|
|
||||||
|
$ctime = strtotime('-1 hour');
|
||||||
|
$field->setCreateTime($ctime);
|
||||||
|
self::assertSame(
|
||||||
|
$field->getFlags(),
|
||||||
|
ExtendedTimestampExtraField::MODIFY_TIME_BIT |
|
||||||
|
ExtendedTimestampExtraField::ACCESS_TIME_BIT |
|
||||||
|
ExtendedTimestampExtraField::CREATE_TIME_BIT
|
||||||
|
);
|
||||||
|
self::assertSame($field->getModifyTime(), $mtime);
|
||||||
|
self::assertSame($field->getAccessTime(), $atime);
|
||||||
|
self::assertSame($field->getCreateTime(), $ctime);
|
||||||
|
self::assertEquals($field->getCreateDateTime(), new \DateTimeImmutable('@' . $ctime));
|
||||||
|
|
||||||
|
$field->setCreateTime(null);
|
||||||
|
self::assertNull($field->getCreateTime());
|
||||||
|
self::assertNull($field->getCreateDateTime());
|
||||||
|
self::assertSame(
|
||||||
|
$field->getFlags(),
|
||||||
|
ExtendedTimestampExtraField::MODIFY_TIME_BIT |
|
||||||
|
ExtendedTimestampExtraField::ACCESS_TIME_BIT
|
||||||
|
);
|
||||||
|
|
||||||
|
$field->setAccessTime(null);
|
||||||
|
self::assertNull($field->getAccessTime());
|
||||||
|
self::assertNull($field->getAccessDateTime());
|
||||||
|
self::assertSame($field->getFlags(), ExtendedTimestampExtraField::MODIFY_TIME_BIT);
|
||||||
|
|
||||||
|
$field->setModifyTime(null);
|
||||||
|
self::assertNull($field->getModifyTime());
|
||||||
|
self::assertNull($field->getModifyDateTime());
|
||||||
|
self::assertSame($field->getFlags(), 0);
|
||||||
|
}
|
||||||
|
}
|
55
tests/Extra/Fields/JarMarkerExtraFieldTest.php
Normal file
55
tests/Extra/Fields/JarMarkerExtraFieldTest.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpZip\Tests\Extra\Fields;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use PhpZip\Exception\ZipException;
|
||||||
|
use PhpZip\Model\Extra\Fields\JarMarkerExtraField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class JarMarkerExtraFieldTest.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @small
|
||||||
|
*/
|
||||||
|
final class JarMarkerExtraFieldTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws ZipException
|
||||||
|
*/
|
||||||
|
public function testExtraField()
|
||||||
|
{
|
||||||
|
$jarField = new JarMarkerExtraField();
|
||||||
|
self::assertSame('', $jarField->packLocalFileData());
|
||||||
|
self::assertSame('', $jarField->packCentralDirData());
|
||||||
|
self::assertEquals(JarMarkerExtraField::unpackLocalFileData(''), $jarField);
|
||||||
|
self::assertEquals(JarMarkerExtraField::unpackCentralDirData(''), $jarField);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipException
|
||||||
|
*/
|
||||||
|
public function testInvalidUnpackLocalData()
|
||||||
|
{
|
||||||
|
$this->setExpectedException(
|
||||||
|
ZipException::class,
|
||||||
|
"JarMarker doesn't expect any data"
|
||||||
|
);
|
||||||
|
|
||||||
|
JarMarkerExtraField::unpackLocalFileData("\x02\x00\00");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipException
|
||||||
|
*/
|
||||||
|
public function testInvalidUnpackCdData()
|
||||||
|
{
|
||||||
|
$this->setExpectedException(
|
||||||
|
ZipException::class,
|
||||||
|
"JarMarker doesn't expect any data"
|
||||||
|
);
|
||||||
|
|
||||||
|
JarMarkerExtraField::unpackCentralDirData("\x02\x00\00");
|
||||||
|
}
|
||||||
|
}
|
97
tests/Extra/Fields/NewUnixExtraFieldTest.php
Normal file
97
tests/Extra/Fields/NewUnixExtraFieldTest.php
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpZip\Tests\Extra\Fields;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use PhpZip\Exception\ZipException;
|
||||||
|
use PhpZip\Model\Extra\Fields\NewUnixExtraField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class NewUnixExtraFieldTest.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @small
|
||||||
|
*/
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
$extraField = new NewUnixExtraField($version, $uid, $gid);
|
||||||
|
self::assertSame($extraField->getHeaderId(), NewUnixExtraField::HEADER_ID);
|
||||||
|
self::assertSame($extraField->getVersion(), $version);
|
||||||
|
self::assertSame($extraField->getGid(), $gid);
|
||||||
|
self::assertSame($extraField->getUid(), $uid);
|
||||||
|
|
||||||
|
self::assertEquals(NewUnixExtraField::unpackLocalFileData($binaryData), $extraField);
|
||||||
|
self::assertEquals(NewUnixExtraField::unpackCentralDirData($binaryData), $extraField);
|
||||||
|
|
||||||
|
self::assertSame($extraField->packLocalFileData(), $binaryData);
|
||||||
|
self::assertSame($extraField->packCentralDirData(), $binaryData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideExtraField()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
NewUnixExtraField::USER_GID_PID,
|
||||||
|
NewUnixExtraField::USER_GID_PID,
|
||||||
|
"\x01\x04\xE8\x03\x00\x00\x04\xE8\x03\x00\x00",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
501,
|
||||||
|
20,
|
||||||
|
"\x01\x04\xF5\x01\x00\x00\x04\x14\x00\x00\x00",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
500,
|
||||||
|
495,
|
||||||
|
"\x01\x04\xF4\x01\x00\x00\x04\xEF\x01\x00\x00",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
11252,
|
||||||
|
10545,
|
||||||
|
"\x01\x04\xF4+\x00\x00\x041)\x00\x00",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
1721,
|
||||||
|
1721,
|
||||||
|
"\x01\x04\xB9\x06\x00\x00\x04\xB9\x06\x00\x00",
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetter()
|
||||||
|
{
|
||||||
|
$extraField = new NewUnixExtraField(1, 1000, 1000);
|
||||||
|
self::assertSame(1, $extraField->getVersion());
|
||||||
|
self::assertSame(1000, $extraField->getUid());
|
||||||
|
self::assertSame(1000, $extraField->getGid());
|
||||||
|
|
||||||
|
$extraField->setUid(0);
|
||||||
|
self::assertSame(0, $extraField->getUid());
|
||||||
|
self::assertSame(1000, $extraField->getGid());
|
||||||
|
|
||||||
|
$extraField->setGid(0);
|
||||||
|
self::assertSame(0, $extraField->getUid());
|
||||||
|
self::assertSame(0, $extraField->getGid());
|
||||||
|
}
|
||||||
|
}
|
245
tests/Extra/Fields/NtfsExtraFieldTest.php
Normal file
245
tests/Extra/Fields/NtfsExtraFieldTest.php
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpZip\Tests\Extra\Fields;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use PhpZip\Model\Extra\Fields\NtfsExtraField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class NtfsExtraFieldTest.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @small
|
||||||
|
*/
|
||||||
|
final class NtfsExtraFieldTest extends TestCase
|
||||||
|
{
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
if (\PHP_INT_SIZE === 4) {
|
||||||
|
self::markTestSkipped('only 64 bit test');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
) {
|
||||||
|
$extraField = new NtfsExtraField($modifyNtfsTime, $accessNtfsTime, $createNtfsTime);
|
||||||
|
self::assertSame($extraField->getHeaderId(), NtfsExtraField::HEADER_ID);
|
||||||
|
|
||||||
|
self::assertEquals($extraField->getModifyDateTime()->getTimestamp(), (int) $modifyTimestamp);
|
||||||
|
self::assertEquals($extraField->getAccessDateTime()->getTimestamp(), (int) $accessTimestamp);
|
||||||
|
self::assertEquals($extraField->getCreateDateTime()->getTimestamp(), (int) $createTimestamp);
|
||||||
|
|
||||||
|
self::assertEquals(NtfsExtraField::unpackLocalFileData($binaryData), $extraField);
|
||||||
|
self::assertEquals(NtfsExtraField::unpackCentralDirData($binaryData), $extraField);
|
||||||
|
|
||||||
|
self::assertSame($extraField->packLocalFileData(), $binaryData);
|
||||||
|
self::assertSame($extraField->packCentralDirData(), $binaryData);
|
||||||
|
|
||||||
|
$extraFieldFromDateTime = NtfsExtraField::create(
|
||||||
|
$extraField->getModifyDateTime(),
|
||||||
|
$extraField->getAccessDateTime(),
|
||||||
|
$extraField->getCreateDateTime()
|
||||||
|
);
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
129853553114795379,
|
||||||
|
129853553114795379,
|
||||||
|
129853552641022547,
|
||||||
|
1340881711.4795379,
|
||||||
|
1340881711.4795379,
|
||||||
|
1340881664.1022547,
|
||||||
|
"\x00\x00\x00\x00\x01\x00\x18\x00s\xCD:Z\x1EU\xCD\x01s\xCD:Z\x1EU\xCD\x01S\x9A\xFD=\x1EU\xCD\x01",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
131301570250000000,
|
||||||
|
131865940850000000,
|
||||||
|
131840940680000000,
|
||||||
|
1485683425.000000,
|
||||||
|
1542120485.000000,
|
||||||
|
1539620468.000000,
|
||||||
|
"\x00\x00\x00\x00\x01\x00\x18\x00\x80\xC63\x1D\x15z\xD2\x01\x80@V\xE2_{\xD4\x01\x00\xB2\x15\x14\xA3d\xD4\x01",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
132181086710000000,
|
||||||
|
132181086710000000,
|
||||||
|
132181086710000000,
|
||||||
|
1573635071.000000,
|
||||||
|
1573635071.000000,
|
||||||
|
1573635071.000000,
|
||||||
|
"\x00\x00\x00\x00\x01\x00\x18\x00\x80\xE9_\x7F\xFF\x99\xD5\x01\x80\xE9_\x7F\xFF\x99\xD5\x01\x80\xE9_\x7F\xFF\x99\xD5\x01",
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $expected
|
||||||
|
* @param int $actual
|
||||||
|
* @param int $delta
|
||||||
|
* @param string $message
|
||||||
|
*/
|
||||||
|
private static function assertEqualsIntegerWithDelta(
|
||||||
|
$expected,
|
||||||
|
$actual,
|
||||||
|
$delta,
|
||||||
|
$message = ''
|
||||||
|
) {
|
||||||
|
self::assertSame(
|
||||||
|
self::roundInt($expected, $delta),
|
||||||
|
self::roundInt($actual, $delta),
|
||||||
|
$message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $number
|
||||||
|
* @param int $delta
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
private static function roundInt($number, $delta)
|
||||||
|
{
|
||||||
|
return (int) (floor($number / $delta) * $delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
self::assertEqualsIntegerWithDelta(NtfsExtraField::timestampToNtfsTime($mtimeTimestamp), $mtimeNtfs, 10);
|
||||||
|
self::assertEqualsIntegerWithDelta(NtfsExtraField::timestampToNtfsTime($atimeTimestamp), $atimeNtfs, 10);
|
||||||
|
self::assertEqualsIntegerWithDelta(NtfsExtraField::timestampToNtfsTime($ctimeTimestamp), $ctimeNtfs, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function testSetter()
|
||||||
|
{
|
||||||
|
$timeZone = new \DateTimeZone('UTC');
|
||||||
|
$initDateTime = new \DateTimeImmutable('-1 min', $timeZone);
|
||||||
|
$mtimeDateTime = new \DateTimeImmutable('-1 hour', $timeZone);
|
||||||
|
$atimeDateTime = new \DateTimeImmutable('-1 day', $timeZone);
|
||||||
|
$ctimeDateTime = new \DateTimeImmutable('-1 year', $timeZone);
|
||||||
|
|
||||||
|
$extraField = NtfsExtraField::create($initDateTime, $initDateTime, $initDateTime);
|
||||||
|
self::assertEquals(
|
||||||
|
$extraField->getModifyDateTime()->getTimestamp(),
|
||||||
|
$initDateTime->getTimestamp()
|
||||||
|
);
|
||||||
|
self::assertEquals(
|
||||||
|
$extraField->getAccessDateTime()->getTimestamp(),
|
||||||
|
$initDateTime->getTimestamp()
|
||||||
|
);
|
||||||
|
self::assertEquals(
|
||||||
|
$extraField->getCreateDateTime()->getTimestamp(),
|
||||||
|
$initDateTime->getTimestamp()
|
||||||
|
);
|
||||||
|
|
||||||
|
$extraField->setModifyDateTime($mtimeDateTime);
|
||||||
|
self::assertEquals(
|
||||||
|
$extraField->getModifyDateTime()->getTimestamp(),
|
||||||
|
$mtimeDateTime->getTimestamp()
|
||||||
|
);
|
||||||
|
self::assertEquals(
|
||||||
|
$extraField->getAccessDateTime()->getTimestamp(),
|
||||||
|
$initDateTime->getTimestamp()
|
||||||
|
);
|
||||||
|
self::assertEquals(
|
||||||
|
$extraField->getCreateDateTime()->getTimestamp(),
|
||||||
|
$initDateTime->getTimestamp()
|
||||||
|
);
|
||||||
|
|
||||||
|
$extraField->setAccessDateTime($atimeDateTime);
|
||||||
|
self::assertEquals(
|
||||||
|
$extraField->getModifyDateTime()->getTimestamp(),
|
||||||
|
$mtimeDateTime->getTimestamp()
|
||||||
|
);
|
||||||
|
self::assertEquals(
|
||||||
|
$extraField->getAccessDateTime()->getTimestamp(),
|
||||||
|
$atimeDateTime->getTimestamp()
|
||||||
|
);
|
||||||
|
self::assertEquals(
|
||||||
|
$extraField->getCreateDateTime()->getTimestamp(),
|
||||||
|
$initDateTime->getTimestamp()
|
||||||
|
);
|
||||||
|
|
||||||
|
$extraField->setCreateDateTime($ctimeDateTime);
|
||||||
|
self::assertEquals(
|
||||||
|
$extraField->getModifyDateTime()->getTimestamp(),
|
||||||
|
$mtimeDateTime->getTimestamp()
|
||||||
|
);
|
||||||
|
self::assertEquals(
|
||||||
|
$extraField->getAccessDateTime()->getTimestamp(),
|
||||||
|
$atimeDateTime->getTimestamp()
|
||||||
|
);
|
||||||
|
self::assertEquals(
|
||||||
|
$extraField->getCreateDateTime()->getTimestamp(),
|
||||||
|
$ctimeDateTime->getTimestamp()
|
||||||
|
);
|
||||||
|
|
||||||
|
$newModifyNtfsTime = $extraField->getCreateNtfsTime();
|
||||||
|
$newAccessNtfsTime = $extraField->getModifyNtfsTime();
|
||||||
|
$newCreateNtfsTime = $extraField->getAccessNtfsTime();
|
||||||
|
$extraField->setModifyNtfsTime($newModifyNtfsTime);
|
||||||
|
$extraField->setAccessNtfsTime($newAccessNtfsTime);
|
||||||
|
$extraField->setCreateNtfsTime($newCreateNtfsTime);
|
||||||
|
self::assertSame($extraField->getModifyNtfsTime(), $newModifyNtfsTime);
|
||||||
|
self::assertSame($extraField->getAccessNtfsTime(), $newAccessNtfsTime);
|
||||||
|
self::assertSame($extraField->getCreateNtfsTime(), $newCreateNtfsTime);
|
||||||
|
}
|
||||||
|
}
|
156
tests/Extra/Fields/OldUnixExtraFieldTest.php
Normal file
156
tests/Extra/Fields/OldUnixExtraFieldTest.php
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpZip\Tests\Extra\Fields;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use PhpZip\Model\Extra\Fields\OldUnixExtraField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class OldUnixExtraFieldTest.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @small
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
*
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function testExtraField(
|
||||||
|
$accessTime,
|
||||||
|
$modifyTime,
|
||||||
|
$uid,
|
||||||
|
$gid,
|
||||||
|
$localBinaryData,
|
||||||
|
$cdBinaryData
|
||||||
|
) {
|
||||||
|
$extraField = new OldUnixExtraField($accessTime, $modifyTime, $uid, $gid);
|
||||||
|
self::assertSame($extraField->getHeaderId(), OldUnixExtraField::HEADER_ID);
|
||||||
|
|
||||||
|
self::assertSame($extraField->getAccessTime(), $accessTime);
|
||||||
|
self::assertSame($extraField->getModifyTime(), $modifyTime);
|
||||||
|
self::assertSame($extraField->getUid(), $uid);
|
||||||
|
self::assertSame($extraField->getGid(), $gid);
|
||||||
|
|
||||||
|
if ($extraField->getModifyTime() !== null) {
|
||||||
|
self::assertEquals(
|
||||||
|
new \DateTimeImmutable('@' . $extraField->getModifyTime()),
|
||||||
|
$extraField->getModifyDateTime()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($extraField->getAccessTime() !== null) {
|
||||||
|
self::assertEquals(
|
||||||
|
new \DateTimeImmutable('@' . $extraField->getAccessTime()),
|
||||||
|
$extraField->getAccessDateTime()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self::assertEquals(OldUnixExtraField::unpackLocalFileData($localBinaryData), $extraField);
|
||||||
|
self::assertSame($extraField->packLocalFileData(), $localBinaryData);
|
||||||
|
|
||||||
|
$uid = null;
|
||||||
|
$gid = null;
|
||||||
|
$extraField = new OldUnixExtraField($accessTime, $modifyTime, $uid, $gid);
|
||||||
|
self::assertSame($extraField->getHeaderId(), OldUnixExtraField::HEADER_ID);
|
||||||
|
|
||||||
|
self::assertSame($extraField->getAccessTime(), $accessTime);
|
||||||
|
self::assertSame($extraField->getModifyTime(), $modifyTime);
|
||||||
|
self::assertNull($extraField->getUid());
|
||||||
|
self::assertNull($extraField->getGid());
|
||||||
|
|
||||||
|
if ($extraField->getModifyTime() !== null) {
|
||||||
|
self::assertEquals(
|
||||||
|
new \DateTimeImmutable('@' . $extraField->getModifyTime()),
|
||||||
|
$extraField->getModifyDateTime()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($extraField->getAccessTime() !== null) {
|
||||||
|
self::assertEquals(
|
||||||
|
new \DateTimeImmutable('@' . $extraField->getAccessTime()),
|
||||||
|
$extraField->getAccessDateTime()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self::assertEquals(OldUnixExtraField::unpackCentralDirData($cdBinaryData), $extraField);
|
||||||
|
self::assertSame($extraField->packCentralDirData(), $cdBinaryData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideExtraField()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
1213373265,
|
||||||
|
1213365834,
|
||||||
|
502,
|
||||||
|
502,
|
||||||
|
"Q\x9BRHJ~RH\xF6\x01\xF6\x01",
|
||||||
|
"Q\x9BRHJ~RH",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
935520420,
|
||||||
|
935520401,
|
||||||
|
501,
|
||||||
|
100,
|
||||||
|
"\xA4\xE8\xC27\x91\xE8\xC27\xF5\x01d\x00",
|
||||||
|
"\xA4\xE8\xC27\x91\xE8\xC27",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1402666135,
|
||||||
|
1402666135,
|
||||||
|
501,
|
||||||
|
20,
|
||||||
|
"\x97\xFC\x9AS\x97\xFC\x9AS\xF5\x01\x14\x00",
|
||||||
|
"\x97\xFC\x9AS\x97\xFC\x9AS",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetter()
|
||||||
|
{
|
||||||
|
$extraField = new OldUnixExtraField(null, null, null, null);
|
||||||
|
|
||||||
|
self::assertNull($extraField->getAccessTime());
|
||||||
|
self::assertNull($extraField->getAccessDateTime());
|
||||||
|
self::assertNull($extraField->getModifyTime());
|
||||||
|
self::assertNull($extraField->getModifyDateTime());
|
||||||
|
self::assertNull($extraField->getUid());
|
||||||
|
self::assertNull($extraField->getGid());
|
||||||
|
|
||||||
|
$extraField->setModifyTime(1402666135);
|
||||||
|
self::assertSame($extraField->getModifyTime(), 1402666135);
|
||||||
|
|
||||||
|
$extraField->setAccessTime(1213365834);
|
||||||
|
self::assertSame($extraField->getAccessTime(), 1213365834);
|
||||||
|
|
||||||
|
$extraField->setUid(500);
|
||||||
|
self::assertSame($extraField->getUid(), 500);
|
||||||
|
|
||||||
|
$extraField->setGid(100);
|
||||||
|
self::assertSame($extraField->getGid(), 100);
|
||||||
|
}
|
||||||
|
}
|
42
tests/Extra/Fields/UnicodeCommentExtraFieldTest.php
Normal file
42
tests/Extra/Fields/UnicodeCommentExtraFieldTest.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpZip\Tests\Extra\Fields;
|
||||||
|
|
||||||
|
use PhpZip\Model\Extra\Fields\UnicodeCommentExtraField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @small
|
||||||
|
*/
|
||||||
|
final class UnicodeCommentExtraFieldTest extends AbstractUnicodeExtraFieldTest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function getUnicodeExtraFieldClassName()
|
||||||
|
{
|
||||||
|
return UnicodeCommentExtraField::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideExtraField()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
4293813303,
|
||||||
|
'комментарий',
|
||||||
|
"\xAA\xAE\xAC\xAC\xA5\xAD\xE2\xA0\xE0\xA8\xA9",
|
||||||
|
"\x017d\xEE\xFF\xD0\xBA\xD0\xBE\xD0\xBC\xD0\xBC\xD0\xB5\xD0\xBD\xD1\x82\xD0\xB0\xD1\x80\xD0\xB8\xD0\xB9",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
897024324,
|
||||||
|
'תגובה',
|
||||||
|
"\x9A\x82\x85\x81\x84",
|
||||||
|
"\x01D\x81w5\xD7\xAA\xD7\x92\xD7\x95\xD7\x91\xD7\x94",
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
56
tests/Extra/Fields/UnicodePathExtraFieldTest.php
Normal file
56
tests/Extra/Fields/UnicodePathExtraFieldTest.php
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpZip\Tests\Extra\Fields;
|
||||||
|
|
||||||
|
use PhpZip\Model\Extra\Fields\UnicodePathExtraField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class UnicodePathExtraFieldTest.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @small
|
||||||
|
*/
|
||||||
|
final class UnicodePathExtraFieldTest extends AbstractUnicodeExtraFieldTest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function getUnicodeExtraFieldClassName()
|
||||||
|
{
|
||||||
|
return UnicodePathExtraField::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideExtraField()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
2728523760,
|
||||||
|
'txt\מבחן עברי.txt',
|
||||||
|
"txt/\x8E\x81\x87\x8F \x92\x81\x98\x89.txt",
|
||||||
|
"\x01\xF0\xF7\xA1\xA2txt\\\xD7\x9E\xD7\x91\xD7\x97\xD7\x9F \xD7\xA2\xD7\x91\xD7\xA8\xD7\x99.txt",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
953311492,
|
||||||
|
'ä\ü.txt',
|
||||||
|
"\x84/\x81.txt",
|
||||||
|
"\x01\x04a\xD28\xC3\xA4\\\xC3\xBC.txt",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
2965532848,
|
||||||
|
'Ölfässer.txt',
|
||||||
|
"\x99lf\x84sser.txt",
|
||||||
|
"\x01\xB0p\xC2\xB0\xC3\x96lf\xC3\xA4sser.txt",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3434671236,
|
||||||
|
'Как заработать в интернете.mp4',
|
||||||
|
"\x8A\xA0\xAA \xA7\xA0\xE0\xA0\xA1\xAE\xE2\xA0\xE2\xEC \xA2 \xA8\xAD\xE2\xA5\xE0\xAD\xA5\xE2\xA5.mp4",
|
||||||
|
"\x01\x84\xEC\xB8\xCC\xD0\x9A\xD0\xB0\xD0\xBA \xD0\xB7\xD0\xB0\xD1\x80\xD0\xB0\xD0\xB1\xD0\xBE\xD1\x82\xD0\xB0\xD1\x82\xD1\x8C \xD0\xB2 \xD0\xB8\xD0\xBD\xD1\x82\xD0\xB5\xD1\x80\xD0\xBD\xD0\xB5\xD1\x82\xD0\xB5.mp4",
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
57
tests/Extra/Fields/UnrecognizedExtraFieldTest.php
Normal file
57
tests/Extra/Fields/UnrecognizedExtraFieldTest.php
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpZip\Tests\Extra\Fields;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use PhpZip\Exception\RuntimeException;
|
||||||
|
use PhpZip\Model\Extra\Fields\UnrecognizedExtraField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class UnrecognizedExtraFieldTest.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @small
|
||||||
|
*/
|
||||||
|
final class UnrecognizedExtraFieldTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testExtraField()
|
||||||
|
{
|
||||||
|
$headerId = 0xF00D;
|
||||||
|
$binaryData = "\x01\x02\x03\x04\x05";
|
||||||
|
|
||||||
|
$unrecognizedExtraField = new UnrecognizedExtraField($headerId, $binaryData);
|
||||||
|
self::assertSame($unrecognizedExtraField->getHeaderId(), $headerId);
|
||||||
|
self::assertSame($unrecognizedExtraField->getData(), $binaryData);
|
||||||
|
|
||||||
|
$newHeaderId = 0xDADA;
|
||||||
|
$newBinaryData = "\x05\x00";
|
||||||
|
$unrecognizedExtraField->setHeaderId($newHeaderId);
|
||||||
|
self::assertSame($unrecognizedExtraField->getHeaderId(), $newHeaderId);
|
||||||
|
$unrecognizedExtraField->setData($newBinaryData);
|
||||||
|
self::assertSame($unrecognizedExtraField->getData(), $newBinaryData);
|
||||||
|
|
||||||
|
self::assertSame($unrecognizedExtraField->packLocalFileData(), $newBinaryData);
|
||||||
|
self::assertSame($unrecognizedExtraField->packCentralDirData(), $newBinaryData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUnpackLocalData()
|
||||||
|
{
|
||||||
|
$this->setExpectedException(
|
||||||
|
RuntimeException::class,
|
||||||
|
'Unsupport parse'
|
||||||
|
);
|
||||||
|
|
||||||
|
UnrecognizedExtraField::unpackLocalFileData("\x01\x02");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUnpackCentralDirData()
|
||||||
|
{
|
||||||
|
$this->setExpectedException(
|
||||||
|
RuntimeException::class,
|
||||||
|
'Unsupport parse'
|
||||||
|
);
|
||||||
|
|
||||||
|
UnrecognizedExtraField::unpackCentralDirData("\x01\x02");
|
||||||
|
}
|
||||||
|
}
|
240
tests/Extra/Fields/WinZipAesExtraFieldTest.php
Normal file
240
tests/Extra/Fields/WinZipAesExtraFieldTest.php
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpZip\Tests\Extra\Fields;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use PhpZip\Constants\ZipCompressionMethod;
|
||||||
|
use PhpZip\Constants\ZipEncryptionMethod;
|
||||||
|
use PhpZip\Exception\InvalidArgumentException;
|
||||||
|
use PhpZip\Exception\ZipException;
|
||||||
|
use PhpZip\Exception\ZipUnsupportMethodException;
|
||||||
|
use PhpZip\Model\Extra\Fields\WinZipAesExtraField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @small
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
) {
|
||||||
|
$extraField = new WinZipAesExtraField($vendorVersion, $keyStrength, $compressionMethod);
|
||||||
|
self::assertSame($extraField->getHeaderId(), WinZipAesExtraField::HEADER_ID);
|
||||||
|
self::assertSame($extraField->getVendorVersion(), $vendorVersion);
|
||||||
|
self::assertSame($extraField->getKeyStrength(), $keyStrength);
|
||||||
|
self::assertSame($extraField->getCompressionMethod(), $compressionMethod);
|
||||||
|
self::assertSame($extraField->getVendorId(), WinZipAesExtraField::VENDOR_ID);
|
||||||
|
self::assertSame($extraField->getSaltSize(), $saltSize);
|
||||||
|
|
||||||
|
self::assertSame($binaryData, $extraField->packLocalFileData());
|
||||||
|
self::assertSame($binaryData, $extraField->packCentralDirData());
|
||||||
|
self::assertEquals(WinZipAesExtraField::unpackLocalFileData($binaryData), $extraField);
|
||||||
|
self::assertEquals(WinZipAesExtraField::unpackCentralDirData($binaryData), $extraField);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideExtraField()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
WinZipAesExtraField::VERSION_AE1,
|
||||||
|
WinZipAesExtraField::KEY_STRENGTH_128BIT,
|
||||||
|
ZipCompressionMethod::STORED,
|
||||||
|
8,
|
||||||
|
"\x01\x00AE\x01\x00\x00",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
WinZipAesExtraField::VERSION_AE1,
|
||||||
|
WinZipAesExtraField::KEY_STRENGTH_192BIT,
|
||||||
|
ZipCompressionMethod::DEFLATED,
|
||||||
|
12,
|
||||||
|
"\x01\x00AE\x02\x08\x00",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
WinZipAesExtraField::VERSION_AE2,
|
||||||
|
WinZipAesExtraField::KEY_STRENGTH_128BIT,
|
||||||
|
ZipCompressionMethod::DEFLATED,
|
||||||
|
8,
|
||||||
|
"\x02\x00AE\x01\x08\x00",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
WinZipAesExtraField::VERSION_AE2,
|
||||||
|
WinZipAesExtraField::KEY_STRENGTH_256BIT,
|
||||||
|
ZipCompressionMethod::STORED,
|
||||||
|
16,
|
||||||
|
"\x02\x00AE\x03\x00\x00",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
WinZipAesExtraField::VERSION_AE2,
|
||||||
|
WinZipAesExtraField::KEY_STRENGTH_192BIT,
|
||||||
|
ZipCompressionMethod::DEFLATED,
|
||||||
|
12,
|
||||||
|
"\x02\x00AE\x02\x08\x00",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
WinZipAesExtraField::VERSION_AE2,
|
||||||
|
WinZipAesExtraField::KEY_STRENGTH_256BIT,
|
||||||
|
ZipCompressionMethod::STORED,
|
||||||
|
16,
|
||||||
|
"\x02\x00AE\x03\x00\x00",
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipUnsupportMethodException
|
||||||
|
*/
|
||||||
|
public function testSetter()
|
||||||
|
{
|
||||||
|
$extraField = new WinZipAesExtraField(
|
||||||
|
WinZipAesExtraField::VERSION_AE1,
|
||||||
|
WinZipAesExtraField::KEY_STRENGTH_256BIT,
|
||||||
|
ZipCompressionMethod::DEFLATED
|
||||||
|
);
|
||||||
|
|
||||||
|
self::assertSame($extraField->getVendorVersion(), WinZipAesExtraField::VERSION_AE1);
|
||||||
|
self::assertSame($extraField->getKeyStrength(), WinZipAesExtraField::KEY_STRENGTH_256BIT);
|
||||||
|
self::assertSame($extraField->getCompressionMethod(), ZipCompressionMethod::DEFLATED);
|
||||||
|
self::assertSame($extraField->getSaltSize(), 16);
|
||||||
|
self::assertSame($extraField->getEncryptionStrength(), 256);
|
||||||
|
self::assertSame($extraField->getEncryptionMethod(), ZipEncryptionMethod::WINZIP_AES_256);
|
||||||
|
|
||||||
|
$extraField->setVendorVersion(WinZipAesExtraField::VERSION_AE2);
|
||||||
|
self::assertSame($extraField->getVendorVersion(), WinZipAesExtraField::VERSION_AE2);
|
||||||
|
self::assertSame($extraField->getKeyStrength(), WinZipAesExtraField::KEY_STRENGTH_256BIT);
|
||||||
|
self::assertSame($extraField->getCompressionMethod(), ZipCompressionMethod::DEFLATED);
|
||||||
|
self::assertSame($extraField->getSaltSize(), 16);
|
||||||
|
self::assertSame($extraField->getEncryptionStrength(), 256);
|
||||||
|
self::assertSame($extraField->getEncryptionMethod(), ZipEncryptionMethod::WINZIP_AES_256);
|
||||||
|
|
||||||
|
$extraField->setKeyStrength(WinZipAesExtraField::KEY_STRENGTH_128BIT);
|
||||||
|
self::assertSame($extraField->getVendorVersion(), WinZipAesExtraField::VERSION_AE2);
|
||||||
|
self::assertSame($extraField->getKeyStrength(), WinZipAesExtraField::KEY_STRENGTH_128BIT);
|
||||||
|
self::assertSame($extraField->getCompressionMethod(), ZipCompressionMethod::DEFLATED);
|
||||||
|
self::assertSame($extraField->getSaltSize(), 8);
|
||||||
|
self::assertSame($extraField->getEncryptionStrength(), 128);
|
||||||
|
self::assertSame($extraField->getEncryptionMethod(), ZipEncryptionMethod::WINZIP_AES_128);
|
||||||
|
|
||||||
|
$extraField->setKeyStrength(WinZipAesExtraField::KEY_STRENGTH_192BIT);
|
||||||
|
self::assertSame($extraField->getVendorVersion(), WinZipAesExtraField::VERSION_AE2);
|
||||||
|
self::assertSame($extraField->getKeyStrength(), WinZipAesExtraField::KEY_STRENGTH_192BIT);
|
||||||
|
self::assertSame($extraField->getCompressionMethod(), ZipCompressionMethod::DEFLATED);
|
||||||
|
self::assertSame($extraField->getSaltSize(), 12);
|
||||||
|
self::assertSame($extraField->getEncryptionStrength(), 192);
|
||||||
|
self::assertSame($extraField->getEncryptionMethod(), ZipEncryptionMethod::WINZIP_AES_192);
|
||||||
|
|
||||||
|
$extraField->setCompressionMethod(ZipCompressionMethod::STORED);
|
||||||
|
self::assertSame($extraField->getVendorVersion(), WinZipAesExtraField::VERSION_AE2);
|
||||||
|
self::assertSame($extraField->getKeyStrength(), WinZipAesExtraField::KEY_STRENGTH_192BIT);
|
||||||
|
self::assertSame($extraField->getCompressionMethod(), ZipCompressionMethod::STORED);
|
||||||
|
self::assertSame($extraField->getSaltSize(), 12);
|
||||||
|
self::assertSame($extraField->getEncryptionStrength(), 192);
|
||||||
|
self::assertSame($extraField->getEncryptionMethod(), ZipEncryptionMethod::WINZIP_AES_192);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipUnsupportMethodException
|
||||||
|
*/
|
||||||
|
public function testConstructUnsupportVendorVersion()
|
||||||
|
{
|
||||||
|
$this->setExpectedException(InvalidArgumentException::class, 'Unsupport WinZip AES vendor version: 3');
|
||||||
|
|
||||||
|
new WinZipAesExtraField(
|
||||||
|
3,
|
||||||
|
WinZipAesExtraField::KEY_STRENGTH_192BIT,
|
||||||
|
ZipCompressionMethod::STORED
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipUnsupportMethodException
|
||||||
|
*/
|
||||||
|
public function testSetterUnsupportVendorVersion()
|
||||||
|
{
|
||||||
|
$this->setExpectedException(InvalidArgumentException::class, 'Unsupport WinZip AES vendor version: 3');
|
||||||
|
|
||||||
|
$extraField = new WinZipAesExtraField(
|
||||||
|
WinZipAesExtraField::VERSION_AE1,
|
||||||
|
WinZipAesExtraField::KEY_STRENGTH_192BIT,
|
||||||
|
ZipCompressionMethod::STORED
|
||||||
|
);
|
||||||
|
$extraField->setVendorVersion(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipUnsupportMethodException
|
||||||
|
*/
|
||||||
|
public function testConstructUnsupportCompressionMethod()
|
||||||
|
{
|
||||||
|
$this->setExpectedException(ZipUnsupportMethodException::class, 'Compression method 3 (Reduced compression factor 2) is not supported.');
|
||||||
|
|
||||||
|
new WinZipAesExtraField(
|
||||||
|
WinZipAesExtraField::VERSION_AE1,
|
||||||
|
WinZipAesExtraField::KEY_STRENGTH_192BIT,
|
||||||
|
3
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipUnsupportMethodException
|
||||||
|
*/
|
||||||
|
public function testSetterUnsupportCompressionMethod()
|
||||||
|
{
|
||||||
|
$this->setExpectedException(ZipUnsupportMethodException::class, 'Compression method 3 (Reduced compression factor 2) is not supported.');
|
||||||
|
|
||||||
|
$extraField = new WinZipAesExtraField(
|
||||||
|
WinZipAesExtraField::VERSION_AE1,
|
||||||
|
WinZipAesExtraField::KEY_STRENGTH_192BIT,
|
||||||
|
ZipCompressionMethod::STORED
|
||||||
|
);
|
||||||
|
$extraField->setCompressionMethod(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipUnsupportMethodException
|
||||||
|
*/
|
||||||
|
public function testConstructUnsupportKeyStrength()
|
||||||
|
{
|
||||||
|
$this->setExpectedException(InvalidArgumentException::class, 'Key strength 16 not support value. Allow values: 1, 2, 3');
|
||||||
|
|
||||||
|
new WinZipAesExtraField(
|
||||||
|
WinZipAesExtraField::VERSION_AE1,
|
||||||
|
0x10,
|
||||||
|
ZipCompressionMethod::STORED
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipUnsupportMethodException
|
||||||
|
*/
|
||||||
|
public function testSetterUnsupportKeyStrength()
|
||||||
|
{
|
||||||
|
$this->setExpectedException(InvalidArgumentException::class, 'Key strength 16 not support value. Allow values: 1, 2, 3');
|
||||||
|
|
||||||
|
new WinZipAesExtraField(
|
||||||
|
WinZipAesExtraField::VERSION_AE1,
|
||||||
|
0x10,
|
||||||
|
ZipCompressionMethod::STORED
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
132
tests/Extra/Fields/Zip64ExtraFieldTest.php
Normal file
132
tests/Extra/Fields/Zip64ExtraFieldTest.php
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpZip\Tests\Extra\Fields;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use PhpZip\Constants\ZipConstants;
|
||||||
|
use PhpZip\Exception\ZipException;
|
||||||
|
use PhpZip\Model\Extra\Fields\Zip64ExtraField;
|
||||||
|
use PhpZip\Model\ZipEntry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @small
|
||||||
|
*/
|
||||||
|
final class Zip64ExtraFieldTest extends TestCase
|
||||||
|
{
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
if (\PHP_INT_SIZE === 4) {
|
||||||
|
self::markTestSkipped('only 64 bit test');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*
|
||||||
|
* @throws ZipException
|
||||||
|
*
|
||||||
|
* @noinspection PhpTooManyParametersInspection
|
||||||
|
*/
|
||||||
|
public function testExtraField(
|
||||||
|
$uncompressedSize,
|
||||||
|
$compressedSize,
|
||||||
|
$localHeaderOffset,
|
||||||
|
$diskStart,
|
||||||
|
$localBinaryData,
|
||||||
|
$cdBinaryData
|
||||||
|
) {
|
||||||
|
$extraField = new Zip64ExtraField(
|
||||||
|
$uncompressedSize,
|
||||||
|
$compressedSize,
|
||||||
|
$localHeaderOffset,
|
||||||
|
$diskStart
|
||||||
|
);
|
||||||
|
self::assertSame($extraField->getHeaderId(), Zip64ExtraField::HEADER_ID);
|
||||||
|
self::assertSame($extraField->getUncompressedSize(), $uncompressedSize);
|
||||||
|
self::assertSame($extraField->getCompressedSize(), $compressedSize);
|
||||||
|
self::assertSame($extraField->getLocalHeaderOffset(), $localHeaderOffset);
|
||||||
|
self::assertSame($extraField->getDiskStart(), $diskStart);
|
||||||
|
|
||||||
|
$zipEntry = new ZipEntry('entry');
|
||||||
|
$zipEntry->setUncompressedSize($uncompressedSize !== null ? ZipConstants::ZIP64_MAGIC : 0xfffff);
|
||||||
|
$zipEntry->setCompressedSize($compressedSize !== null ? ZipConstants::ZIP64_MAGIC : 0xffff);
|
||||||
|
$zipEntry->setLocalHeaderOffset($localHeaderOffset !== null ? ZipConstants::ZIP64_MAGIC : 0xfff);
|
||||||
|
|
||||||
|
if ($localBinaryData !== null) {
|
||||||
|
self::assertSame($localBinaryData, $extraField->packLocalFileData());
|
||||||
|
self::assertEquals(Zip64ExtraField::unpackLocalFileData($localBinaryData, $zipEntry), $extraField);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($cdBinaryData !== null) {
|
||||||
|
self::assertSame($cdBinaryData, $extraField->packCentralDirData());
|
||||||
|
self::assertEquals(Zip64ExtraField::unpackCentralDirData($cdBinaryData, $zipEntry), $extraField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideExtraField()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
"\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00",
|
||||||
|
null,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
5368709120,
|
||||||
|
5369580144,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
"\x00\x00\x00@\x01\x00\x00\x00pJ\x0D@\x01\x00\x00\x00",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
4945378839,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
"\x17~\xC4&\x01\x00\x00\x00",
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetter()
|
||||||
|
{
|
||||||
|
$extraField = new Zip64ExtraField();
|
||||||
|
self::assertNull($extraField->getUncompressedSize());
|
||||||
|
self::assertNull($extraField->getCompressedSize());
|
||||||
|
self::assertNull($extraField->getLocalHeaderOffset());
|
||||||
|
self::assertNull($extraField->getDiskStart());
|
||||||
|
|
||||||
|
$uncompressedSize = 12222;
|
||||||
|
$extraField->setUncompressedSize($uncompressedSize);
|
||||||
|
self::assertSame($extraField->getUncompressedSize(), $uncompressedSize);
|
||||||
|
|
||||||
|
$compressedSize = 12222;
|
||||||
|
$extraField->setCompressedSize($uncompressedSize);
|
||||||
|
self::assertSame($extraField->getCompressedSize(), $compressedSize);
|
||||||
|
|
||||||
|
$localHeaderOffset = 12222;
|
||||||
|
$extraField->setLocalHeaderOffset($localHeaderOffset);
|
||||||
|
self::assertSame($extraField->getLocalHeaderOffset(), $localHeaderOffset);
|
||||||
|
|
||||||
|
$diskStart = 2;
|
||||||
|
$extraField->setDiskStart($diskStart);
|
||||||
|
self::assertSame($extraField->getDiskStart(), $diskStart);
|
||||||
|
}
|
||||||
|
}
|
39
tests/Internal/CustomZip/CustomZipWriter.php
Normal file
39
tests/Internal/CustomZip/CustomZipWriter.php
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
parent::beforeWrite();
|
||||||
|
$now = new \DateTimeImmutable();
|
||||||
|
$ntfsTimeExtra = NtfsExtraField::create($now, $now->modify('-1 day'), $now->modify('-10 day'));
|
||||||
|
$unixExtra = new NewUnixExtraField();
|
||||||
|
|
||||||
|
foreach ($this->zipContainer->getEntries() as $entry) {
|
||||||
|
$entry->addExtraField($ntfsTimeExtra);
|
||||||
|
$entry->addExtraField($unixExtra);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
tests/Internal/CustomZip/ZipFileCustomWriter.php
Normal file
20
tests/Internal/CustomZip/ZipFileCustomWriter.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpZip\Tests\Internal\CustomZip;
|
||||||
|
|
||||||
|
use PhpZip\IO\ZipWriter;
|
||||||
|
use PhpZip\ZipFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ZipFileCustomWriter.
|
||||||
|
*/
|
||||||
|
class ZipFileCustomWriter extends ZipFile
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return ZipWriter
|
||||||
|
*/
|
||||||
|
protected function createZipWriter()
|
||||||
|
{
|
||||||
|
return new CustomZipWriter($this->zipContainer);
|
||||||
|
}
|
||||||
|
}
|
28
tests/Internal/CustomZip/ZipFileWithBeforeSave.php
Normal file
28
tests/Internal/CustomZip/ZipFileWithBeforeSave.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
$now = new \DateTimeImmutable();
|
||||||
|
$ntfsTimeExtra = NtfsExtraField::create($now, $now->modify('-1 day'), $now->modify('-10 day'));
|
||||||
|
$unixExtra = new NewUnixExtraField();
|
||||||
|
|
||||||
|
foreach ($this->zipContainer->getEntries() as $entry) {
|
||||||
|
$entry->addExtraField($ntfsTimeExtra);
|
||||||
|
$entry->addExtraField($unixExtra);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
98
tests/Internal/Epub/EpubFile.php
Normal file
98
tests/Internal/Epub/EpubFile.php
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/** @noinspection PhpComposerExtensionStubsInspection */
|
||||||
|
|
||||||
|
namespace PhpZip\Tests\Internal\Epub;
|
||||||
|
|
||||||
|
use PhpZip\Constants\ZipPlatform;
|
||||||
|
use PhpZip\Exception\ZipEntryNotFoundException;
|
||||||
|
use PhpZip\Exception\ZipException;
|
||||||
|
use PhpZip\IO\ZipReader;
|
||||||
|
use PhpZip\IO\ZipWriter;
|
||||||
|
use PhpZip\Model\ImmutableZipContainer;
|
||||||
|
use PhpZip\Model\ZipContainer;
|
||||||
|
use PhpZip\Model\ZipEntry;
|
||||||
|
use PhpZip\ZipFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class EpubFile.
|
||||||
|
*
|
||||||
|
* @property EpubZipContainer $zipContainer
|
||||||
|
*/
|
||||||
|
class EpubFile extends ZipFile
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return ZipWriter
|
||||||
|
*/
|
||||||
|
protected function createZipWriter()
|
||||||
|
{
|
||||||
|
return new EpubWriter($this->zipContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param resource $inputStream
|
||||||
|
* @param array $options
|
||||||
|
*
|
||||||
|
* @return ZipReader
|
||||||
|
*/
|
||||||
|
protected function createZipReader($inputStream, array $options = [])
|
||||||
|
{
|
||||||
|
return new EpubReader($inputStream, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ImmutableZipContainer|null $sourceContainer
|
||||||
|
*
|
||||||
|
* @return ZipContainer
|
||||||
|
*/
|
||||||
|
protected function createZipContainer(ImmutableZipContainer $sourceContainer = null)
|
||||||
|
{
|
||||||
|
return new EpubZipContainer($sourceContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ZipEntry $zipEntry
|
||||||
|
*/
|
||||||
|
protected function addZipEntry(ZipEntry $zipEntry)
|
||||||
|
{
|
||||||
|
$zipEntry->setCreatedOS(ZipPlatform::OS_DOS);
|
||||||
|
$zipEntry->setExtractedOS(ZipPlatform::OS_UNIX);
|
||||||
|
parent::addZipEntry($zipEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipEntryNotFoundException
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getMimeType()
|
||||||
|
{
|
||||||
|
return $this->zipContainer->getMimeType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEpubInfo()
|
||||||
|
{
|
||||||
|
return new EpubInfo($this->getEntryContents($this->getRootFile()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipException
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRootFile()
|
||||||
|
{
|
||||||
|
$entryName = 'META-INF/container.xml';
|
||||||
|
$contents = $this->getEntryContents($entryName);
|
||||||
|
$doc = new \DOMDocument();
|
||||||
|
$doc->loadXML($contents);
|
||||||
|
$xpath = new \DOMXPath($doc);
|
||||||
|
$rootFile = $xpath->evaluate('string(//@full-path)');
|
||||||
|
|
||||||
|
if ($rootFile === '') {
|
||||||
|
throw new ZipException('Incorrect ' . $entryName . ' file format');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $rootFile;
|
||||||
|
}
|
||||||
|
}
|
159
tests/Internal/Epub/EpubInfo.php
Normal file
159
tests/Internal/Epub/EpubInfo.php
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/** @noinspection PhpComposerExtensionStubsInspection */
|
||||||
|
|
||||||
|
namespace PhpZip\Tests\Internal\Epub;
|
||||||
|
|
||||||
|
use PhpZip\Exception\ZipException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class EpubInfo.
|
||||||
|
*
|
||||||
|
* @see http://idpf.org/epub/30/spec/epub30-publications.html
|
||||||
|
*/
|
||||||
|
class EpubInfo
|
||||||
|
{
|
||||||
|
/** @var string|null */
|
||||||
|
private $title;
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
private $creator;
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
private $language;
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
private $publisher;
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
private $description;
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
private $rights;
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
private $date;
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
private $subject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EpubInfo constructor.
|
||||||
|
*
|
||||||
|
* @param $xmlContents
|
||||||
|
*
|
||||||
|
* @throws ZipException
|
||||||
|
*/
|
||||||
|
public function __construct($xmlContents)
|
||||||
|
{
|
||||||
|
$doc = new \DOMDocument();
|
||||||
|
$doc->loadXML($xmlContents);
|
||||||
|
$xpath = new \DOMXpath($doc);
|
||||||
|
$xpath->registerNamespace('root', 'http://www.idpf.org/2007/opf');
|
||||||
|
$metaDataNodeList = $xpath->query('//root:metadata');
|
||||||
|
|
||||||
|
if (\count($metaDataNodeList) !== 1) {
|
||||||
|
throw new ZipException('Invalid .opf file format');
|
||||||
|
}
|
||||||
|
$metaDataNode = $metaDataNodeList->item(0);
|
||||||
|
|
||||||
|
$title = $xpath->evaluate('string(//dc:title)', $metaDataNode);
|
||||||
|
$creator = $xpath->evaluate('string(//dc:creator)', $metaDataNode);
|
||||||
|
$language = $xpath->evaluate('string(//dc:language)', $metaDataNode);
|
||||||
|
$publisher = $xpath->evaluate('string(//dc:publisher)', $metaDataNode);
|
||||||
|
$description = $xpath->evaluate('string(//dc:description)', $metaDataNode);
|
||||||
|
$rights = $xpath->evaluate('string(//dc:rights)', $metaDataNode);
|
||||||
|
$date = $xpath->evaluate('string(//dc:date)', $metaDataNode);
|
||||||
|
$subject = $xpath->evaluate('string(//dc:subject)', $metaDataNode);
|
||||||
|
|
||||||
|
$this->title = empty($title) ? null : $title;
|
||||||
|
$this->creator = empty($creator) ? null : $creator;
|
||||||
|
$this->language = empty($language) ? null : $language;
|
||||||
|
$this->publisher = empty($publisher) ? null : $publisher;
|
||||||
|
$this->description = empty($description) ? null : $description;
|
||||||
|
$this->rights = empty($rights) ? null : $rights;
|
||||||
|
$this->date = empty($date) ? null : $date;
|
||||||
|
$this->subject = empty($subject) ? null : $subject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getTitle()
|
||||||
|
{
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getCreator()
|
||||||
|
{
|
||||||
|
return $this->creator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getLanguage()
|
||||||
|
{
|
||||||
|
return $this->language;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getPublisher()
|
||||||
|
{
|
||||||
|
return $this->publisher;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getDescription()
|
||||||
|
{
|
||||||
|
return $this->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getRights()
|
||||||
|
{
|
||||||
|
return $this->rights;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getDate()
|
||||||
|
{
|
||||||
|
return $this->date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getSubject()
|
||||||
|
{
|
||||||
|
return $this->subject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function toArray()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'title' => $this->title,
|
||||||
|
'creator' => $this->creator,
|
||||||
|
'language' => $this->language,
|
||||||
|
'publisher' => $this->publisher,
|
||||||
|
'description' => $this->description,
|
||||||
|
'rights' => $this->rights,
|
||||||
|
'date' => $this->date,
|
||||||
|
'subject' => $this->subject,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
21
tests/Internal/Epub/EpubReader.php
Normal file
21
tests/Internal/Epub/EpubReader.php
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpZip\Tests\Internal\Epub;
|
||||||
|
|
||||||
|
use PhpZip\IO\ZipReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class EpubReader.
|
||||||
|
*/
|
||||||
|
class EpubReader extends ZipReader
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*
|
||||||
|
* @see https://github.com/w3c/epubcheck/issues/334
|
||||||
|
*/
|
||||||
|
protected function isZip64Support()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
66
tests/Internal/Epub/EpubWriter.php
Normal file
66
tests/Internal/Epub/EpubWriter.php
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpZip\Tests\Internal\Epub;
|
||||||
|
|
||||||
|
use PhpZip\Constants\ZipCompressionMethod;
|
||||||
|
use PhpZip\Constants\ZipPlatform;
|
||||||
|
use PhpZip\Exception\ZipUnsupportMethodException;
|
||||||
|
use PhpZip\IO\ZipWriter;
|
||||||
|
use PhpZip\Model\Data\ZipNewData;
|
||||||
|
use PhpZip\Model\ZipEntry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class EpubWriter.
|
||||||
|
*
|
||||||
|
* @property EpubZipContainer $zipContainer
|
||||||
|
*/
|
||||||
|
class EpubWriter extends ZipWriter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws ZipUnsupportMethodException
|
||||||
|
*/
|
||||||
|
protected function beforeWrite()
|
||||||
|
{
|
||||||
|
parent::beforeWrite();
|
||||||
|
|
||||||
|
if (!$this->zipContainer->hasEntry('mimetype')) {
|
||||||
|
$zipEntry = new ZipEntry('mimetype');
|
||||||
|
$zipEntry->setCreatedOS(ZipPlatform::OS_DOS);
|
||||||
|
$zipEntry->setExtractedOS(ZipPlatform::OS_DOS);
|
||||||
|
$zipEntry->setCompressionMethod(ZipCompressionMethod::STORED);
|
||||||
|
$zipEntry->setData(new ZipNewData($zipEntry, 'application/epub+zip'));
|
||||||
|
$this->zipContainer->addEntry($zipEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->sortEntries();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sortEntries()
|
||||||
|
{
|
||||||
|
$this->zipContainer->sortByEntry(
|
||||||
|
static function (ZipEntry $a, ZipEntry $b) {
|
||||||
|
if (strcasecmp($a->getName(), 'mimetype') === 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcasecmp($b->getName(), 'mimetype') === 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($a->isDirectory() && $b->isDirectory()) {
|
||||||
|
return strcmp($a->getName(), $b->getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($a->isDirectory()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($b->isDirectory()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return strcmp($a->getName(), $b->getName());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
22
tests/Internal/Epub/EpubZipContainer.php
Normal file
22
tests/Internal/Epub/EpubZipContainer.php
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
return $this->getEntry('mimetype')->getData()->getDataAsString();
|
||||||
|
}
|
||||||
|
}
|
88
tests/SymlinkTest.php
Normal file
88
tests/SymlinkTest.php
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpZip\Tests;
|
||||||
|
|
||||||
|
use PhpZip\Constants\ZipOptions;
|
||||||
|
use PhpZip\Util\FilesUtil;
|
||||||
|
use PhpZip\ZipFile;
|
||||||
|
use Symfony\Component\Finder\Finder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @small
|
||||||
|
*/
|
||||||
|
final class SymlinkTest extends ZipFileTest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* This method is called before the first test of this test class is run.
|
||||||
|
*/
|
||||||
|
public static function setUpBeforeClass()
|
||||||
|
{
|
||||||
|
parent::setUpBeforeClass();
|
||||||
|
|
||||||
|
if (\DIRECTORY_SEPARATOR === '\\') {
|
||||||
|
self::markTestSkipped('only linux test');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideAllowSymlink
|
||||||
|
*
|
||||||
|
* @param bool $allowSymlink
|
||||||
|
*
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function testSymlink($allowSymlink)
|
||||||
|
{
|
||||||
|
if (!is_dir($this->outputDirname)) {
|
||||||
|
self::assertTrue(mkdir($this->outputDirname, 0755, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
$contentsFile = random_bytes(100);
|
||||||
|
$filePath = $this->outputDirname . '/file.bin';
|
||||||
|
$symlinkPath = $this->outputDirname . '/symlink.bin';
|
||||||
|
$symlinkTarget = basename($filePath);
|
||||||
|
self::assertNotFalse(file_put_contents($filePath, $contentsFile));
|
||||||
|
self::assertTrue(symlink($symlinkTarget, $symlinkPath));
|
||||||
|
|
||||||
|
$finder = (new Finder())->in($this->outputDirname);
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile->addFromFinder($finder);
|
||||||
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertCorrectZipArchive($this->outputFilename);
|
||||||
|
|
||||||
|
FilesUtil::removeDir($this->outputDirname);
|
||||||
|
self::assertFalse(is_dir($this->outputDirname));
|
||||||
|
self::assertTrue(mkdir($this->outputDirname, 0755, true));
|
||||||
|
|
||||||
|
$zipFile->openFile($this->outputFilename);
|
||||||
|
$zipFile->extractTo($this->outputDirname, null, [
|
||||||
|
ZipOptions::EXTRACT_SYMLINKS => $allowSymlink,
|
||||||
|
]);
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
$splFileInfo = new \SplFileInfo($symlinkPath);
|
||||||
|
|
||||||
|
if ($allowSymlink) {
|
||||||
|
self::assertTrue($splFileInfo->isLink());
|
||||||
|
self::assertSame($splFileInfo->getLinkTarget(), $symlinkTarget);
|
||||||
|
} else {
|
||||||
|
self::assertFalse($splFileInfo->isLink());
|
||||||
|
self::assertStringEqualsFile($symlinkPath, $symlinkTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Generator
|
||||||
|
*/
|
||||||
|
public function provideAllowSymlink()
|
||||||
|
{
|
||||||
|
yield 'allow' => [true];
|
||||||
|
yield 'deny' => [false];
|
||||||
|
}
|
||||||
|
}
|
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace PhpZip\Tests;
|
namespace PhpZip\Tests;
|
||||||
|
|
||||||
|
use PhpZip\Constants\ZipCompressionMethod;
|
||||||
use PhpZip\Exception\ZipException;
|
use PhpZip\Exception\ZipException;
|
||||||
use PhpZip\ZipFile;
|
use PhpZip\ZipFile;
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@ class Zip64Test extends ZipTestCase
|
|||||||
|
|
||||||
$zipFile = new ZipFile();
|
$zipFile = new ZipFile();
|
||||||
for ($i = 0; $i < $countFiles; $i++) {
|
for ($i = 0; $i < $countFiles; $i++) {
|
||||||
$zipFile[$i . '.txt'] = (string) $i;
|
$zipFile->addFromString($i . '.txt', (string) $i, ZipCompressionMethod::STORED);
|
||||||
}
|
}
|
||||||
$zipFile->saveAsFile($this->outputFilename);
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
$zipFile->close();
|
$zipFile->close();
|
||||||
|
@@ -304,6 +304,55 @@ class ZipEntryTest extends TestCase
|
|||||||
static::assertNull($zipEntry->getData());
|
static::assertNull($zipEntry->getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function testZipNewDataGuardClone()
|
||||||
|
{
|
||||||
|
$resource = fopen('php://temp', 'r+b');
|
||||||
|
static::assertNotFalse($resource);
|
||||||
|
fwrite($resource, random_bytes(1024));
|
||||||
|
rewind($resource);
|
||||||
|
|
||||||
|
$zipEntry = new ZipEntry('entry');
|
||||||
|
$zipEntry2 = new ZipEntry('entry2');
|
||||||
|
|
||||||
|
$zipData = new ZipNewData($zipEntry, $resource);
|
||||||
|
$zipData2 = new ZipNewData($zipEntry2, $resource);
|
||||||
|
$cloneData = clone $zipData;
|
||||||
|
$cloneData2 = clone $cloneData;
|
||||||
|
|
||||||
|
static::assertSame($zipData->getDataAsStream(), $resource);
|
||||||
|
static::assertSame($zipData2->getDataAsStream(), $resource);
|
||||||
|
static::assertSame($cloneData->getDataAsStream(), $resource);
|
||||||
|
static::assertSame($cloneData2->getDataAsStream(), $resource);
|
||||||
|
|
||||||
|
$validResource = \is_resource($resource);
|
||||||
|
static::assertTrue($validResource);
|
||||||
|
|
||||||
|
unset($cloneData);
|
||||||
|
$validResource = \is_resource($resource);
|
||||||
|
static::assertTrue($validResource);
|
||||||
|
|
||||||
|
unset($zipData);
|
||||||
|
$validResource = \is_resource($resource);
|
||||||
|
static::assertTrue($validResource);
|
||||||
|
|
||||||
|
unset($zipData2);
|
||||||
|
$validResource = \is_resource($resource);
|
||||||
|
static::assertTrue($validResource);
|
||||||
|
|
||||||
|
$reflectionClass = new \ReflectionClass($cloneData2);
|
||||||
|
static::assertSame(
|
||||||
|
$reflectionClass->getStaticProperties()['guardClonedStream'][(int) $resource],
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
unset($cloneData2);
|
||||||
|
$validResource = \is_resource($resource);
|
||||||
|
static::assertFalse($validResource);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider providePlatform
|
* @dataProvider providePlatform
|
||||||
*
|
*
|
||||||
|
@@ -1,41 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace PhpZip\Tests;
|
|
||||||
|
|
||||||
use PhpZip\Exception\ZipException;
|
|
||||||
use PhpZip\Tests\Internal\ZipFileExtended;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*
|
|
||||||
* @small
|
|
||||||
*/
|
|
||||||
class ZipEventTest extends ZipTestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @throws ZipException
|
|
||||||
*/
|
|
||||||
public function testBeforeSave()
|
|
||||||
{
|
|
||||||
$zipFile = new ZipFileExtended();
|
|
||||||
$zipFile->openFile(__DIR__ . '/resources/apk.zip');
|
|
||||||
static::assertTrue(isset($zipFile['META-INF/MANIFEST.MF']));
|
|
||||||
static::assertTrue(isset($zipFile['META-INF/CERT.SF']));
|
|
||||||
static::assertTrue(isset($zipFile['META-INF/CERT.RSA']));
|
|
||||||
// the "META-INF/" folder will be deleted when saved
|
|
||||||
// in the ZipFileExtended::onBeforeSave() method
|
|
||||||
$zipFile->saveAsFile($this->outputFilename);
|
|
||||||
static::assertFalse(isset($zipFile['META-INF/MANIFEST.MF']));
|
|
||||||
static::assertFalse(isset($zipFile['META-INF/CERT.SF']));
|
|
||||||
static::assertFalse(isset($zipFile['META-INF/CERT.RSA']));
|
|
||||||
$zipFile->close();
|
|
||||||
|
|
||||||
static::assertCorrectZipArchive($this->outputFilename);
|
|
||||||
|
|
||||||
$zipFile->openFile($this->outputFilename);
|
|
||||||
static::assertFalse(isset($zipFile['META-INF/MANIFEST.MF']));
|
|
||||||
static::assertFalse(isset($zipFile['META-INF/CERT.SF']));
|
|
||||||
static::assertFalse(isset($zipFile['META-INF/CERT.RSA']));
|
|
||||||
$zipFile->close();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1010,16 +1010,16 @@ class ZipFileTest extends ZipTestCase
|
|||||||
'test1.txt' => random_bytes(255),
|
'test1.txt' => random_bytes(255),
|
||||||
'test2.txt' => random_bytes(255),
|
'test2.txt' => random_bytes(255),
|
||||||
'test/test 2/test3.txt' => random_bytes(255),
|
'test/test 2/test3.txt' => random_bytes(255),
|
||||||
'test empty/dir' => null,
|
'test empty/dir/' => null,
|
||||||
];
|
];
|
||||||
|
|
||||||
$zipFile = new ZipFile();
|
$zipFile = new ZipFile();
|
||||||
|
|
||||||
foreach ($entries as $entryName => $value) {
|
foreach ($entries as $entryName => $contents) {
|
||||||
if ($value === null) {
|
if ($contents === null) {
|
||||||
$zipFile->addEmptyDir($entryName);
|
$zipFile->addEmptyDir($entryName);
|
||||||
} else {
|
} else {
|
||||||
$zipFile->addFromString($entryName, $value);
|
$zipFile->addFromString($entryName, $contents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$zipFile->saveAsFile($this->outputFilename);
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
@@ -1028,19 +1028,28 @@ class ZipFileTest extends ZipTestCase
|
|||||||
static::assertTrue(mkdir($this->outputDirname, 0755, true));
|
static::assertTrue(mkdir($this->outputDirname, 0755, true));
|
||||||
|
|
||||||
$zipFile->openFile($this->outputFilename);
|
$zipFile->openFile($this->outputFilename);
|
||||||
$zipFile->extractTo($this->outputDirname);
|
$zipFile->extractTo($this->outputDirname, null, [], $extractedEntries);
|
||||||
|
|
||||||
foreach ($entries as $entryName => $value) {
|
foreach ($entries as $entryName => $contents) {
|
||||||
$fullExtractedFilename = $this->outputDirname . \DIRECTORY_SEPARATOR . $entryName;
|
$fullExtractedFilename = $this->outputDirname . \DIRECTORY_SEPARATOR . $entryName;
|
||||||
|
|
||||||
if ($value === null) {
|
static::assertTrue(
|
||||||
|
isset($extractedEntries[$fullExtractedFilename]),
|
||||||
|
'No extract info for ' . $fullExtractedFilename
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($contents === null) {
|
||||||
static::assertTrue(is_dir($fullExtractedFilename));
|
static::assertTrue(is_dir($fullExtractedFilename));
|
||||||
static::assertTrue(FilesUtil::isEmptyDir($fullExtractedFilename));
|
static::assertTrue(FilesUtil::isEmptyDir($fullExtractedFilename));
|
||||||
} else {
|
} else {
|
||||||
static::assertTrue(is_file($fullExtractedFilename));
|
static::assertTrue(is_file($fullExtractedFilename));
|
||||||
$contents = file_get_contents($fullExtractedFilename);
|
$contents = file_get_contents($fullExtractedFilename);
|
||||||
static::assertSame($contents, $value);
|
static::assertSame($contents, $contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var ZipEntry $entry */
|
||||||
|
$entry = $extractedEntries[$fullExtractedFilename];
|
||||||
|
static::assertSame($entry->getName(), $entryName);
|
||||||
}
|
}
|
||||||
$zipFile->close();
|
$zipFile->close();
|
||||||
}
|
}
|
||||||
@@ -2420,6 +2429,59 @@ class ZipFileTest extends ZipTestCase
|
|||||||
$zipFile->close();
|
$zipFile->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipEntryNotFoundException
|
||||||
|
* @throws ZipException
|
||||||
|
*/
|
||||||
|
public function testCloneZipContainerInZipWriter()
|
||||||
|
{
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile['file 1'] = 'contents';
|
||||||
|
$zipEntryBeforeWrite = $zipFile->getEntry('file 1');
|
||||||
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
|
$zipAfterBeforeWrite = $zipFile->getEntry('file 1');
|
||||||
|
|
||||||
|
static::assertSame($zipAfterBeforeWrite, $zipEntryBeforeWrite);
|
||||||
|
|
||||||
|
$zipFile->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipException
|
||||||
|
*/
|
||||||
|
public function testMultiSave()
|
||||||
|
{
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile['file 1'] = 'contents';
|
||||||
|
for ($i = 0; $i < 10; $i++) {
|
||||||
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
|
self::assertCorrectZipArchive($this->outputFilename);
|
||||||
|
}
|
||||||
|
$zipFile->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipEntryNotFoundException
|
||||||
|
* @throws ZipException
|
||||||
|
*/
|
||||||
|
public function testNoData()
|
||||||
|
{
|
||||||
|
$this->setExpectedException(ZipException::class, 'No data for zip entry file');
|
||||||
|
|
||||||
|
$entryName = 'file';
|
||||||
|
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$zipFile[$entryName] = '';
|
||||||
|
$zipEntry = $zipFile->getEntry($entryName);
|
||||||
|
$zipEntry->setData(null);
|
||||||
|
$zipFile->getEntryContents($entryName);
|
||||||
|
} finally {
|
||||||
|
$zipFile->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws ZipEntryNotFoundException
|
* @throws ZipEntryNotFoundException
|
||||||
* @throws ZipException
|
* @throws ZipException
|
||||||
|
118
tests/ZipInfoTest.php
Normal file
118
tests/ZipInfoTest.php
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpZip\Tests;
|
||||||
|
|
||||||
|
use PhpZip\Constants\ZipCompressionMethod;
|
||||||
|
use PhpZip\Constants\ZipEncryptionMethod;
|
||||||
|
use PhpZip\Constants\ZipPlatform;
|
||||||
|
use PhpZip\Exception\ZipEntryNotFoundException;
|
||||||
|
use PhpZip\Exception\ZipException;
|
||||||
|
use PhpZip\Model\ZipInfo;
|
||||||
|
use PhpZip\ZipFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Testing the {@see ZipInfo} class.
|
||||||
|
*
|
||||||
|
* {@see ZipInfo} is {@deprecated}. Use the {@see ZipEntry} class.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @small
|
||||||
|
*/
|
||||||
|
final class ZipInfoTest extends ZipTestCase
|
||||||
|
{
|
||||||
|
public function testZipAllInfo()
|
||||||
|
{
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile['entry'] = 'contents';
|
||||||
|
$zipFile['entry 2'] = 'contents';
|
||||||
|
$zipAllInfo = $zipFile->getAllInfo();
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertCount(2, $zipAllInfo);
|
||||||
|
self::assertContainsOnlyInstancesOf(ZipInfo::class, $zipAllInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipEntryNotFoundException
|
||||||
|
* @throws ZipException
|
||||||
|
*/
|
||||||
|
public function testZipEntryInfo()
|
||||||
|
{
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile['entry'] = 'contents';
|
||||||
|
$zipFile['entry 2'] = 'contents';
|
||||||
|
$zipInfo = $zipFile->getEntryInfo('entry');
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertInstanceOf(ZipInfo::class, $zipInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipEntryNotFoundException
|
||||||
|
* @throws ZipException
|
||||||
|
*/
|
||||||
|
public function testZipInfoEntryNotFound()
|
||||||
|
{
|
||||||
|
$this->setExpectedException(
|
||||||
|
ZipEntryNotFoundException::class,
|
||||||
|
'Zip Entry "unknown.name" was not found in the archive.'
|
||||||
|
);
|
||||||
|
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile->getEntryInfo('unknown.name');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZipEntryNotFoundException
|
||||||
|
* @throws ZipException
|
||||||
|
*/
|
||||||
|
public function testZipInfo()
|
||||||
|
{
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile->openFile(__DIR__ . '/resources/Advanced-v1.0.0.epub');
|
||||||
|
$entryName = 'META-INF/container.xml';
|
||||||
|
$zipEntry = $zipFile->getEntry($entryName);
|
||||||
|
$zipInfo = $zipFile->getEntryInfo($entryName);
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertSame($zipInfo->getName(), $zipEntry->getName());
|
||||||
|
self::assertSame($zipInfo->isFolder(), $zipEntry->isDirectory());
|
||||||
|
self::assertSame($zipInfo->getSize(), $zipEntry->getUncompressedSize());
|
||||||
|
self::assertSame($zipInfo->getCompressedSize(), $zipEntry->getCompressedSize());
|
||||||
|
self::assertSame($zipInfo->getMtime(), $zipEntry->getMTime()->getTimestamp());
|
||||||
|
self::assertSame(
|
||||||
|
$zipInfo->getCtime(),
|
||||||
|
$zipEntry->getCTime() !== null ? $zipEntry->getCTime()->getTimestamp() : null
|
||||||
|
);
|
||||||
|
self::assertSame(
|
||||||
|
$zipInfo->getAtime(),
|
||||||
|
$zipEntry->getATime() !== null ? $zipEntry->getATime()->getTimestamp() : null
|
||||||
|
);
|
||||||
|
self::assertNotEmpty($zipInfo->getAttributes());
|
||||||
|
self::assertSame($zipInfo->isEncrypted(), $zipEntry->isEncrypted());
|
||||||
|
self::assertSame($zipInfo->getComment(), $zipEntry->getComment());
|
||||||
|
self::assertSame($zipInfo->getCrc(), $zipEntry->getCrc());
|
||||||
|
self::assertSame(
|
||||||
|
$zipInfo->getMethod(),
|
||||||
|
ZipCompressionMethod::getCompressionMethodName($zipEntry->getCompressionMethod())
|
||||||
|
);
|
||||||
|
self::assertSame(
|
||||||
|
$zipInfo->getMethodName(),
|
||||||
|
ZipCompressionMethod::getCompressionMethodName($zipEntry->getCompressionMethod())
|
||||||
|
);
|
||||||
|
self::assertSame(
|
||||||
|
$zipInfo->getEncryptionMethodName(),
|
||||||
|
ZipEncryptionMethod::getEncryptionMethodName($zipEntry->getEncryptionMethod())
|
||||||
|
);
|
||||||
|
self::assertSame($zipInfo->getPlatform(), ZipPlatform::getPlatformName($zipEntry->getExtractedOS()));
|
||||||
|
self::assertSame(ZipInfo::getPlatformName($zipEntry), ZipPlatform::getPlatformName($zipEntry->getExtractedOS()));
|
||||||
|
self::assertSame($zipInfo->getVersion(), $zipEntry->getExtractVersion());
|
||||||
|
self::assertNull($zipInfo->getEncryptionMethod());
|
||||||
|
self::assertSame($zipInfo->getCompressionLevel(), $zipEntry->getCompressionLevel());
|
||||||
|
self::assertSame($zipInfo->getCompressionMethod(), $zipEntry->getCompressionMethod());
|
||||||
|
self::assertNotEmpty($zipInfo->toArray());
|
||||||
|
|
||||||
|
self::assertSame((string) $zipInfo, 'PhpZip\Model\ZipInfo {Name="META-INF/container.xml", Size="249 bytes", Compressed size="169 bytes", Modified time="2019-04-08T14:59:08+00:00", Comment="", Method name="Deflated", Attributes="------", Platform="MS-DOS", Version=20}');
|
||||||
|
}
|
||||||
|
}
|
BIN
tests/resources/Advanced-v1.0.0.epub
Normal file
BIN
tests/resources/Advanced-v1.0.0.epub
Normal file
Binary file not shown.
Reference in New Issue
Block a user