mirror of
https://github.com/Ne-Lexa/php-zip.git
synced 2025-07-17 14:11:13 +02:00
Add tests
This commit is contained in:
@@ -1,7 +1,11 @@
|
|||||||
`PhpZip` (ver 3.0.+)
|
`PhpZip`
|
||||||
====================
|
====================
|
||||||
`PhpZip` - php library for manipulating zip archives.
|
`PhpZip` - php library for manipulating zip archives.
|
||||||
|
|
||||||
|
[](https://packagist.org/packages/nelexa/zip)
|
||||||
|
[](https://packagist.org/packages/nelexa/zip)
|
||||||
|
[](https://packagist.org/packages/nelexa/zip)
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
---------
|
---------
|
||||||
- Opening and unzipping zip files.
|
- Opening and unzipping zip files.
|
||||||
|
@@ -112,7 +112,11 @@ class CentralDirectory
|
|||||||
rewind($inputStream);
|
rewind($inputStream);
|
||||||
// Constraint: A ZIP file must start with a Local File Header
|
// Constraint: A ZIP file must start with a Local File Header
|
||||||
// or a (ZIP64) End Of Central Directory Record if it's empty.
|
// or a (ZIP64) End Of Central Directory Record if it's empty.
|
||||||
$signature = unpack('V', fread($inputStream, 4))[1];
|
$signatureBytes = fread($inputStream, 4);
|
||||||
|
if (strlen($signatureBytes) < 4) {
|
||||||
|
throw new ZipException("Invalid zip file.");
|
||||||
|
}
|
||||||
|
$signature = unpack('V', $signatureBytes)[1];
|
||||||
if (
|
if (
|
||||||
ZipEntry::LOCAL_FILE_HEADER_SIG !== $signature
|
ZipEntry::LOCAL_FILE_HEADER_SIG !== $signature
|
||||||
&& EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIG !== $signature
|
&& EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIG !== $signature
|
||||||
|
@@ -319,14 +319,6 @@ class EndOfCentralDirectory
|
|||||||
$this->newComment = $comment;
|
$this->newComment = $comment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isModified()
|
|
||||||
{
|
|
||||||
return $this->modified;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write end of central directory.
|
* Write end of central directory.
|
||||||
*
|
*
|
||||||
|
@@ -119,6 +119,10 @@ class ZipReadEntry extends ZipAbstractEntry
|
|||||||
public function getEntryContent()
|
public function getEntryContent()
|
||||||
{
|
{
|
||||||
if ($this->entryContent === null) {
|
if ($this->entryContent === null) {
|
||||||
|
if ($this->isDirectory()) {
|
||||||
|
$this->entryContent = null;
|
||||||
|
return $this->entryContent;
|
||||||
|
}
|
||||||
$isEncrypted = $this->isEncrypted();
|
$isEncrypted = $this->isEncrypted();
|
||||||
$password = $this->getPassword();
|
$password = $this->getPassword();
|
||||||
if ($isEncrypted && empty($password)) {
|
if ($isEncrypted && empty($password)) {
|
||||||
|
@@ -433,7 +433,7 @@ class ZipFile implements \Countable, \ArrayAccess, \Iterator
|
|||||||
throw new InvalidArgumentException("Filename is null");
|
throw new InvalidArgumentException("Filename is null");
|
||||||
}
|
}
|
||||||
if (!is_file($filename)) {
|
if (!is_file($filename)) {
|
||||||
throw new InvalidArgumentException("File is not exists");
|
throw new InvalidArgumentException("File $filename is not exists");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $compressionMethod) {
|
if (null === $compressionMethod) {
|
||||||
@@ -559,23 +559,17 @@ class ZipFile implements \Countable, \ArrayAccess, \Iterator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add directory to the zip archive.
|
* Add directory not recursively to the zip archive.
|
||||||
*
|
*
|
||||||
* @param string $inputDir Input directory
|
* @param string $inputDir Input directory
|
||||||
* @param bool $recursive Recursive search files
|
* @param string $localPath Add files to this directory, or the root.
|
||||||
* @param string|null $toLocalPath If not null then put $inputDir to path $outEntryDir
|
* @param int|null $compressionMethod Compression method.
|
||||||
* @param array $ignoreFiles List of files to exclude from the folder $inputDir.
|
* Use ZipFile::METHOD_STORED, ZipFile::METHOD_DEFLATED or ZipFile::METHOD_BZIP2.
|
||||||
* @param int|null $compressionMethod Compression method
|
* If null, then auto choosing method.
|
||||||
* @return bool
|
* @return ZipFile
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
public function addDir(
|
public function addDir($inputDir, $localPath = "/", $compressionMethod = null)
|
||||||
$inputDir,
|
|
||||||
$recursive = true,
|
|
||||||
$toLocalPath = "/",
|
|
||||||
array $ignoreFiles = [],
|
|
||||||
$compressionMethod = null
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
$inputDir = (string)$inputDir;
|
$inputDir = (string)$inputDir;
|
||||||
if ($inputDir === null || strlen($inputDir) === 0) {
|
if ($inputDir === null || strlen($inputDir) === 0) {
|
||||||
@@ -584,30 +578,102 @@ class ZipFile implements \Countable, \ArrayAccess, \Iterator
|
|||||||
if (!is_dir($inputDir)) {
|
if (!is_dir($inputDir)) {
|
||||||
throw new InvalidArgumentException('Directory ' . $inputDir . ' can\'t exists');
|
throw new InvalidArgumentException('Directory ' . $inputDir . ' can\'t exists');
|
||||||
}
|
}
|
||||||
|
$inputDir = rtrim($inputDir, '/\\') . DIRECTORY_SEPARATOR;
|
||||||
|
|
||||||
if (null !== $toLocalPath && is_string($toLocalPath) && !empty($toLocalPath)) {
|
$directoryIterator = new \DirectoryIterator($inputDir);
|
||||||
$toLocalPath = rtrim($toLocalPath, '/') . '/';
|
return $this->addFilesFromIterator($directoryIterator, $localPath, $compressionMethod);
|
||||||
} else {
|
}
|
||||||
$toLocalPath = "/";
|
|
||||||
|
/**
|
||||||
|
* Add recursive directory to the zip archive.
|
||||||
|
*
|
||||||
|
* @param string $inputDir Input directory
|
||||||
|
* @param string $localPath Add files to this directory, or the root.
|
||||||
|
* @param int|null $compressionMethod Compression method.
|
||||||
|
* Use ZipFile::METHOD_STORED, ZipFile::METHOD_DEFLATED or ZipFile::METHOD_BZIP2.
|
||||||
|
* If null, then auto choosing method.
|
||||||
|
* @return ZipFile
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
* @throws ZipUnsupportMethod
|
||||||
|
* @see ZipFile::METHOD_STORED
|
||||||
|
* @see ZipFile::METHOD_DEFLATED
|
||||||
|
* @see ZipFile::METHOD_BZIP2
|
||||||
|
*/
|
||||||
|
public function addDirRecursive($inputDir, $localPath = "/", $compressionMethod = null)
|
||||||
|
{
|
||||||
|
$inputDir = (string)$inputDir;
|
||||||
|
if ($inputDir === null || strlen($inputDir) === 0) {
|
||||||
|
throw new InvalidArgumentException('Input dir empty');
|
||||||
|
}
|
||||||
|
if (!is_dir($inputDir)) {
|
||||||
|
throw new InvalidArgumentException('Directory ' . $inputDir . ' can\'t exists');
|
||||||
}
|
}
|
||||||
$inputDir = rtrim($inputDir, '/\\') . DIRECTORY_SEPARATOR;
|
$inputDir = rtrim($inputDir, '/\\') . DIRECTORY_SEPARATOR;
|
||||||
|
|
||||||
$count = $this->count();
|
$directoryIterator = new \RecursiveDirectoryIterator($inputDir);
|
||||||
|
return $this->addFilesFromIterator($directoryIterator, $localPath, $compressionMethod);
|
||||||
|
}
|
||||||
|
|
||||||
$files = FilesUtil::fileSearchWithIgnore($inputDir, $recursive, $ignoreFiles);
|
|
||||||
/**
|
/**
|
||||||
* @var \SplFileInfo $file
|
* Add directories from directory iterator.
|
||||||
|
*
|
||||||
|
* @param \Iterator $iterator Directory iterator.
|
||||||
|
* @param string $localPath Add files to this directory, or the root.
|
||||||
|
* @param int|null $compressionMethod Compression method.
|
||||||
|
* Use ZipFile::METHOD_STORED, ZipFile::METHOD_DEFLATED or ZipFile::METHOD_BZIP2.
|
||||||
|
* If null, then auto choosing method.
|
||||||
|
* @return ZipFile
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
* @throws ZipUnsupportMethod
|
||||||
|
* @see ZipFile::METHOD_STORED
|
||||||
|
* @see ZipFile::METHOD_DEFLATED
|
||||||
|
* @see ZipFile::METHOD_BZIP2
|
||||||
*/
|
*/
|
||||||
|
public function addFilesFromIterator(
|
||||||
|
\Iterator $iterator,
|
||||||
|
$localPath = '/',
|
||||||
|
$compressionMethod = null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$localPath = (string)$localPath;
|
||||||
|
if (null !== $localPath && 0 !== strlen($localPath)) {
|
||||||
|
$localPath = rtrim($localPath, '/');
|
||||||
|
} else {
|
||||||
|
$localPath = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
$iterator = $iterator instanceof \RecursiveIterator ?
|
||||||
|
new \RecursiveIteratorIterator($iterator) :
|
||||||
|
new \IteratorIterator($iterator);
|
||||||
|
/**
|
||||||
|
* @var string[] $files
|
||||||
|
* @var string $path
|
||||||
|
*/
|
||||||
|
$files = [];
|
||||||
|
foreach ($iterator as $file) {
|
||||||
|
if ($file instanceof \SplFileInfo) {
|
||||||
|
empty($path) and $path = rtrim($file->getPath(), '/');
|
||||||
|
if ('..' === $file->getBasename()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ('.' === $file->getBasename()) {
|
||||||
|
$files[] = dirname($file->getPathname());
|
||||||
|
} else {
|
||||||
|
$files[] = $file->getPathname();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
$filename = str_replace($inputDir, $toLocalPath, $file);
|
$relativePath = str_replace($path, $localPath, $file);
|
||||||
$filename = ltrim($filename, '/');
|
$relativePath = ltrim($relativePath, '/');
|
||||||
if (is_dir($file)) {
|
if (is_dir($file)) {
|
||||||
FilesUtil::isEmptyDir($file) && $this->addEmptyDir($filename);
|
FilesUtil::isEmptyDir($file) && $this->addEmptyDir($relativePath);
|
||||||
} elseif (is_file($file)) {
|
} elseif (is_file($file)) {
|
||||||
$this->addFile($file, $filename, $compressionMethod);
|
$this->addFile($file, $relativePath, $compressionMethod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $this->count() > $count;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -615,33 +681,69 @@ class ZipFile implements \Countable, \ArrayAccess, \Iterator
|
|||||||
*
|
*
|
||||||
* @param string $inputDir Input directory
|
* @param string $inputDir Input directory
|
||||||
* @param string $globPattern Glob pattern.
|
* @param string $globPattern Glob pattern.
|
||||||
* @param string|null $moveToPath Add files to this directory, or the root.
|
* @param string|null $localPath Add files to this directory, or the root.
|
||||||
* @param bool $recursive Recursive search.
|
* @param int|null $compressionMethod Compression method.
|
||||||
* @param int $compressionMethod Compression method.
|
* Use ZipFile::METHOD_STORED, ZipFile::METHOD_DEFLATED or ZipFile::METHOD_BZIP2.
|
||||||
|
* If null, then auto choosing method.
|
||||||
* @return ZipFile
|
* @return ZipFile
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
* @sse https://en.wikipedia.org/wiki/Glob_(programming) Glob pattern syntax
|
* @sse https://en.wikipedia.org/wiki/Glob_(programming) Glob pattern syntax
|
||||||
*/
|
*/
|
||||||
public function addFilesFromGlob(
|
public function addFilesFromGlob($inputDir, $globPattern, $localPath = '/', $compressionMethod = null)
|
||||||
|
{
|
||||||
|
return $this->addGlob($inputDir, $globPattern, $localPath, false, $compressionMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add files recursively from glob pattern.
|
||||||
|
*
|
||||||
|
* @param string $inputDir Input directory
|
||||||
|
* @param string $globPattern Glob pattern.
|
||||||
|
* @param string|null $localPath Add files to this directory, or the root.
|
||||||
|
* @param int|null $compressionMethod Compression method.
|
||||||
|
* Use ZipFile::METHOD_STORED, ZipFile::METHOD_DEFLATED or ZipFile::METHOD_BZIP2.
|
||||||
|
* If null, then auto choosing method.
|
||||||
|
* @return ZipFile
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
* @sse https://en.wikipedia.org/wiki/Glob_(programming) Glob pattern syntax
|
||||||
|
*/
|
||||||
|
public function addFilesFromGlobRecursive($inputDir, $globPattern, $localPath = '/', $compressionMethod = null)
|
||||||
|
{
|
||||||
|
return $this->addGlob($inputDir, $globPattern, $localPath, true, $compressionMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add files from glob pattern.
|
||||||
|
*
|
||||||
|
* @param string $inputDir Input directory
|
||||||
|
* @param string $globPattern Glob pattern.
|
||||||
|
* @param string|null $localPath Add files to this directory, or the root.
|
||||||
|
* @param bool $recursive Recursive search.
|
||||||
|
* @param int|null $compressionMethod Compression method.
|
||||||
|
* Use ZipFile::METHOD_STORED, ZipFile::METHOD_DEFLATED or ZipFile::METHOD_BZIP2.
|
||||||
|
* If null, then auto choosing method.
|
||||||
|
* @return ZipFile
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
* @sse https://en.wikipedia.org/wiki/Glob_(programming) Glob pattern syntax
|
||||||
|
*/
|
||||||
|
private function addGlob(
|
||||||
$inputDir,
|
$inputDir,
|
||||||
$globPattern,
|
$globPattern,
|
||||||
$moveToPath = '/',
|
$localPath = '/',
|
||||||
$recursive = true,
|
$recursive = true,
|
||||||
$compressionMethod = self::METHOD_DEFLATED
|
$compressionMethod = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
$inputDir = (string)$inputDir;
|
$inputDir = (string)$inputDir;
|
||||||
if (empty($inputDir)) {
|
if (null === $inputDir || 0 === strlen($inputDir)) {
|
||||||
throw new InvalidArgumentException('Input dir empty');
|
throw new InvalidArgumentException('Input dir empty');
|
||||||
}
|
}
|
||||||
if (!is_dir($inputDir)) {
|
if (!is_dir($inputDir)) {
|
||||||
throw new InvalidArgumentException('Directory ' . $inputDir . ' can\'t exists');
|
throw new InvalidArgumentException('Directory ' . $inputDir . ' can\'t exists');
|
||||||
}
|
}
|
||||||
if (null === $globPattern || strlen($globPattern) === 0) {
|
$globPattern = (string)$globPattern;
|
||||||
throw new InvalidArgumentException("globPattern null");
|
|
||||||
}
|
|
||||||
if (empty($globPattern)) {
|
if (empty($globPattern)) {
|
||||||
throw new InvalidArgumentException("globPattern empty");
|
throw new InvalidArgumentException("glob pattern empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
$inputDir = rtrim($inputDir, '/\\') . DIRECTORY_SEPARATOR;
|
$inputDir = rtrim($inputDir, '/\\') . DIRECTORY_SEPARATOR;
|
||||||
@@ -651,17 +753,17 @@ class ZipFile implements \Countable, \ArrayAccess, \Iterator
|
|||||||
if ($filesFound === false || empty($filesFound)) {
|
if ($filesFound === false || empty($filesFound)) {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
if (!empty($moveToPath) && is_string($moveToPath)) {
|
if (!empty($localPath) && is_string($localPath)) {
|
||||||
$moveToPath = rtrim($moveToPath, '/') . '/';
|
$localPath = rtrim($localPath, '/') . '/';
|
||||||
} else {
|
} else {
|
||||||
$moveToPath = "/";
|
$localPath = "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string $file
|
* @var string $file
|
||||||
*/
|
*/
|
||||||
foreach ($filesFound as $file) {
|
foreach ($filesFound as $file) {
|
||||||
$filename = str_replace($inputDir, $moveToPath, $file);
|
$filename = str_replace($inputDir, $localPath, $file);
|
||||||
$filename = ltrim($filename, '/');
|
$filename = ltrim($filename, '/');
|
||||||
if (is_dir($file)) {
|
if (is_dir($file)) {
|
||||||
FilesUtil::isEmptyDir($file) && $this->addEmptyDir($filename);
|
FilesUtil::isEmptyDir($file) && $this->addEmptyDir($filename);
|
||||||
@@ -677,29 +779,67 @@ class ZipFile implements \Countable, \ArrayAccess, \Iterator
|
|||||||
*
|
*
|
||||||
* @param string $inputDir Search files in this directory.
|
* @param string $inputDir Search files in this directory.
|
||||||
* @param string $regexPattern Regex pattern.
|
* @param string $regexPattern Regex pattern.
|
||||||
* @param string|null $moveToPath Add files to this directory, or the root.
|
* @param string|null $localPath Add files to this directory, or the root.
|
||||||
|
* @param int|null $compressionMethod Compression method.
|
||||||
|
* Use ZipFile::METHOD_STORED, ZipFile::METHOD_DEFLATED or ZipFile::METHOD_BZIP2.
|
||||||
|
* If null, then auto choosing method.
|
||||||
|
* @return ZipFile
|
||||||
|
* @internal param bool $recursive Recursive search.
|
||||||
|
*/
|
||||||
|
public function addFilesFromRegex($inputDir, $regexPattern, $localPath = "/", $compressionMethod = null)
|
||||||
|
{
|
||||||
|
return $this->addRegex($inputDir, $regexPattern, $localPath, false, $compressionMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add files recursively from regex pattern.
|
||||||
|
*
|
||||||
|
* @param string $inputDir Search files in this directory.
|
||||||
|
* @param string $regexPattern Regex pattern.
|
||||||
|
* @param string|null $localPath Add files to this directory, or the root.
|
||||||
|
* @param int|null $compressionMethod Compression method.
|
||||||
|
* Use ZipFile::METHOD_STORED, ZipFile::METHOD_DEFLATED or ZipFile::METHOD_BZIP2.
|
||||||
|
* If null, then auto choosing method.
|
||||||
|
* @return ZipFile
|
||||||
|
* @internal param bool $recursive Recursive search.
|
||||||
|
*/
|
||||||
|
public function addFilesFromRegexRecursive($inputDir, $regexPattern, $localPath = "/", $compressionMethod = null)
|
||||||
|
{
|
||||||
|
return $this->addRegex($inputDir, $regexPattern, $localPath, true, $compressionMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add files from regex pattern.
|
||||||
|
*
|
||||||
|
* @param string $inputDir Search files in this directory.
|
||||||
|
* @param string $regexPattern Regex pattern.
|
||||||
|
* @param string|null $localPath Add files to this directory, or the root.
|
||||||
* @param bool $recursive Recursive search.
|
* @param bool $recursive Recursive search.
|
||||||
* @param int $compressionMethod Compression method.
|
* @param int|null $compressionMethod Compression method.
|
||||||
|
* Use ZipFile::METHOD_STORED, ZipFile::METHOD_DEFLATED or ZipFile::METHOD_BZIP2.
|
||||||
|
* If null, then auto choosing method.
|
||||||
* @return ZipFile
|
* @return ZipFile
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
public function addFilesFromRegex(
|
private function addRegex(
|
||||||
$inputDir,
|
$inputDir,
|
||||||
$regexPattern,
|
$regexPattern,
|
||||||
$moveToPath = "/",
|
$localPath = "/",
|
||||||
$recursive = true,
|
$recursive = true,
|
||||||
$compressionMethod = self::METHOD_DEFLATED
|
$compressionMethod = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if ($regexPattern === null || !is_string($regexPattern) || empty($regexPattern)) {
|
$regexPattern = (string)$regexPattern;
|
||||||
|
if (empty($regexPattern)) {
|
||||||
throw new InvalidArgumentException("regex pattern empty");
|
throw new InvalidArgumentException("regex pattern empty");
|
||||||
}
|
}
|
||||||
$inputDir = (string)$inputDir;
|
$inputDir = (string)$inputDir;
|
||||||
if (empty($inputDir)) {
|
if (null === $inputDir || 0 === strlen($inputDir)) {
|
||||||
throw new InvalidArgumentException('Invalid $inputDir value');
|
throw new InvalidArgumentException('Input dir empty');
|
||||||
}
|
}
|
||||||
if (!is_dir($inputDir)) {
|
if (!is_dir($inputDir)) {
|
||||||
throw new InvalidArgumentException('Path ' . $inputDir . ' can\'t directory.');
|
throw new InvalidArgumentException('Directory ' . $inputDir . ' can\'t exists');
|
||||||
}
|
}
|
||||||
$inputDir = rtrim($inputDir, '/\\') . DIRECTORY_SEPARATOR;
|
$inputDir = rtrim($inputDir, '/\\') . DIRECTORY_SEPARATOR;
|
||||||
|
|
||||||
@@ -707,10 +847,10 @@ class ZipFile implements \Countable, \ArrayAccess, \Iterator
|
|||||||
if ($files === false || empty($files)) {
|
if ($files === false || empty($files)) {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
if (!empty($moveToPath) && is_string($moveToPath)) {
|
if (!empty($localPath) && is_string($localPath)) {
|
||||||
$moveToPath = rtrim($moveToPath, '/') . '/';
|
$localPath = rtrim($localPath, '/') . '/';
|
||||||
} else {
|
} else {
|
||||||
$moveToPath = "/";
|
$localPath = "/";
|
||||||
}
|
}
|
||||||
$inputDir = rtrim($inputDir, '/\\') . DIRECTORY_SEPARATOR;
|
$inputDir = rtrim($inputDir, '/\\') . DIRECTORY_SEPARATOR;
|
||||||
|
|
||||||
@@ -718,7 +858,7 @@ class ZipFile implements \Countable, \ArrayAccess, \Iterator
|
|||||||
* @var string $file
|
* @var string $file
|
||||||
*/
|
*/
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
$filename = str_replace($inputDir, $moveToPath, $file);
|
$filename = str_replace($inputDir, $localPath, $file);
|
||||||
$filename = ltrim($filename, '/');
|
$filename = ltrim($filename, '/');
|
||||||
if (is_dir($file)) {
|
if (is_dir($file)) {
|
||||||
FilesUtil::isEmptyDir($file) && $this->addEmptyDir($filename);
|
FilesUtil::isEmptyDir($file) && $this->addEmptyDir($filename);
|
||||||
@@ -936,6 +1076,31 @@ class ZipFile implements \Countable, \ArrayAccess, \Iterator
|
|||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rewrite and reopen zip archive.
|
||||||
|
* @return ZipFile
|
||||||
|
* @throws ZipException
|
||||||
|
*/
|
||||||
|
public function rewrite()
|
||||||
|
{
|
||||||
|
if($this->inputStream === null){
|
||||||
|
throw new ZipException('input stream is null');
|
||||||
|
}
|
||||||
|
$meta = stream_get_meta_data($this->inputStream);
|
||||||
|
$content = $this->outputAsString();
|
||||||
|
$this->close();
|
||||||
|
if ($meta['wrapper_type'] === 'plainfile') {
|
||||||
|
if (file_put_contents($meta['uri'], $content) === false) {
|
||||||
|
throw new ZipException("Can not overwrite the zip file in the {$meta['uri']} file.");
|
||||||
|
}
|
||||||
|
if (!($handle = @fopen($meta['uri'], 'rb'))) {
|
||||||
|
throw new ZipException("File {$meta['uri']} can't open.");
|
||||||
|
}
|
||||||
|
return $this->openFromStream($handle);
|
||||||
|
}
|
||||||
|
return $this->openFromString($content);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close zip archive and release input stream.
|
* Close zip archive and release input stream.
|
||||||
*/
|
*/
|
||||||
@@ -976,12 +1141,11 @@ class ZipFile implements \Countable, \ArrayAccess, \Iterator
|
|||||||
* @link http://php.net/manual/en/arrayaccess.offsetget.php
|
* @link http://php.net/manual/en/arrayaccess.offsetget.php
|
||||||
* @param string $entryName The offset to retrieve.
|
* @param string $entryName The offset to retrieve.
|
||||||
* @return string|null
|
* @return string|null
|
||||||
|
* @throws ZipNotFoundEntry
|
||||||
*/
|
*/
|
||||||
public function offsetGet($entryName)
|
public function offsetGet($entryName)
|
||||||
{
|
{
|
||||||
return $this->offsetExists($entryName) ?
|
return $this->centralDirectory->getEntry($entryName)->getEntryContent();
|
||||||
$this->centralDirectory->getEntry($entryName)->getEntryContent() :
|
|
||||||
null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -992,6 +1156,8 @@ class ZipFile implements \Countable, \ArrayAccess, \Iterator
|
|||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
* @see ZipFile::addFromString
|
* @see ZipFile::addFromString
|
||||||
* @see ZipFile::addEmptyDir
|
* @see ZipFile::addEmptyDir
|
||||||
|
* @see ZipFile::addFile
|
||||||
|
* @see ZipFile::addFilesFromIterator
|
||||||
*/
|
*/
|
||||||
public function offsetSet($entryName, $contents)
|
public function offsetSet($entryName, $contents)
|
||||||
{
|
{
|
||||||
@@ -1002,6 +1168,15 @@ class ZipFile implements \Countable, \ArrayAccess, \Iterator
|
|||||||
if (strlen($entryName) === 0) {
|
if (strlen($entryName) === 0) {
|
||||||
throw new InvalidArgumentException('entryName is empty');
|
throw new InvalidArgumentException('entryName is empty');
|
||||||
}
|
}
|
||||||
|
if ($contents instanceof \SplFileInfo) {
|
||||||
|
if ($contents instanceof \DirectoryIterator) {
|
||||||
|
$this->addFilesFromIterator($contents, $entryName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->addFile($contents->getPathname(), $entryName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$contents = (string)$contents;
|
||||||
if ($entryName[strlen($entryName) - 1] === '/') {
|
if ($entryName[strlen($entryName) - 1] === '/') {
|
||||||
$this->addEmptyDir($entryName);
|
$this->addEmptyDir($entryName);
|
||||||
} else {
|
} else {
|
||||||
|
359
tests/PhpZip/ZipFileAddDirTest.php
Normal file
359
tests/PhpZip/ZipFileAddDirTest.php
Normal file
@@ -0,0 +1,359 @@
|
|||||||
|
<?php
|
||||||
|
namespace PhpZip;
|
||||||
|
|
||||||
|
use PhpZip\Util\Iterator\IgnoreFilesFilterIterator;
|
||||||
|
use PhpZip\Util\Iterator\IgnoreFilesRecursiveFilterIterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test add directory to zip archive.
|
||||||
|
*/
|
||||||
|
class ZipFileAddDirTest extends ZipTestCase
|
||||||
|
{
|
||||||
|
private static $files = [
|
||||||
|
'.hidden' => 'Hidden file',
|
||||||
|
'text file.txt' => 'Text file',
|
||||||
|
'Текстовый документ.txt' => 'Текстовый документ',
|
||||||
|
'empty dir/' => null,
|
||||||
|
'empty dir2/ещё пустой каталог/' => null,
|
||||||
|
'catalog/New File' => 'New Catalog File',
|
||||||
|
'catalog/New File 2' => 'New Catalog File 2',
|
||||||
|
'catalog/Empty Dir/' => null,
|
||||||
|
'category/list.txt' => 'Category list',
|
||||||
|
'category/Pictures/128x160/Car/01.jpg' => 'File 01.jpg',
|
||||||
|
'category/Pictures/128x160/Car/02.jpg' => 'File 02.jpg',
|
||||||
|
'category/Pictures/240x320/Car/01.jpg' => 'File 01.jpg',
|
||||||
|
'category/Pictures/240x320/Car/02.jpg' => 'File 02.jpg',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Before test
|
||||||
|
*/
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
$this->fillDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function fillDirectory()
|
||||||
|
{
|
||||||
|
foreach (self::$files as $name => $content) {
|
||||||
|
$fullName = $this->outputDirname . '/' . $name;
|
||||||
|
if ($content === null) {
|
||||||
|
if (!is_dir($fullName)) {
|
||||||
|
mkdir($fullName, 0755, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$dirname = dirname($fullName);
|
||||||
|
if (!is_dir($dirname)) {
|
||||||
|
mkdir($dirname, 0755, true);
|
||||||
|
}
|
||||||
|
file_put_contents($fullName, $content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function assertFilesResult(ZipFile $zipFile, array $actualResultFiles = [], $localPath = '/')
|
||||||
|
{
|
||||||
|
$localPath = rtrim($localPath, '/');
|
||||||
|
$localPath = empty($localPath) ? "" : $localPath . '/';
|
||||||
|
self::assertEquals(sizeof($zipFile), sizeof($actualResultFiles));
|
||||||
|
$actualResultFiles = array_flip($actualResultFiles);
|
||||||
|
foreach (self::$files as $file => $content) {
|
||||||
|
$zipEntryName = $localPath . $file;
|
||||||
|
if (isset($actualResultFiles[$file])) {
|
||||||
|
self::assertTrue(isset($zipFile[$zipEntryName]));
|
||||||
|
self::assertEquals($zipFile[$zipEntryName], $content);
|
||||||
|
unset($actualResultFiles[$file]);
|
||||||
|
} else {
|
||||||
|
self::assertFalse(isset($zipFile[$zipEntryName]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self::assertEmpty($actualResultFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAddDirWithLocalPath()
|
||||||
|
{
|
||||||
|
$localPath = 'to/path';
|
||||||
|
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile->addDir($this->outputDirname, $localPath);
|
||||||
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertCorrectZipArchive($this->outputFilename);
|
||||||
|
|
||||||
|
$zipFile->openFile($this->outputFilename);
|
||||||
|
self::assertFilesResult($zipFile, [
|
||||||
|
'.hidden',
|
||||||
|
'text file.txt',
|
||||||
|
'Текстовый документ.txt',
|
||||||
|
'empty dir/',
|
||||||
|
], $localPath);
|
||||||
|
$zipFile->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAddDirWithoutLocalPath()
|
||||||
|
{
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile->addDir($this->outputDirname);
|
||||||
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertCorrectZipArchive($this->outputFilename);
|
||||||
|
|
||||||
|
$zipFile->openFile($this->outputFilename);
|
||||||
|
self::assertFilesResult($zipFile, [
|
||||||
|
'.hidden',
|
||||||
|
'text file.txt',
|
||||||
|
'Текстовый документ.txt',
|
||||||
|
'empty dir/',
|
||||||
|
]);
|
||||||
|
$zipFile->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAddFilesFromIterator()
|
||||||
|
{
|
||||||
|
$localPath = 'to/project';
|
||||||
|
|
||||||
|
$directoryIterator = new \DirectoryIterator($this->outputDirname);
|
||||||
|
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile->addFilesFromIterator($directoryIterator, $localPath);
|
||||||
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertCorrectZipArchive($this->outputFilename);
|
||||||
|
|
||||||
|
$zipFile->openFile($this->outputFilename);
|
||||||
|
self::assertFilesResult($zipFile, [
|
||||||
|
'.hidden',
|
||||||
|
'text file.txt',
|
||||||
|
'Текстовый документ.txt',
|
||||||
|
'empty dir/',
|
||||||
|
], $localPath);
|
||||||
|
$zipFile->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAddFilesFromRecursiveIterator()
|
||||||
|
{
|
||||||
|
$localPath = 'to/project';
|
||||||
|
|
||||||
|
$directoryIterator = new \RecursiveDirectoryIterator($this->outputDirname);
|
||||||
|
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile->addFilesFromIterator($directoryIterator, $localPath);
|
||||||
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertCorrectZipArchive($this->outputFilename);
|
||||||
|
|
||||||
|
$zipFile->openFile($this->outputFilename);
|
||||||
|
self::assertFilesResult($zipFile, array_keys(self::$files), $localPath);
|
||||||
|
$zipFile->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAddRecursiveDirWithLocalPath()
|
||||||
|
{
|
||||||
|
$localPath = 'to/path';
|
||||||
|
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile->addDirRecursive($this->outputDirname, $localPath);
|
||||||
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertCorrectZipArchive($this->outputFilename);
|
||||||
|
|
||||||
|
$zipFile->openFile($this->outputFilename);
|
||||||
|
self::assertFilesResult($zipFile, array_keys(self::$files), $localPath);
|
||||||
|
$zipFile->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAddRecursiveDirWithoutLocalPath()
|
||||||
|
{
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile->addDirRecursive($this->outputDirname);
|
||||||
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertCorrectZipArchive($this->outputFilename);
|
||||||
|
|
||||||
|
$zipFile->openFile($this->outputFilename);
|
||||||
|
self::assertFilesResult($zipFile, array_keys(self::$files));
|
||||||
|
$zipFile->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAddFilesFromIteratorWithIgnoreFiles(){
|
||||||
|
$localPath = 'to/project';
|
||||||
|
$ignoreFiles = [
|
||||||
|
'Текстовый документ.txt',
|
||||||
|
'empty dir/'
|
||||||
|
];
|
||||||
|
|
||||||
|
$directoryIterator = new \DirectoryIterator($this->outputDirname);
|
||||||
|
$ignoreIterator = new IgnoreFilesFilterIterator($directoryIterator, $ignoreFiles);
|
||||||
|
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile->addFilesFromIterator($ignoreIterator, $localPath);
|
||||||
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertCorrectZipArchive($this->outputFilename);
|
||||||
|
|
||||||
|
$zipFile->openFile($this->outputFilename);
|
||||||
|
self::assertFilesResult($zipFile, [
|
||||||
|
'.hidden',
|
||||||
|
'text file.txt',
|
||||||
|
], $localPath);
|
||||||
|
$zipFile->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAddFilesFromRecursiveIteratorWithIgnoreFiles(){
|
||||||
|
$localPath = 'to/project';
|
||||||
|
$ignoreFiles = [
|
||||||
|
'.hidden',
|
||||||
|
'empty dir2/ещё пустой каталог/',
|
||||||
|
'list.txt',
|
||||||
|
'category/Pictures/240x320',
|
||||||
|
];
|
||||||
|
|
||||||
|
$directoryIterator = new \RecursiveDirectoryIterator($this->outputDirname);
|
||||||
|
$ignoreIterator = new IgnoreFilesRecursiveFilterIterator($directoryIterator, $ignoreFiles);
|
||||||
|
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile->addFilesFromIterator($ignoreIterator, $localPath);
|
||||||
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertCorrectZipArchive($this->outputFilename);
|
||||||
|
|
||||||
|
$zipFile->openFile($this->outputFilename);
|
||||||
|
self::assertFilesResult($zipFile, [
|
||||||
|
'text file.txt',
|
||||||
|
'Текстовый документ.txt',
|
||||||
|
'empty dir/',
|
||||||
|
'catalog/New File',
|
||||||
|
'catalog/New File 2',
|
||||||
|
'catalog/Empty Dir/',
|
||||||
|
'category/Pictures/128x160/Car/01.jpg',
|
||||||
|
'category/Pictures/128x160/Car/02.jpg',
|
||||||
|
], $localPath);
|
||||||
|
$zipFile->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create archive and add files from glob pattern
|
||||||
|
*/
|
||||||
|
public function testAddFilesFromGlob()
|
||||||
|
{
|
||||||
|
$localPath = '/';
|
||||||
|
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile->addFilesFromGlob($this->outputDirname, '**.{txt,jpg}', $localPath);
|
||||||
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertCorrectZipArchive($this->outputFilename);
|
||||||
|
|
||||||
|
$zipFile->openFile($this->outputFilename);
|
||||||
|
self::assertFilesResult($zipFile, [
|
||||||
|
'text file.txt',
|
||||||
|
'Текстовый документ.txt',
|
||||||
|
], $localPath);
|
||||||
|
$zipFile->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create archive and add recursively files from glob pattern
|
||||||
|
*/
|
||||||
|
public function testAddFilesFromGlobRecursive()
|
||||||
|
{
|
||||||
|
$localPath = '/';
|
||||||
|
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile->addFilesFromGlobRecursive($this->outputDirname, '**.{txt,jpg}', $localPath);
|
||||||
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertCorrectZipArchive($this->outputFilename);
|
||||||
|
|
||||||
|
$zipFile->openFile($this->outputFilename);
|
||||||
|
self::assertFilesResult($zipFile, [
|
||||||
|
'text file.txt',
|
||||||
|
'Текстовый документ.txt',
|
||||||
|
'category/list.txt',
|
||||||
|
'category/Pictures/128x160/Car/01.jpg',
|
||||||
|
'category/Pictures/128x160/Car/02.jpg',
|
||||||
|
'category/Pictures/240x320/Car/01.jpg',
|
||||||
|
'category/Pictures/240x320/Car/02.jpg',
|
||||||
|
], $localPath);
|
||||||
|
$zipFile->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create archive and add files from regex pattern
|
||||||
|
*/
|
||||||
|
public function testAddFilesFromRegex()
|
||||||
|
{
|
||||||
|
$localPath = 'path';
|
||||||
|
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile->addFilesFromRegex($this->outputDirname, '~\.(txt|jpe?g)$~i', $localPath);
|
||||||
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertCorrectZipArchive($this->outputFilename);
|
||||||
|
|
||||||
|
$zipFile->openFile($this->outputFilename);
|
||||||
|
self::assertFilesResult($zipFile, [
|
||||||
|
'text file.txt',
|
||||||
|
'Текстовый документ.txt',
|
||||||
|
], $localPath);
|
||||||
|
$zipFile->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create archive and add files recursively from regex pattern
|
||||||
|
*/
|
||||||
|
public function testAddFilesFromRegexRecursive()
|
||||||
|
{
|
||||||
|
$localPath = '/';
|
||||||
|
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile->addFilesFromRegexRecursive($this->outputDirname, '~\.(txt|jpe?g)$~i', $localPath);
|
||||||
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertCorrectZipArchive($this->outputFilename);
|
||||||
|
|
||||||
|
$zipFile->openFile($this->outputFilename);
|
||||||
|
self::assertFilesResult($zipFile, [
|
||||||
|
'text file.txt',
|
||||||
|
'Текстовый документ.txt',
|
||||||
|
'category/list.txt',
|
||||||
|
'category/Pictures/128x160/Car/01.jpg',
|
||||||
|
'category/Pictures/128x160/Car/02.jpg',
|
||||||
|
'category/Pictures/240x320/Car/01.jpg',
|
||||||
|
'category/Pictures/240x320/Car/02.jpg',
|
||||||
|
], $localPath);
|
||||||
|
$zipFile->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testArrayAccessAddDir()
|
||||||
|
{
|
||||||
|
$localPath = 'path/to';
|
||||||
|
$iterator = new \RecursiveDirectoryIterator($this->outputDirname);
|
||||||
|
|
||||||
|
$zipFile = new ZipFile();
|
||||||
|
$zipFile[$localPath] = $iterator;
|
||||||
|
$zipFile->saveAsFile($this->outputFilename);
|
||||||
|
$zipFile->close();
|
||||||
|
|
||||||
|
self::assertCorrectZipArchive($this->outputFilename);
|
||||||
|
|
||||||
|
$zipFile->openFile($this->outputFilename);
|
||||||
|
self::assertFilesResult($zipFile, array_keys(self::$files), $localPath);
|
||||||
|
$zipFile->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,51 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace PhpZip;
|
namespace PhpZip;
|
||||||
|
|
||||||
use PhpZip\Model\EndOfCentralDirectory;
|
use PhpZip\Model\EndOfCentralDirectory;
|
||||||
|
use PhpZip\Util\FilesUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PHPUnit test case and helper methods.
|
* PHPUnit test case and helper methods.
|
||||||
*/
|
*/
|
||||||
class ZipTestCase extends \PHPUnit_Framework_TestCase
|
class ZipTestCase extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $outputFilename;
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $outputDirname;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Before test
|
||||||
|
*/
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$id = uniqid('phpzip');
|
||||||
|
$this->outputFilename = sys_get_temp_dir() . '/' . $id . '.zip';
|
||||||
|
$this->outputDirname = sys_get_temp_dir() . '/' . $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After test
|
||||||
|
*/
|
||||||
|
protected function tearDown()
|
||||||
|
{
|
||||||
|
parent::tearDown();
|
||||||
|
|
||||||
|
if ($this->outputFilename !== null && file_exists($this->outputFilename)) {
|
||||||
|
unlink($this->outputFilename);
|
||||||
|
}
|
||||||
|
if ($this->outputDirname !== null && is_dir($this->outputDirname)) {
|
||||||
|
FilesUtil::removeDir($this->outputDirname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assert correct zip archive.
|
* Assert correct zip archive.
|
||||||
*
|
*
|
||||||
|
Reference in New Issue
Block a user