|
@@ -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 array|string|null $entries The entries to extract. It accepts either
|
|
|
|
|
- * a single entry name or an array of names.
|
|
|
|
|
|
|
+ * @param string $destDir location where to extract the files
|
|
|
|
|
+ * @param array|string|null $entries entries to extract
|
|
|
|
|
+ * @param array $options extract options
|
|
|
|
|
+ * @param array $extractedEntries if the extractedEntries argument
|
|
|
|
|
+ * is present, then the specified
|
|
|
|
|
+ * array will be filled with
|
|
|
|
|
+ * information about the
|
|
|
|
|
+ * extracted entries
|
|
|
*
|
|
*
|
|
|
* @throws ZipException
|
|
* @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);
|
|
|
|
|
+ $zipEntry->setCreatedOS(ZipPlatform::OS_UNIX);
|
|
|
|
|
+ $zipEntry->setExtractedOS(ZipPlatform::OS_UNIX);
|
|
|
|
|
+
|
|
|
$zipData = null;
|
|
$zipData = null;
|
|
|
|
|
+ $filePerms = $file->getPerms();
|
|
|
|
|
+
|
|
|
|
|
+ if ($file->isLink()) {
|
|
|
|
|
+ $linkTarget = $file->getLinkTarget();
|
|
|
|
|
+ $lengthLinkTarget = \strlen($linkTarget);
|
|
|
|
|
|
|
|
- if ($file->isFile()) {
|
|
|
|
|
|
|
+ $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->setExtractedOS(ZipPlatform::OS_UNIX);
|
|
|
|
|
- $zipEntry->setUnixMode($file->getPerms());
|
|
|
|
|
|
|
+ $zipEntry->setUnixMode($filePerms);
|
|
|
|
|
|
|
|
$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();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|