Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/CarnetApp/CarnetNextcloud.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/nelexa/zip/src/PhpZip/Stream')
-rw-r--r--vendor/nelexa/zip/src/PhpZip/Stream/ResponseStream.php298
-rw-r--r--vendor/nelexa/zip/src/PhpZip/Stream/ZipInputStream.php603
-rw-r--r--vendor/nelexa/zip/src/PhpZip/Stream/ZipInputStreamInterface.php53
-rw-r--r--vendor/nelexa/zip/src/PhpZip/Stream/ZipOutputStream.php528
-rw-r--r--vendor/nelexa/zip/src/PhpZip/Stream/ZipOutputStreamInterface.php29
5 files changed, 1511 insertions, 0 deletions
diff --git a/vendor/nelexa/zip/src/PhpZip/Stream/ResponseStream.php b/vendor/nelexa/zip/src/PhpZip/Stream/ResponseStream.php
new file mode 100644
index 0000000..172de1e
--- /dev/null
+++ b/vendor/nelexa/zip/src/PhpZip/Stream/ResponseStream.php
@@ -0,0 +1,298 @@
+<?php
+
+namespace PhpZip\Stream;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Implement PSR Message Stream
+ */
+class ResponseStream implements StreamInterface
+{
+ /**
+ * @var array
+ */
+ private static $readWriteHash = [
+ 'read' => [
+ 'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true,
+ 'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true,
+ 'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true,
+ 'x+t' => true, 'c+t' => true, 'a+' => true,
+ ],
+ 'write' => [
+ 'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true,
+ 'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true,
+ 'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true,
+ 'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true,
+ ],
+ ];
+ /**
+ * @var resource
+ */
+ private $stream;
+ /**
+ * @var int
+ */
+ private $size;
+ /**
+ * @var bool
+ */
+ private $seekable;
+ /**
+ * @var bool
+ */
+ private $readable;
+ /**
+ * @var bool
+ */
+ private $writable;
+ /**
+ * @var array|mixed|null
+ */
+ private $uri;
+
+ /**
+ * @param resource $stream Stream resource to wrap.
+ * @throws \InvalidArgumentException if the stream is not a stream resource
+ */
+ public function __construct($stream)
+ {
+ if (!is_resource($stream)) {
+ throw new \InvalidArgumentException('Stream must be a resource');
+ }
+ $this->stream = $stream;
+ $meta = stream_get_meta_data($this->stream);
+ $this->seekable = $meta['seekable'];
+ $this->readable = isset(self::$readWriteHash['read'][$meta['mode']]);
+ $this->writable = isset(self::$readWriteHash['write'][$meta['mode']]);
+ $this->uri = $this->getMetadata('uri');
+ }
+
+ /**
+ * Get stream metadata as an associative array or retrieve a specific key.
+ *
+ * The keys returned are identical to the keys returned from PHP's
+ * stream_get_meta_data() function.
+ *
+ * @link http://php.net/manual/en/function.stream-get-meta-data.php
+ * @param string $key Specific metadata to retrieve.
+ * @return array|mixed|null Returns an associative array if no key is
+ * provided. Returns a specific key value if a key is provided and the
+ * value is found, or null if the key is not found.
+ */
+ public function getMetadata($key = null)
+ {
+ if (!$this->stream) {
+ return $key ? null : [];
+ }
+ $meta = stream_get_meta_data($this->stream);
+ return isset($meta[$key]) ? $meta[$key] : null;
+ }
+
+ /**
+ * Reads all data from the stream into a string, from the beginning to end.
+ *
+ * This method MUST attempt to seek to the beginning of the stream before
+ * reading data and read the stream until the end is reached.
+ *
+ * Warning: This could attempt to load a large amount of data into memory.
+ *
+ * This method MUST NOT raise an exception in order to conform with PHP's
+ * string casting operations.
+ *
+ * @see http://php.net/manual/en/language.oop5.magic.php#object.tostring
+ * @return string
+ */
+ public function __toString()
+ {
+ if (!$this->stream) {
+ return '';
+ }
+ $this->rewind();
+ return (string)stream_get_contents($this->stream);
+ }
+
+ /**
+ * Seek to the beginning of the stream.
+ *
+ * If the stream is not seekable, this method will raise an exception;
+ * otherwise, it will perform a seek(0).
+ *
+ * @see seek()
+ * @link http://www.php.net/manual/en/function.fseek.php
+ * @throws \RuntimeException on failure.
+ */
+ public function rewind()
+ {
+ $this->seekable && rewind($this->stream);
+ }
+
+ /**
+ * Get the size of the stream if known.
+ *
+ * @return int|null Returns the size in bytes if known, or null if unknown.
+ */
+ public function getSize()
+ {
+ if ($this->size !== null) {
+ return $this->size;
+ }
+ if (!$this->stream) {
+ return null;
+ }
+ // Clear the stat cache if the stream has a URI
+ if ($this->uri) {
+ clearstatcache(true, $this->uri);
+ }
+ $stats = fstat($this->stream);
+ if (isset($stats['size'])) {
+ $this->size = $stats['size'];
+ return $this->size;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the current position of the file read/write pointer
+ *
+ * @return int Position of the file pointer
+ * @throws \RuntimeException on error.
+ */
+ public function tell()
+ {
+ return $this->stream ? ftell($this->stream) : false;
+ }
+
+ /**
+ * Returns true if the stream is at the end of the stream.
+ *
+ * @return bool
+ */
+ public function eof()
+ {
+ return !$this->stream || feof($this->stream);
+ }
+
+ /**
+ * Returns whether or not the stream is seekable.
+ *
+ * @return bool
+ */
+ public function isSeekable()
+ {
+ return $this->seekable;
+ }
+
+ /**
+ * Seek to a position in the stream.
+ *
+ * @link http://www.php.net/manual/en/function.fseek.php
+ * @param int $offset Stream offset
+ * @param int $whence Specifies how the cursor position will be calculated
+ * based on the seek offset. Valid values are identical to the built-in
+ * PHP $whence values for `fseek()`. SEEK_SET: Set position equal to
+ * offset bytes SEEK_CUR: Set position to current location plus offset
+ * SEEK_END: Set position to end-of-stream plus offset.
+ * @throws \RuntimeException on failure.
+ */
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ $this->seekable && fseek($this->stream, $offset, $whence);
+ }
+
+ /**
+ * Returns whether or not the stream is writable.
+ *
+ * @return bool
+ */
+ public function isWritable()
+ {
+ return $this->writable;
+ }
+
+ /**
+ * Write data to the stream.
+ *
+ * @param string $string The string that is to be written.
+ * @return int Returns the number of bytes written to the stream.
+ * @throws \RuntimeException on failure.
+ */
+ public function write($string)
+ {
+ $this->size = null;
+ return $this->writable ? fwrite($this->stream, $string) : false;
+ }
+
+ /**
+ * Returns whether or not the stream is readable.
+ *
+ * @return bool
+ */
+ public function isReadable()
+ {
+ return $this->readable;
+ }
+
+ /**
+ * Read data from the stream.
+ *
+ * @param int $length Read up to $length bytes from the object and return
+ * them. Fewer than $length bytes may be returned if underlying stream
+ * call returns fewer bytes.
+ * @return string Returns the data read from the stream, or an empty string
+ * if no bytes are available.
+ * @throws \RuntimeException if an error occurs.
+ */
+ public function read($length)
+ {
+ return $this->readable ? fread($this->stream, $length) : "";
+ }
+
+ /**
+ * Returns the remaining contents in a string
+ *
+ * @return string
+ * @throws \RuntimeException if unable to read or an error occurs while
+ * reading.
+ */
+ public function getContents()
+ {
+ return $this->stream ? stream_get_contents($this->stream) : '';
+ }
+
+ /**
+ * Closes the stream when the destructed
+ */
+ public function __destruct()
+ {
+ $this->close();
+ }
+
+ /**
+ * Closes the stream and any underlying resources.
+ *
+ * @return void
+ */
+ public function close()
+ {
+ if (is_resource($this->stream)) {
+ fclose($this->stream);
+ }
+ $this->detach();
+ }
+
+ /**
+ * Separates any underlying resources from the stream.
+ *
+ * After the stream has been detached, the stream is in an unusable state.
+ *
+ * @return resource|null Underlying PHP stream, if any
+ */
+ public function detach()
+ {
+ $result = $this->stream;
+ $this->stream = $this->size = $this->uri = null;
+ $this->readable = $this->writable = $this->seekable = false;
+ return $result;
+ }
+}
diff --git a/vendor/nelexa/zip/src/PhpZip/Stream/ZipInputStream.php b/vendor/nelexa/zip/src/PhpZip/Stream/ZipInputStream.php
new file mode 100644
index 0000000..8c8adf5
--- /dev/null
+++ b/vendor/nelexa/zip/src/PhpZip/Stream/ZipInputStream.php
@@ -0,0 +1,603 @@
+<?php
+
+namespace PhpZip\Stream;
+
+use PhpZip\Crypto\TraditionalPkwareEncryptionEngine;
+use PhpZip\Crypto\WinZipAesEngine;
+use PhpZip\Exception\Crc32Exception;
+use PhpZip\Exception\InvalidArgumentException;
+use PhpZip\Exception\RuntimeException;
+use PhpZip\Exception\ZipCryptoException;
+use PhpZip\Exception\ZipException;
+use PhpZip\Exception\ZipUnsupportMethod;
+use PhpZip\Extra\ExtraFieldsCollection;
+use PhpZip\Extra\ExtraFieldsFactory;
+use PhpZip\Extra\Fields\ApkAlignmentExtraField;
+use PhpZip\Extra\Fields\WinZipAesEntryExtraField;
+use PhpZip\Mapper\OffsetPositionMapper;
+use PhpZip\Mapper\PositionMapper;
+use PhpZip\Model\EndOfCentralDirectory;
+use PhpZip\Model\Entry\ZipSourceEntry;
+use PhpZip\Model\ZipEntry;
+use PhpZip\Model\ZipModel;
+use PhpZip\Util\PackUtil;
+use PhpZip\Util\StringUtil;
+use PhpZip\ZipFileInterface;
+
+/**
+ * Read zip file
+ *
+ * @author Ne-Lexa alexey@nelexa.ru
+ * @license MIT
+ */
+class ZipInputStream implements ZipInputStreamInterface
+{
+ /**
+ * @var resource
+ */
+ protected $in;
+ /**
+ * @var PositionMapper
+ */
+ protected $mapper;
+ /**
+ * @var int The number of bytes in the preamble of this ZIP file.
+ */
+ protected $preamble = 0;
+ /**
+ * @var int The number of bytes in the postamble of this ZIP file.
+ */
+ protected $postamble = 0;
+ /**
+ * @var ZipModel
+ */
+ protected $zipModel;
+
+ /**
+ * ZipInputStream constructor.
+ * @param resource $in
+ * @throws RuntimeException
+ */
+ public function __construct($in)
+ {
+ if (!is_resource($in)) {
+ throw new RuntimeException('$in must be resource');
+ }
+ $this->in = $in;
+ $this->mapper = new PositionMapper();
+ }
+
+ /**
+ * @return ZipModel
+ */
+ public function readZip()
+ {
+ $this->checkZipFileSignature();
+ $endOfCentralDirectory = $this->readEndOfCentralDirectory();
+ $entries = $this->mountCentralDirectory($endOfCentralDirectory);
+ $this->zipModel = ZipModel::newSourceModel($entries, $endOfCentralDirectory);
+ return $this->zipModel;
+ }
+
+ /**
+ * Check zip file signature
+ *
+ * @throws ZipException if this not .ZIP file.
+ */
+ protected function checkZipFileSignature()
+ {
+ rewind($this->in);
+ // Constraint: A ZIP file must start with a Local File Header
+ // or a (ZIP64) End Of Central Directory Record if it's empty.
+ $signatureBytes = fread($this->in, 4);
+ if (strlen($signatureBytes) < 4) {
+ throw new ZipException("Invalid zip file.");
+ }
+ $signature = unpack('V', $signatureBytes)[1];
+ if (
+ ZipEntry::LOCAL_FILE_HEADER_SIG !== $signature
+ && EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIG !== $signature
+ && EndOfCentralDirectory::END_OF_CENTRAL_DIRECTORY_RECORD_SIG !== $signature
+ ) {
+ throw new ZipException("Expected Local File Header or (ZIP64) End Of Central Directory Record! Signature: " . $signature);
+ }
+ }
+
+ /**
+ * @return EndOfCentralDirectory
+ * @throws ZipException
+ */
+ protected function readEndOfCentralDirectory()
+ {
+ $comment = null;
+ // Search for End of central directory record.
+ $stats = fstat($this->in);
+ $size = $stats['size'];
+ $max = $size - EndOfCentralDirectory::END_OF_CENTRAL_DIRECTORY_RECORD_MIN_LEN;
+ $min = $max >= 0xffff ? $max - 0xffff : 0;
+ for ($endOfCentralDirRecordPos = $max; $endOfCentralDirRecordPos >= $min; $endOfCentralDirRecordPos--) {
+ fseek($this->in, $endOfCentralDirRecordPos, SEEK_SET);
+ // end of central dir signature 4 bytes (0x06054b50)
+ if (EndOfCentralDirectory::END_OF_CENTRAL_DIRECTORY_RECORD_SIG !== unpack('V', fread($this->in, 4))[1]) {
+ continue;
+ }
+
+ // number of this disk - 2 bytes
+ // number of the disk with the start of the
+ // central directory - 2 bytes
+ // total number of entries in the central
+ // directory on this disk - 2 bytes
+ // total number of entries in the central
+ // directory - 2 bytes
+ // size of the central directory - 4 bytes
+ // offset of start of central directory with
+ // respect to the starting disk number - 4 bytes
+ // ZIP file comment length - 2 bytes
+ $data = unpack(
+ 'vdiskNo/vcdDiskNo/vcdEntriesDisk/vcdEntries/VcdSize/VcdPos/vcommentLength',
+ fread($this->in, 18)
+ );
+
+ if (0 !== $data['diskNo'] || 0 !== $data['cdDiskNo'] || $data['cdEntriesDisk'] !== $data['cdEntries']) {
+ throw new ZipException(
+ "ZIP file spanning/splitting is not supported!"
+ );
+ }
+ // .ZIP file comment (variable size)
+ if (0 < $data['commentLength']) {
+ $comment = fread($this->in, $data['commentLength']);
+ }
+ $this->preamble = $endOfCentralDirRecordPos;
+ $this->postamble = $size - ftell($this->in);
+
+ // Check for ZIP64 End Of Central Directory Locator.
+ $endOfCentralDirLocatorPos = $endOfCentralDirRecordPos - EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_LEN;
+
+ fseek($this->in, $endOfCentralDirLocatorPos, SEEK_SET);
+ // zip64 end of central dir locator
+ // signature 4 bytes (0x07064b50)
+ if (
+ 0 > $endOfCentralDirLocatorPos ||
+ ftell($this->in) === $size ||
+ EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG !== unpack('V', fread($this->in, 4))[1]
+ ) {
+ // Seek and check first CFH, probably requiring an offset mapper.
+ $offset = $endOfCentralDirRecordPos - $data['cdSize'];
+ fseek($this->in, $offset, SEEK_SET);
+ $offset -= $data['cdPos'];
+ if (0 !== $offset) {
+ $this->mapper = new OffsetPositionMapper($offset);
+ }
+ $entryCount = $data['cdEntries'];
+ return new EndOfCentralDirectory($entryCount, $comment);
+ }
+
+ // number of the disk with the
+ // start of the zip64 end of
+ // central directory 4 bytes
+ $zip64EndOfCentralDirectoryRecordDisk = unpack('V', fread($this->in, 4))[1];
+ // relative offset of the zip64
+ // end of central directory record 8 bytes
+ $zip64EndOfCentralDirectoryRecordPos = PackUtil::unpackLongLE(fread($this->in, 8));
+ // total number of disks 4 bytes
+ $totalDisks = unpack('V', fread($this->in, 4))[1];
+ if (0 !== $zip64EndOfCentralDirectoryRecordDisk || 1 !== $totalDisks) {
+ throw new ZipException("ZIP file spanning/splitting is not supported!");
+ }
+ fseek($this->in, $zip64EndOfCentralDirectoryRecordPos, SEEK_SET);
+ // zip64 end of central dir
+ // signature 4 bytes (0x06064b50)
+ $zip64EndOfCentralDirSig = unpack('V', fread($this->in, 4))[1];
+ if (EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIG !== $zip64EndOfCentralDirSig) {
+ throw new ZipException("Expected ZIP64 End Of Central Directory Record!");
+ }
+ // size of zip64 end of central
+ // directory record 8 bytes
+ // version made by 2 bytes
+ // version needed to extract 2 bytes
+ fseek($this->in, 12, SEEK_CUR);
+ // number of this disk 4 bytes
+ $diskNo = unpack('V', fread($this->in, 4))[1];
+ // number of the disk with the
+ // start of the central directory 4 bytes
+ $cdDiskNo = unpack('V', fread($this->in, 4))[1];
+ // total number of entries in the
+ // central directory on this disk 8 bytes
+ $cdEntriesDisk = PackUtil::unpackLongLE(fread($this->in, 8));
+ // total number of entries in the
+ // central directory 8 bytes
+ $cdEntries = PackUtil::unpackLongLE(fread($this->in, 8));
+ if (0 !== $diskNo || 0 !== $cdDiskNo || $cdEntriesDisk !== $cdEntries) {
+ throw new ZipException("ZIP file spanning/splitting is not supported!");
+ }
+ if ($cdEntries < 0 || 0x7fffffff < $cdEntries) {
+ throw new ZipException("Total Number Of Entries In The Central Directory out of range!");
+ }
+ // size of the central directory 8 bytes
+ fseek($this->in, 8, SEEK_CUR);
+ // offset of start of central
+ // directory with respect to
+ // the starting disk number 8 bytes
+ $cdPos = PackUtil::unpackLongLE(fread($this->in, 8));
+ // zip64 extensible data sector (variable size)
+ fseek($this->in, $cdPos, SEEK_SET);
+ $this->preamble = $zip64EndOfCentralDirectoryRecordPos;
+ $entryCount = $cdEntries;
+ $zip64 = true;
+ return new EndOfCentralDirectory($entryCount, $comment, $zip64);
+ }
+ // Start recovering file entries from min.
+ $this->preamble = $min;
+ $this->postamble = $size - $min;
+ return new EndOfCentralDirectory(0, $comment);
+ }
+
+ /**
+ * Reads the central directory from the given seekable byte channel
+ * and populates the internal tables with ZipEntry instances.
+ *
+ * The ZipEntry's will know all data that can be obtained from the
+ * central directory alone, but not the data that requires the local
+ * file header or additional data to be read.
+ *
+ * @param EndOfCentralDirectory $endOfCentralDirectory
+ * @return ZipEntry[]
+ * @throws ZipException
+ */
+ protected function mountCentralDirectory(EndOfCentralDirectory $endOfCentralDirectory)
+ {
+ $numEntries = $endOfCentralDirectory->getEntryCount();
+ $entries = [];
+
+ for (; $numEntries > 0; $numEntries--) {
+ $entry = $this->readEntry();
+ // Re-load virtual offset after ZIP64 Extended Information
+ // Extra Field may have been parsed, map it to the real
+ // offset and conditionally update the preamble size from it.
+ $lfhOff = $this->mapper->map($entry->getOffset());
+ $lfhOff = PHP_INT_SIZE === 4 ? sprintf('%u', $lfhOff) : $lfhOff;
+ if ($lfhOff < $this->preamble) {
+ $this->preamble = $lfhOff;
+ }
+ $entries[$entry->getName()] = $entry;
+ }
+
+ if (0 !== $numEntries % 0x10000) {
+ throw new ZipException("Expected " . abs($numEntries) .
+ ($numEntries > 0 ? " more" : " less") .
+ " entries in the Central Directory!");
+ }
+
+ if ($this->preamble + $this->postamble >= fstat($this->in)['size']) {
+ assert(0 === $numEntries);
+ $this->checkZipFileSignature();
+ }
+
+ return $entries;
+ }
+
+ /**
+ * @return ZipEntry
+ * @throws InvalidArgumentException
+ */
+ public function readEntry()
+ {
+ // central file header signature 4 bytes (0x02014b50)
+ $fileHeaderSig = unpack('V', fread($this->in, 4))[1];
+ if (ZipOutputStreamInterface::CENTRAL_FILE_HEADER_SIG !== $fileHeaderSig) {
+ throw new InvalidArgumentException("Corrupt zip file. Can not read zip entry.");
+ }
+
+ // version made by 2 bytes
+ // version needed to extract 2 bytes
+ // general purpose bit flag 2 bytes
+ // compression method 2 bytes
+ // last mod file time 2 bytes
+ // last mod file date 2 bytes
+ // crc-32 4 bytes
+ // compressed size 4 bytes
+ // uncompressed size 4 bytes
+ // file name length 2 bytes
+ // extra field length 2 bytes
+ // file comment length 2 bytes
+ // disk number start 2 bytes
+ // internal file attributes 2 bytes
+ // external file attributes 4 bytes
+ // relative offset of local header 4 bytes
+ $data = unpack(
+ 'vversionMadeBy/vversionNeededToExtract/vgpbf/' .
+ 'vrawMethod/VrawTime/VrawCrc/VrawCompressedSize/' .
+ 'VrawSize/vfileLength/vextraLength/vcommentLength/' .
+ 'VrawInternalAttributes/VrawExternalAttributes/VlfhOff',
+ fread($this->in, 42)
+ );
+
+// $utf8 = 0 !== ($data['gpbf'] & self::GPBF_UTF8);
+
+ // See appendix D of PKWARE's ZIP File Format Specification.
+ $name = fread($this->in, $data['fileLength']);
+
+ $entry = new ZipSourceEntry($this);
+ $entry->setName($name);
+ $entry->setVersionNeededToExtract($data['versionNeededToExtract']);
+ $entry->setPlatform($data['versionMadeBy'] >> 8);
+ $entry->setMethod($data['rawMethod']);
+ $entry->setGeneralPurposeBitFlags($data['gpbf']);
+ $entry->setDosTime($data['rawTime']);
+ $entry->setCrc($data['rawCrc']);
+ $entry->setCompressedSize($data['rawCompressedSize']);
+ $entry->setSize($data['rawSize']);
+ $entry->setExternalAttributes($data['rawExternalAttributes']);
+ $entry->setOffset($data['lfhOff']); // must be unmapped!
+ if (0 < $data['extraLength']) {
+ $entry->setExtra(fread($this->in, $data['extraLength']));
+ }
+ if (0 < $data['commentLength']) {
+ $entry->setComment(fread($this->in, $data['commentLength']));
+ }
+ return $entry;
+ }
+
+ /**
+ * @param ZipEntry $entry
+ * @return string
+ * @throws ZipException
+ */
+ public function readEntryContent(ZipEntry $entry)
+ {
+ if ($entry->isDirectory()) {
+ return null;
+ }
+ if (!($entry instanceof ZipSourceEntry)) {
+ throw new InvalidArgumentException('entry must be ' . ZipSourceEntry::class);
+ }
+ $isEncrypted = $entry->isEncrypted();
+ if ($isEncrypted && null === $entry->getPassword()) {
+ throw new ZipException("Can not password from entry " . $entry->getName());
+ }
+
+ $pos = $entry->getOffset();
+ assert(ZipEntry::UNKNOWN !== $pos);
+ $pos = PHP_INT_SIZE === 4 ? sprintf('%u', $pos) : $pos;
+
+ $startPos = $pos = $this->mapper->map($pos);
+ fseek($this->in, $startPos);
+
+ // local file header signature 4 bytes (0x04034b50)
+ if (ZipEntry::LOCAL_FILE_HEADER_SIG !== unpack('V', fread($this->in, 4))[1]) {
+ throw new ZipException($entry->getName() . " (expected Local File Header)");
+ }
+ fseek($this->in, $pos + ZipEntry::LOCAL_FILE_HEADER_FILE_NAME_LENGTH_POS);
+ // file name length 2 bytes
+ // extra field length 2 bytes
+ $data = unpack('vfileLength/vextraLength', fread($this->in, 4));
+ $pos += ZipEntry::LOCAL_FILE_HEADER_MIN_LEN + $data['fileLength'] + $data['extraLength'];
+
+ assert(ZipEntry::UNKNOWN !== $entry->getCrc());
+
+ $method = $entry->getMethod();
+
+ fseek($this->in, $pos);
+
+ // Get raw entry content
+ $compressedSize = $entry->getCompressedSize();
+ $compressedSize = PHP_INT_SIZE === 4 ? sprintf('%u', $compressedSize) : $compressedSize;
+ if ($compressedSize > 0) {
+ $content = fread($this->in, $compressedSize);
+ } else {
+ $content = '';
+ }
+
+ $skipCheckCrc = false;
+ if ($isEncrypted) {
+ if (ZipEntry::METHOD_WINZIP_AES === $method) {
+ // Strong Encryption Specification - WinZip AES
+ $winZipAesEngine = new WinZipAesEngine($entry);
+ $content = $winZipAesEngine->decrypt($content);
+ /**
+ * @var WinZipAesEntryExtraField $field
+ */
+ $field = $entry->getExtraFieldsCollection()->get(WinZipAesEntryExtraField::getHeaderId());
+ $method = $field->getMethod();
+ $entry->setEncryptionMethod($field->getEncryptionMethod());
+ $skipCheckCrc = true;
+ } else {
+ // Traditional PKWARE Decryption
+ $zipCryptoEngine = new TraditionalPkwareEncryptionEngine($entry);
+ $content = $zipCryptoEngine->decrypt($content);
+ $entry->setEncryptionMethod(ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL);
+ }
+
+ if (!$skipCheckCrc) {
+ // Check CRC32 in the Local File Header or Data Descriptor.
+ $localCrc = null;
+ if ($entry->getGeneralPurposeBitFlag(ZipEntry::GPBF_DATA_DESCRIPTOR)) {
+ // The CRC32 is in the Data Descriptor after the compressed size.
+ // Note the Data Descriptor's Signature is optional:
+ // All newer apps should write it (and so does TrueVFS),
+ // but older apps might not.
+ fseek($this->in, $pos + $compressedSize);
+ $localCrc = unpack('V', fread($this->in, 4))[1];
+ if (ZipEntry::DATA_DESCRIPTOR_SIG === $localCrc) {
+ $localCrc = unpack('V', fread($this->in, 4))[1];
+ }
+ } else {
+ fseek($this->in, $startPos + 14);
+ // The CRC32 in the Local File Header.
+ $localCrc = sprintf('%u', fread($this->in, 4)[1]);
+ $localCrc = PHP_INT_SIZE === 4 ? sprintf('%u', $localCrc) : $localCrc;
+ }
+
+ $crc = PHP_INT_SIZE === 4 ? sprintf('%u', $entry->getCrc()) : $entry->getCrc();
+
+ if ($crc != $localCrc) {
+ throw new Crc32Exception($entry->getName(), $crc, $localCrc);
+ }
+ }
+ }
+
+ switch ($method) {
+ case ZipFileInterface::METHOD_STORED:
+ break;
+ case ZipFileInterface::METHOD_DEFLATED:
+ $content = gzinflate($content);
+ break;
+ case ZipFileInterface::METHOD_BZIP2:
+ if (!extension_loaded('bz2')) {
+ throw new ZipException('Extension bzip2 not install');
+ }
+ $content = bzdecompress($content);
+ break;
+ default:
+ throw new ZipUnsupportMethod($entry->getName() .
+ " (compression method " . $method . " is not supported)");
+ }
+ if (!$skipCheckCrc AND false) {
+ $localCrc = crc32($content);
+ $localCrc = PHP_INT_SIZE === 4 ? sprintf('%u', $localCrc) : $localCrc;
+ $crc = PHP_INT_SIZE === 4 ? sprintf('%u', $entry->getCrc()) : $entry->getCrc();
+ if ($crc != $localCrc) {
+ if ($isEncrypted) {
+ throw new ZipCryptoException("Wrong password");
+ }
+ throw new Crc32Exception($entry->getName(), $crc, $localCrc);
+ }
+ }
+ return $content;
+ }
+
+ /**
+ * @return resource
+ */
+ public function getStream()
+ {
+ return $this->in;
+ }
+
+ /**
+ * Copy the input stream of the LOC entry zip and the data into
+ * the output stream and zip the alignment if necessary.
+ *
+ * @param ZipEntry $entry
+ * @param ZipOutputStreamInterface $out
+ */
+ public function copyEntry(ZipEntry $entry, ZipOutputStreamInterface $out)
+ {
+ $pos = $entry->getOffset();
+ assert(ZipEntry::UNKNOWN !== $pos);
+ $pos = PHP_INT_SIZE === 4 ? sprintf('%u', $pos) : $pos;
+ $pos = $this->mapper->map($pos);
+
+ $nameLength = strlen($entry->getName());
+
+ fseek($this->in, $pos + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN - 2, SEEK_SET);
+ $sourceExtraLength = $destExtraLength = unpack('v', fread($this->in, 2))[1];
+
+ if ($sourceExtraLength > 0) {
+ // read Local File Header extra fields
+ fseek($this->in, $pos + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN + $nameLength, SEEK_SET);
+ $extra = fread($this->in, $sourceExtraLength);
+ $extraFieldsCollection = ExtraFieldsFactory::createExtraFieldCollections($extra, $entry);
+ if (isset($extraFieldsCollection[ApkAlignmentExtraField::getHeaderId()]) && $this->zipModel->isZipAlign()) {
+ unset($extraFieldsCollection[ApkAlignmentExtraField::getHeaderId()]);
+ $destExtraLength = strlen(ExtraFieldsFactory::createSerializedData($extraFieldsCollection));
+ }
+ } else {
+ $extraFieldsCollection = new ExtraFieldsCollection();
+ }
+
+ $dataAlignmentMultiple = $this->zipModel->getZipAlign();
+ $copyInToOutLength = $entry->getCompressedSize();
+
+ fseek($this->in, $pos, SEEK_SET);
+
+ if (
+ $this->zipModel->isZipAlign() &&
+ !$entry->isEncrypted() &&
+ $entry->getMethod() === ZipFileInterface::METHOD_STORED
+ ) {
+ if (StringUtil::endsWith($entry->getName(), '.so')) {
+ $dataAlignmentMultiple = ApkAlignmentExtraField::ANDROID_COMMON_PAGE_ALIGNMENT_BYTES;
+ }
+
+ $dataMinStartOffset =
+ ftell($out->getStream()) +
+ ZipEntry::LOCAL_FILE_HEADER_MIN_LEN +
+ $destExtraLength +
+ $nameLength +
+ ApkAlignmentExtraField::ALIGNMENT_ZIP_EXTRA_MIN_SIZE_BYTES;
+ $padding =
+ ($dataAlignmentMultiple - ($dataMinStartOffset % $dataAlignmentMultiple))
+ % $dataAlignmentMultiple;
+
+ $alignExtra = new ApkAlignmentExtraField();
+ $alignExtra->setMultiple($dataAlignmentMultiple);
+ $alignExtra->setPadding($padding);
+ $extraFieldsCollection->add($alignExtra);
+
+ $extra = ExtraFieldsFactory::createSerializedData($extraFieldsCollection);
+
+ // copy Local File Header without extra field length
+ // from input stream to output stream
+ stream_copy_to_stream($this->in, $out->getStream(), ZipEntry::LOCAL_FILE_HEADER_MIN_LEN - 2);
+ // write new extra field length (2 bytes) to output stream
+ fwrite($out->getStream(), pack('v', strlen($extra)));
+ // skip 2 bytes to input stream
+ fseek($this->in, 2, SEEK_CUR);
+ // copy name from input stream to output stream
+ stream_copy_to_stream($this->in, $out->getStream(), $nameLength);
+ // write extra field to output stream
+ fwrite($out->getStream(), $extra);
+ // skip source extraLength from input stream
+ fseek($this->in, $sourceExtraLength, SEEK_CUR);
+ } else {
+ $copyInToOutLength += ZipEntry::LOCAL_FILE_HEADER_MIN_LEN + $sourceExtraLength + $nameLength;
+ ;
+ }
+ if ($entry->getGeneralPurposeBitFlag(ZipEntry::GPBF_DATA_DESCRIPTOR)) {
+// crc-32 4 bytes
+// compressed size 4 bytes
+// uncompressed size 4 bytes
+ $copyInToOutLength += 12;
+ if ($entry->isZip64ExtensionsRequired()) {
+// compressed size +4 bytes
+// uncompressed size +4 bytes
+ $copyInToOutLength += 8;
+ }
+ }
+ // copy loc, data, data descriptor from input to output stream
+ stream_copy_to_stream($this->in, $out->getStream(), $copyInToOutLength);
+ }
+
+ /**
+ * @param ZipEntry $entry
+ * @param ZipOutputStreamInterface $out
+ */
+ public function copyEntryData(ZipEntry $entry, ZipOutputStreamInterface $out)
+ {
+ $offset = $entry->getOffset();
+ $offset = PHP_INT_SIZE === 4 ? sprintf('%u', $offset) : $offset;
+ $offset = $this->mapper->map($offset);
+ $nameLength = strlen($entry->getName());
+
+ fseek($this->in, $offset + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN - 2, SEEK_SET);
+ $extraLength = unpack('v', fread($this->in, 2))[1];
+
+ fseek($this->in, $offset + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN + $nameLength + $extraLength, SEEK_SET);
+ // copy raw data from input stream to output stream
+ stream_copy_to_stream($this->in, $out->getStream(), $entry->getCompressedSize());
+ }
+
+ public function __destruct()
+ {
+ $this->close();
+ }
+
+ public function close()
+ {
+ if ($this->in != null) {
+ fclose($this->in);
+ $this->in = null;
+ }
+ }
+}
diff --git a/vendor/nelexa/zip/src/PhpZip/Stream/ZipInputStreamInterface.php b/vendor/nelexa/zip/src/PhpZip/Stream/ZipInputStreamInterface.php
new file mode 100644
index 0000000..2093c03
--- /dev/null
+++ b/vendor/nelexa/zip/src/PhpZip/Stream/ZipInputStreamInterface.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace PhpZip\Stream;
+
+use PhpZip\Model\ZipEntry;
+use PhpZip\Model\ZipModel;
+
+/**
+ * Read zip file
+ *
+ * @author Ne-Lexa alexey@nelexa.ru
+ * @license MIT
+ */
+interface ZipInputStreamInterface
+{
+ /**
+ * @return ZipModel
+ */
+ public function readZip();
+
+ /**
+ * @return ZipEntry
+ */
+ public function readEntry();
+
+ /**
+ * @param ZipEntry $entry
+ * @return string
+ */
+ public function readEntryContent(ZipEntry $entry);
+
+ /**
+ * @return resource
+ */
+ public function getStream();
+
+ /**
+ * Copy the input stream of the LOC entry zip and the data into
+ * the output stream and zip the alignment if necessary.
+ *
+ * @param ZipEntry $entry
+ * @param ZipOutputStreamInterface $out
+ */
+ public function copyEntry(ZipEntry $entry, ZipOutputStreamInterface $out);
+
+ /**
+ * @param ZipEntry $entry
+ * @param ZipOutputStreamInterface $out
+ */
+ public function copyEntryData(ZipEntry $entry, ZipOutputStreamInterface $out);
+
+ public function close();
+}
diff --git a/vendor/nelexa/zip/src/PhpZip/Stream/ZipOutputStream.php b/vendor/nelexa/zip/src/PhpZip/Stream/ZipOutputStream.php
new file mode 100644
index 0000000..c1c875d
--- /dev/null
+++ b/vendor/nelexa/zip/src/PhpZip/Stream/ZipOutputStream.php
@@ -0,0 +1,528 @@
+<?php
+
+namespace PhpZip\Stream;
+
+use PhpZip\Crypto\TraditionalPkwareEncryptionEngine;
+use PhpZip\Crypto\WinZipAesEngine;
+use PhpZip\Exception\InvalidArgumentException;
+use PhpZip\Exception\RuntimeException;
+use PhpZip\Exception\ZipException;
+use PhpZip\Extra\ExtraFieldsFactory;
+use PhpZip\Extra\Fields\ApkAlignmentExtraField;
+use PhpZip\Extra\Fields\WinZipAesEntryExtraField;
+use PhpZip\Extra\Fields\Zip64ExtraField;
+use PhpZip\Model\EndOfCentralDirectory;
+use PhpZip\Model\Entry\OutputOffsetEntry;
+use PhpZip\Model\Entry\ZipChangesEntry;
+use PhpZip\Model\Entry\ZipSourceEntry;
+use PhpZip\Model\ZipEntry;
+use PhpZip\Model\ZipModel;
+use PhpZip\Util\PackUtil;
+use PhpZip\Util\StringUtil;
+use PhpZip\ZipFileInterface;
+
+/**
+ * Write
+ * ip file
+ *
+ * @author Ne-Lexa alexey@nelexa.ru
+ * @license MIT
+ */
+class ZipOutputStream implements ZipOutputStreamInterface
+{
+ /**
+ * @var resource
+ */
+ protected $out;
+ /**
+ * @var ZipModel
+ */
+ protected $zipModel;
+
+ /**
+ * ZipOutputStream constructor.
+ * @param resource $out
+ * @param ZipModel $zipModel
+ * @throws InvalidArgumentException
+ */
+ public function __construct($out, ZipModel $zipModel)
+ {
+ if (!is_resource($out)) {
+ throw new InvalidArgumentException('$out must be resource');
+ }
+ $this->out = $out;
+ $this->zipModel = $zipModel;
+ }
+
+ public function writeZip()
+ {
+ $entries = $this->zipModel->getEntries();
+ $outPosEntries = [];
+ foreach ($entries as $entry) {
+ $outPosEntries[] = new OutputOffsetEntry(ftell($this->out), $entry);
+ $this->writeEntry($entry);
+ }
+ $centralDirectoryOffset = ftell($this->out);
+ foreach ($outPosEntries as $outputEntry) {
+ $this->writeCentralDirectoryHeader($outputEntry);
+ }
+ $this->writeEndOfCentralDirectoryRecord($centralDirectoryOffset);
+ }
+
+ /**
+ * @param ZipEntry $entry
+ * @throws ZipException
+ */
+ public function writeEntry(ZipEntry $entry)
+ {
+ if ($entry instanceof ZipSourceEntry) {
+ $entry->getInputStream()->copyEntry($entry, $this);
+ return;
+ }
+
+ $entryContent = $this->entryCommitChangesAndReturnContent($entry);
+
+ $offset = ftell($this->out);
+ $compressedSize = $entry->getCompressedSize();
+
+ $extra = $entry->getExtra();
+
+ $nameLength = strlen($entry->getName());
+ $extraLength = strlen($extra);
+
+ // zip align
+ if (
+ $this->zipModel->isZipAlign() &&
+ !$entry->isEncrypted() &&
+ $entry->getMethod() === ZipFileInterface::METHOD_STORED
+ ) {
+ $dataAlignmentMultiple = $this->zipModel->getZipAlign();
+ if (StringUtil::endsWith($entry->getName(), '.so')) {
+ $dataAlignmentMultiple = ApkAlignmentExtraField::ANDROID_COMMON_PAGE_ALIGNMENT_BYTES;
+ }
+ $dataMinStartOffset =
+ $offset +
+ ZipEntry::LOCAL_FILE_HEADER_MIN_LEN +
+ $extraLength +
+ $nameLength +
+ ApkAlignmentExtraField::ALIGNMENT_ZIP_EXTRA_MIN_SIZE_BYTES;
+
+ $padding =
+ ($dataAlignmentMultiple - ($dataMinStartOffset % $dataAlignmentMultiple))
+ % $dataAlignmentMultiple;
+
+ $alignExtra = new ApkAlignmentExtraField();
+ $alignExtra->setMultiple($dataAlignmentMultiple);
+ $alignExtra->setPadding($padding);
+
+ $extraFieldsCollection = clone $entry->getExtraFieldsCollection();
+ $extraFieldsCollection->add($alignExtra);
+
+ $extra = ExtraFieldsFactory::createSerializedData($extraFieldsCollection);
+ $extraLength = strlen($extra);
+ }
+
+ $size = $nameLength + $extraLength;
+ if (0xffff < $size) {
+ throw new ZipException(
+ $entry->getName() . " (the total size of " . $size .
+ " bytes for the name, extra fields and comment " .
+ "exceeds the maximum size of " . 0xffff . " bytes)"
+ );
+ }
+
+ $dd = $entry->isDataDescriptorRequired();
+ fwrite(
+ $this->out,
+ pack(
+ 'VvvvVVVVvv',
+ // local file header signature 4 bytes (0x04034b50)
+ ZipEntry::LOCAL_FILE_HEADER_SIG,
+ // version needed to extract 2 bytes
+ $entry->getVersionNeededToExtract(),
+ // general purpose bit flag 2 bytes
+ $entry->getGeneralPurposeBitFlags(),
+ // compression method 2 bytes
+ $entry->getMethod(),
+ // last mod file time 2 bytes
+ // last mod file date 2 bytes
+ $entry->getDosTime(),
+ // crc-32 4 bytes
+ $dd ? 0 : $entry->getCrc(),
+ // compressed size 4 bytes
+ $dd ? 0 : $entry->getCompressedSize(),
+ // uncompressed size 4 bytes
+ $dd ? 0 : $entry->getSize(),
+ // file name length 2 bytes
+ $nameLength,
+ // extra field length 2 bytes
+ $extraLength
+ )
+ );
+ if ($nameLength > 0) {
+ fwrite($this->out, $entry->getName());
+ }
+ if ($extraLength > 0) {
+ fwrite($this->out, $extra);
+ }
+
+ if ($entry instanceof ZipChangesEntry && !$entry->isChangedContent()) {
+ $entry->getSourceEntry()->getInputStream()->copyEntryData($entry->getSourceEntry(), $this);
+ } elseif (null !== $entryContent) {
+ fwrite($this->out, $entryContent);
+ }
+
+ assert(ZipEntry::UNKNOWN !== $entry->getCrc());
+ assert(ZipEntry::UNKNOWN !== $entry->getSize());
+ if ($entry->getGeneralPurposeBitFlag(ZipEntry::GPBF_DATA_DESCRIPTOR)) {
+ // data descriptor signature 4 bytes (0x08074b50)
+ // crc-32 4 bytes
+ fwrite($this->out, pack('VV', ZipEntry::DATA_DESCRIPTOR_SIG, $entry->getCrc()));
+ // compressed size 4 or 8 bytes
+ // uncompressed size 4 or 8 bytes
+ if ($entry->isZip64ExtensionsRequired()) {
+ fwrite($this->out, PackUtil::packLongLE($compressedSize));
+ fwrite($this->out, PackUtil::packLongLE($entry->getSize()));
+ } else {
+ fwrite($this->out, pack('VV', $entry->getCompressedSize(), $entry->getSize()));
+ }
+ } elseif ($entry->getCompressedSize() != $compressedSize) {
+ throw new ZipException(
+ $entry->getName() . " (expected compressed entry size of "
+ . $entry->getCompressedSize() . " bytes, " .
+ "but is actually " . $compressedSize . " bytes)"
+ );
+ }
+ }
+
+ /**
+ * @param ZipEntry $entry
+ * @return null|string
+ * @throws ZipException
+ */
+ protected function entryCommitChangesAndReturnContent(ZipEntry $entry)
+ {
+ if (ZipEntry::UNKNOWN === $entry->getPlatform()) {
+ $entry->setPlatform(ZipEntry::PLATFORM_UNIX);
+ }
+ if (ZipEntry::UNKNOWN === $entry->getTime()) {
+ $entry->setTime(time());
+ }
+ $method = $entry->getMethod();
+
+ $encrypted = $entry->isEncrypted();
+ // See appendix D of PKWARE's ZIP File Format Specification.
+ $utf8 = true;
+
+ if ($encrypted && null === $entry->getPassword()) {
+ throw new ZipException("Can not password from entry " . $entry->getName());
+ }
+
+ // Compose General Purpose Bit Flag.
+ $general = ($encrypted ? ZipEntry::GPBF_ENCRYPTED : 0)
+ | ($entry->isDataDescriptorRequired() ? ZipEntry::GPBF_DATA_DESCRIPTOR : 0)
+ | ($utf8 ? ZipEntry::GPBF_UTF8 : 0);
+
+ $entryContent = null;
+ $extraFieldsCollection = $entry->getExtraFieldsCollection();
+ if (!($entry instanceof ZipChangesEntry && !$entry->isChangedContent())) {
+ $entryContent = $entry->getEntryContent();
+
+ if ($entryContent !== null) {
+ $entry->setSize(strlen($entryContent));
+ $entry->setCrc(crc32($entryContent));
+
+ if ($encrypted && ZipEntry::METHOD_WINZIP_AES === $method) {
+ /**
+ * @var WinZipAesEntryExtraField $field
+ */
+ $field = $extraFieldsCollection->get(WinZipAesEntryExtraField::getHeaderId());
+ if (null !== $field) {
+ $method = $field->getMethod();
+ }
+ }
+
+ switch ($method) {
+ case ZipFileInterface::METHOD_STORED:
+ break;
+
+ case ZipFileInterface::METHOD_DEFLATED:
+ $entryContent = gzdeflate($entryContent, $entry->getCompressionLevel());
+ break;
+
+ case ZipFileInterface::METHOD_BZIP2:
+ $compressionLevel = $entry->getCompressionLevel() === ZipFileInterface::LEVEL_DEFAULT_COMPRESSION ?
+ ZipEntry::LEVEL_DEFAULT_BZIP2_COMPRESSION :
+ $entry->getCompressionLevel();
+ $entryContent = bzcompress($entryContent, $compressionLevel);
+ if (is_int($entryContent)) {
+ throw new ZipException('Error bzip2 compress. Error code: ' . $entryContent);
+ }
+ break;
+
+ case ZipEntry::UNKNOWN:
+ $entryContent = $this->determineBestCompressionMethod($entry, $entryContent);
+ $method = $entry->getMethod();
+ break;
+
+ default:
+ throw new ZipException($entry->getName() . " (unsupported compression method " . $method . ")");
+ }
+
+ if (ZipFileInterface::METHOD_DEFLATED === $method) {
+ $bit1 = false;
+ $bit2 = false;
+ switch ($entry->getCompressionLevel()) {
+ case ZipFileInterface::LEVEL_BEST_COMPRESSION:
+ $bit1 = true;
+ break;
+
+ case ZipFileInterface::LEVEL_FAST:
+ $bit2 = true;
+ break;
+
+ case ZipFileInterface::LEVEL_SUPER_FAST:
+ $bit1 = true;
+ $bit2 = true;
+ break;
+ }
+
+ $general |= ($bit1 ? ZipEntry::GPBF_COMPRESSION_FLAG1 : 0);
+ $general |= ($bit2 ? ZipEntry::GPBF_COMPRESSION_FLAG2 : 0);
+ }
+
+ if ($encrypted) {
+ if (in_array($entry->getEncryptionMethod(), [
+ ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128,
+ ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192,
+ ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256,
+ ], true)) {
+ $keyStrength = WinZipAesEntryExtraField::getKeyStrangeFromEncryptionMethod($entry->getEncryptionMethod()); // size bits
+ $field = ExtraFieldsFactory::createWinZipAesEntryExtra();
+ $field->setKeyStrength($keyStrength);
+ $field->setMethod($method);
+ $size = $entry->getSize();
+ if (20 <= $size && ZipFileInterface::METHOD_BZIP2 !== $method) {
+ $field->setVendorVersion(WinZipAesEntryExtraField::VV_AE_1);
+ } else {
+ $field->setVendorVersion(WinZipAesEntryExtraField::VV_AE_2);
+ $entry->setCrc(0);
+ }
+ $extraFieldsCollection->add($field);
+ $entry->setMethod(ZipEntry::METHOD_WINZIP_AES);
+
+ $winZipAesEngine = new WinZipAesEngine($entry);
+ $entryContent = $winZipAesEngine->encrypt($entryContent);
+ } elseif ($entry->getEncryptionMethod() === ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL) {
+ $zipCryptoEngine = new TraditionalPkwareEncryptionEngine($entry);
+ $entryContent = $zipCryptoEngine->encrypt($entryContent);
+ }
+ }
+
+ $compressedSize = strlen($entryContent);
+ $entry->setCompressedSize($compressedSize);
+ }
+ }
+
+ // Commit changes.
+ $entry->setGeneralPurposeBitFlags($general);
+
+ if ($entry->isZip64ExtensionsRequired()) {
+ $extraFieldsCollection->add(ExtraFieldsFactory::createZip64Extra($entry));
+ } elseif ($extraFieldsCollection->has(Zip64ExtraField::getHeaderId())) {
+ $extraFieldsCollection->remove(Zip64ExtraField::getHeaderId());
+ }
+ return $entryContent;
+ }
+
+ /**
+ * @param ZipEntry $entry
+ * @param string $content
+ * @return string
+ * @throws ZipException
+ */
+ protected function determineBestCompressionMethod(ZipEntry $entry, $content)
+ {
+ if (null !== $content) {
+ $entryContent = gzdeflate($content, $entry->getCompressionLevel());
+ if (strlen($entryContent) < strlen($content)) {
+ $entry->setMethod(ZipFileInterface::METHOD_DEFLATED);
+ return $entryContent;
+ }
+ $entry->setMethod(ZipFileInterface::METHOD_STORED);
+ }
+ return $content;
+ }
+
+ /**
+ * Writes a Central File Header record.
+ *
+ * @param OutputOffsetEntry $outEntry
+ * @throws RuntimeException
+ * @internal param OutPosEntry $entry
+ */
+ protected function writeCentralDirectoryHeader(OutputOffsetEntry $outEntry)
+ {
+ $entry = $outEntry->getEntry();
+ $compressedSize = $entry->getCompressedSize();
+ $size = $entry->getSize();
+ // This test MUST NOT include the CRC-32 because VV_AE_2 sets it to
+ // UNKNOWN!
+ if (ZipEntry::UNKNOWN === ($compressedSize | $size)) {
+ throw new RuntimeException("invalid entry");
+ }
+ $extra = $entry->getExtra();
+ $extraSize = strlen($extra);
+
+ $commentLength = strlen($entry->getComment());
+ fwrite(
+ $this->out,
+ pack(
+ 'VvvvvVVVVvvvvvVV',
+ // central file header signature 4 bytes (0x02014b50)
+ self::CENTRAL_FILE_HEADER_SIG,
+ // version made by 2 bytes
+ ($entry->getPlatform() << 8) | 63,
+ // version needed to extract 2 bytes
+ $entry->getVersionNeededToExtract(),
+ // general purpose bit flag 2 bytes
+ $entry->getGeneralPurposeBitFlags(),
+ // compression method 2 bytes
+ $entry->getMethod(),
+ // last mod file datetime 4 bytes
+ $entry->getDosTime(),
+ // crc-32 4 bytes
+ $entry->getCrc(),
+ // compressed size 4 bytes
+ $entry->getCompressedSize(),
+ // uncompressed size 4 bytes
+ $entry->getSize(),
+ // file name length 2 bytes
+ strlen($entry->getName()),
+ // extra field length 2 bytes
+ $extraSize,
+ // file comment length 2 bytes
+ $commentLength,
+ // disk number start 2 bytes
+ 0,
+ // internal file attributes 2 bytes
+ 0,
+ // external file attributes 4 bytes
+ $entry->getExternalAttributes(),
+ // relative offset of local header 4 bytes
+ $outEntry->getOffset()
+ )
+ );
+ // file name (variable size)
+ fwrite($this->out, $entry->getName());
+ if (0 < $extraSize) {
+ // extra field (variable size)
+ fwrite($this->out, $extra);
+ }
+ if (0 < $commentLength) {
+ // file comment (variable size)
+ fwrite($this->out, $entry->getComment());
+ }
+ }
+
+ protected function writeEndOfCentralDirectoryRecord($centralDirectoryOffset)
+ {
+ $centralDirectoryEntriesCount = count($this->zipModel);
+ $position = ftell($this->out);
+ $centralDirectorySize = $position - $centralDirectoryOffset;
+ $centralDirectoryEntriesZip64 = $centralDirectoryEntriesCount > 0xffff;
+ $centralDirectorySizeZip64 = $centralDirectorySize > 0xffffffff;
+ $centralDirectoryOffsetZip64 = $centralDirectoryOffset > 0xffffffff;
+ $centralDirectoryEntries16 = $centralDirectoryEntriesZip64 ? 0xffff : (int)$centralDirectoryEntriesCount;
+ $centralDirectorySize32 = $centralDirectorySizeZip64 ? 0xffffffff : $centralDirectorySize;
+ $centralDirectoryOffset32 = $centralDirectoryOffsetZip64 ? 0xffffffff : $centralDirectoryOffset;
+ $zip64 // ZIP64 extensions?
+ = $centralDirectoryEntriesZip64
+ || $centralDirectorySizeZip64
+ || $centralDirectoryOffsetZip64;
+ if ($zip64) {
+ // [zip64 end of central directory record]
+ // relative offset of the zip64 end of central directory record
+ $zip64EndOfCentralDirectoryOffset = $position;
+ // zip64 end of central dir
+ // signature 4 bytes (0x06064b50)
+ fwrite($this->out, pack('V', EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIG));
+ // size of zip64 end of central
+ // directory record 8 bytes
+ fwrite($this->out, PackUtil::packLongLE(EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_MIN_LEN - 12));
+ // version made by 2 bytes
+ // version needed to extract 2 bytes
+ // due to potential use of BZIP2 compression
+ // number of this disk 4 bytes
+ // number of the disk with the
+ // start of the central directory 4 bytes
+ fwrite($this->out, pack('vvVV', 63, 46, 0, 0));
+ // total number of entries in the
+ // central directory on this disk 8 bytes
+ fwrite($this->out, PackUtil::packLongLE($centralDirectoryEntriesCount));
+ // total number of entries in the
+ // central directory 8 bytes
+ fwrite($this->out, PackUtil::packLongLE($centralDirectoryEntriesCount));
+ // size of the central directory 8 bytes
+ fwrite($this->out, PackUtil::packLongLE($centralDirectorySize));
+ // offset of start of central
+ // directory with respect to
+ // the starting disk number 8 bytes
+ fwrite($this->out, PackUtil::packLongLE($centralDirectoryOffset));
+ // zip64 extensible data sector (variable size)
+
+ // [zip64 end of central directory locator]
+ // signature 4 bytes (0x07064b50)
+ // number of the disk with the
+ // start of the zip64 end of
+ // central directory 4 bytes
+ fwrite($this->out, pack('VV', EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG, 0));
+ // relative offset of the zip64
+ // end of central directory record 8 bytes
+ fwrite($this->out, PackUtil::packLongLE($zip64EndOfCentralDirectoryOffset));
+ // total number of disks 4 bytes
+ fwrite($this->out, pack('V', 1));
+ }
+ $comment = $this->zipModel->getArchiveComment();
+ $commentLength = strlen($comment);
+ fwrite(
+ $this->out,
+ pack(
+ 'VvvvvVVv',
+ // end of central dir signature 4 bytes (0x06054b50)
+ EndOfCentralDirectory::END_OF_CENTRAL_DIRECTORY_RECORD_SIG,
+ // number of this disk 2 bytes
+ 0,
+ // number of the disk with the
+ // start of the central directory 2 bytes
+ 0,
+ // total number of entries in the
+ // central directory on this disk 2 bytes
+ $centralDirectoryEntries16,
+ // total number of entries in
+ // the central directory 2 bytes
+ $centralDirectoryEntries16,
+ // size of the central directory 4 bytes
+ $centralDirectorySize32,
+ // offset of start of central
+ // directory with respect to
+ // the starting disk number 4 bytes
+ $centralDirectoryOffset32,
+ // .ZIP file comment length 2 bytes
+ $commentLength
+ )
+ );
+ if ($commentLength > 0) {
+ // .ZIP file comment (variable size)
+ fwrite($this->out, $comment);
+ }
+ }
+
+ /**
+ * @return resource
+ */
+ public function getStream()
+ {
+ return $this->out;
+ }
+}
diff --git a/vendor/nelexa/zip/src/PhpZip/Stream/ZipOutputStreamInterface.php b/vendor/nelexa/zip/src/PhpZip/Stream/ZipOutputStreamInterface.php
new file mode 100644
index 0000000..57c397e
--- /dev/null
+++ b/vendor/nelexa/zip/src/PhpZip/Stream/ZipOutputStreamInterface.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace PhpZip\Stream;
+
+use PhpZip\Model\ZipEntry;
+
+/**
+ * Write zip file
+ *
+ * @author Ne-Lexa alexey@nelexa.ru
+ * @license MIT
+ */
+interface ZipOutputStreamInterface
+{
+ /** Central File Header signature. */
+ const CENTRAL_FILE_HEADER_SIG = 0x02014B50;
+
+ public function writeZip();
+
+ /**
+ * @param ZipEntry $entry
+ */
+ public function writeEntry(ZipEntry $entry);
+
+ /**
+ * @return resource
+ */
+ public function getStream();
+}