Merge branch 'master_MDL-76923' of https://github.com/mattporritt/moodle

This commit is contained in:
Sara Arjona 2023-03-16 16:27:55 +01:00
commit 6ebfc73e55
18 changed files with 301 additions and 310 deletions

View File

@ -584,7 +584,7 @@ All rights reserved.</copyright>
<location>zipstream</location>
<name>ZipStream-PHP</name>
<description>PHP ZIP Streaming Library</description>
<version>2.2.0</version>
<version>2.4.0</version>
<license>MIT</license>
<repository>https://github.com/maennchen/ZipStream-PHP</repository>
<copyrights>

View File

@ -6,3 +6,9 @@ Instructions to import ZipStream into Moodle:
3/ Ensure any dependencies are also imported (eg psr/http-message and myclabs/php-enum).
The dependencies will be listed in the "require" section of the library's composer.json file
Local changes:
* 2023/03/03 - Version 3.0.0 of the ZipStream library uses "readonly", "enum" and "First-class Callable Syntax"
properties that are only supported by PHP 8.1 and above.
As Moodle 4.2 only requires PHP 8.0 version 2.4.0 (released 9/12/2022) has been used instead.
When Moodle requires PHP 8.1 version 3.0.0 can be used.

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace ZipStream;
@ -22,22 +23,6 @@ class Bigint
$this->fillBytes($value, 0, 8);
}
/**
* Fill the bytes field with int
*
* @param int $value
* @param int $start
* @param int $count
* @return void
*/
protected function fillBytes(int $value, int $start, int $count): void
{
for ($i = 0; $i < $count; $i++) {
$this->bytes[$start + $i] = $i >= PHP_INT_SIZE ? 0 : $value & 0xFF;
$value >>= 8;
}
}
/**
* Get an instance
*
@ -58,7 +43,7 @@ class Bigint
*/
public static function fromLowHigh(int $low, int $high): self
{
$bigint = new Bigint();
$bigint = new self();
$bigint->fillBytes($low, 0, 4);
$bigint->fillBytes($high, 4, 4);
return $bigint;
@ -150,7 +135,7 @@ class Bigint
* @param Bigint $other
* @return Bigint
*/
public function add(Bigint $other): Bigint
public function add(self $other): self
{
$result = clone $this;
$overflow = false;
@ -166,8 +151,24 @@ class Bigint
}
}
if ($overflow) {
throw new OverflowException;
throw new OverflowException();
}
return $result;
}
/**
* Fill the bytes field with int
*
* @param int $value
* @param int $start
* @param int $count
* @return void
*/
protected function fillBytes(int $value, int $start, int $count): void
{
for ($i = 0; $i < $count; $i++) {
$this->bytes[$start + $i] = $i >= PHP_INT_SIZE ? 0 : $value & 0xFF;
$value >>= 8;
}
}
}

View File

@ -1,70 +1,27 @@
<?php
declare(strict_types=1);
namespace ZipStream;
/**
* @deprecated
*/
class DeflateStream extends Stream
{
protected $filter;
/**
* @var Option\File
*/
protected $options;
/**
* Rewind stream
*
* @return void
*/
public function rewind(): void
public function __construct($stream)
{
// deflate filter needs to be removed before rewind
if ($this->filter) {
$this->removeDeflateFilter();
$this->seek(0);
$this->addDeflateFilter($this->options);
} else {
rewind($this->stream);
}
parent::__construct($stream);
trigger_error('Class ' . __CLASS__ . ' is deprecated, delation will be handled internally instead', E_USER_DEPRECATED);
}
/**
* Remove the deflate filter
*
* @return void
*/
public function removeDeflateFilter(): void
{
if (!$this->filter) {
return;
}
stream_filter_remove($this->filter);
$this->filter = null;
trigger_error('Method ' . __METHOD__ . ' is deprecated', E_USER_DEPRECATED);
}
/**
* Add a deflate filter
*
* @param Option\File $options
* @return void
*/
public function addDeflateFilter(Option\File $options): void
{
$this->options = $options;
// parameter 4 for stream_filter_append expects array
// so we convert the option object in an array
$optionsArr = [
'comment' => $options->getComment(),
'method' => $options->getMethod(),
'deflateLevel' => $options->getDeflateLevel(),
'time' => $options->getTime()
];
$this->filter = stream_filter_append(
$this->stream,
'zlib.deflate',
STREAM_FILTER_READ,
$optionsArr
);
trigger_error('Method ' . __METHOD__ . ' is deprecated', E_USER_DEPRECATED);
}
}

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace ZipStream;

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace ZipStream\Exception;

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace ZipStream\Exception;

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace ZipStream\Exception;

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace ZipStream\Exception;

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace ZipStream\Exception;

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace ZipStream\Exception;

View File

@ -1,11 +1,11 @@
<?php
declare(strict_types=1);
namespace ZipStream;
use HashContext;
use Psr\Http\Message\StreamInterface;
use RuntimeException;
use ZipStream\Exception\EncodingException;
use ZipStream\Exception\FileNotFoundException;
use ZipStream\Exception\FileNotReadableException;
use ZipStream\Exception\OverflowException;
@ -15,13 +15,15 @@ use ZipStream\Option\Version;
class File
{
const HASH_ALGORITHM = 'crc32b';
public const HASH_ALGORITHM = 'crc32b';
const BIT_ZERO_HEADER = 0x0008;
const BIT_EFS_UTF8 = 0x0800;
public const BIT_ZERO_HEADER = 0x0008;
const COMPUTE = 1;
const SEND = 2;
public const BIT_EFS_UTF8 = 0x0800;
public const COMPUTE = 1;
public const SEND = 2;
private const CHUNKED_READ_BLOCK_SIZE = 1048576;
@ -39,6 +41,7 @@ class File
* @var Bigint
*/
public $len;
/**
* @var Bigint
*/
@ -78,7 +81,7 @@ class File
private $deflate;
/**
* @var \HashContext
* @var HashContext
*/
private $hash;
@ -117,7 +120,7 @@ class File
} else {
$this->method = $this->zip->opt->getLargeFileMethod();
$stream = new DeflateStream(fopen($path, 'rb'));
$stream = new Stream(fopen($path, 'rb'));
$this->processStream($stream);
$stream->close();
}
@ -162,21 +165,17 @@ class File
// Sets Bit 11: Language encoding flag (EFS). If this bit is set,
// the filename and comment fields for this file
// MUST be encoded using UTF-8. (see APPENDIX D)
if (!mb_check_encoding($name, 'UTF-8') ||
!mb_check_encoding($comment, 'UTF-8')) {
throw new EncodingException(
'File name and comment should use UTF-8 ' .
'if one of them does not fit into ASCII range.'
);
if (mb_check_encoding($name, 'UTF-8') &&
mb_check_encoding($comment, 'UTF-8')) {
$this->bits |= self::BIT_EFS_UTF8;
}
$this->bits |= self::BIT_EFS_UTF8;
}
if ($this->method->equals(Method::DEFLATE())) {
$this->version = Version::DEFLATE();
}
$force = (boolean)($this->bits & self::BIT_ZERO_HEADER) &&
$force = (bool)($this->bits & self::BIT_ZERO_HEADER) &&
$this->zip->opt->isEnableZip64();
$footer = $this->buildZip64ExtraBlock($force);
@ -228,6 +227,97 @@ class File
return str_replace(['\\', ':', '*', '?', '"', '<', '>', '|'], '_', $filename);
}
/**
* Create and send data descriptor footer for this file.
*
* @return void
*/
public function addFileFooter(): void
{
if ($this->bits & self::BIT_ZERO_HEADER) {
// compressed and uncompressed size
$sizeFormat = 'V';
if ($this->zip->opt->isEnableZip64()) {
$sizeFormat = 'P';
}
$fields = [
['V', ZipStream::DATA_DESCRIPTOR_SIGNATURE],
['V', $this->crc], // CRC32
[$sizeFormat, $this->zlen], // Length of compressed data
[$sizeFormat, $this->len], // Length of original data
];
$footer = ZipStream::packFields($fields);
$this->zip->send($footer);
} else {
$footer = '';
}
$this->totalLength = $this->hlen->add($this->zlen)->add(Bigint::init(strlen($footer)));
$this->zip->addToCdr($this);
}
public function processStream(StreamInterface $stream): void
{
$this->zlen = new Bigint();
$this->len = new Bigint();
if ($this->zip->opt->isZeroHeader()) {
$this->processStreamWithZeroHeader($stream);
} else {
$this->processStreamWithComputedHeader($stream);
}
}
/**
* Send CDR record for specified file.
*
* @return string
*/
public function getCdrFile(): string
{
$name = static::filterFilename($this->name);
// get attributes
$comment = $this->opt->getComment();
// get dos timestamp
$time = static::dosTime($this->opt->getTime()->getTimestamp());
$footer = $this->buildZip64ExtraBlock();
$fields = [
['V', ZipStream::CDR_FILE_SIGNATURE], // Central file header signature
['v', ZipStream::ZIP_VERSION_MADE_BY], // Made by version
['v', $this->version->getValue()], // Extract by version
['v', $this->bits], // General purpose bit flags - data descriptor flag set
['v', $this->method->getValue()], // Compression method
['V', $time], // Timestamp (DOS Format)
['V', $this->crc], // CRC32
['V', $this->zlen->getLowFF()], // Compressed Data Length
['V', $this->len->getLowFF()], // Original Data Length
['v', strlen($name)], // Length of filename
['v', strlen($footer)], // Extra data len (see above)
['v', strlen($comment)], // Length of comment
['v', 0], // Disk number
['v', 0], // Internal File Attributes
['V', 32], // External File Attributes
['V', $this->ofs->getLowFF()], // Relative offset of local header
];
// pack fields, then append name and comment
$header = ZipStream::packFields($fields);
return $header . $name . $footer . $comment;
}
/**
* @return Bigint
*/
public function getTotalLength(): Bigint
{
return $this->totalLength;
}
/**
* Convert a UNIX timestamp to a DOS timestamp.
*
@ -241,14 +331,14 @@ class File
// set lower-bound on dates
if ($d['year'] < 1980) {
$d = array(
$d = [
'year' => 1980,
'mon' => 1,
'mday' => 1,
'hours' => 0,
'minutes' => 0,
'seconds' => 0
);
'seconds' => 0,
];
}
// remove extra years from 1980
@ -266,7 +356,6 @@ class File
protected function buildZip64ExtraBlock(bool $force = false): string
{
$fields = [];
if ($this->len->isOver32($force)) {
$fields[] = ['P', $this->len]; // Length of original data
@ -303,49 +392,6 @@ class File
return ZipStream::packFields($fields);
}
/**
* Create and send data descriptor footer for this file.
*
* @return void
*/
public function addFileFooter(): void
{
if ($this->bits & self::BIT_ZERO_HEADER) {
// compressed and uncompressed size
$sizeFormat = 'V';
if ($this->zip->opt->isEnableZip64()) {
$sizeFormat = 'P';
}
$fields = [
['V', ZipStream::DATA_DESCRIPTOR_SIGNATURE],
['V', $this->crc], // CRC32
[$sizeFormat, $this->zlen], // Length of compressed data
[$sizeFormat, $this->len], // Length of original data
];
$footer = ZipStream::packFields($fields);
$this->zip->send($footer);
} else {
$footer = '';
}
$this->totalLength = $this->hlen->add($this->zlen)->add(Bigint::init(strlen($footer)));
$this->zip->addToCdr($this);
}
public function processStream(StreamInterface $stream): void
{
$this->zlen = new Bigint();
$this->len = new Bigint();
if ($this->zip->opt->isZeroHeader()) {
$this->processStreamWithZeroHeader($stream);
} else {
$this->processStreamWithComputedHeader($stream);
}
}
protected function processStreamWithZeroHeader(StreamInterface $stream): void
{
$this->bits |= self::BIT_ZERO_HEADER;
@ -363,7 +409,7 @@ class File
$data = $stream->read(self::CHUNKED_READ_BLOCK_SIZE);
$total += strlen($data);
if ($size > 0 && $total > $size) {
$data = substr($data, 0 , strlen($data)-($total - $size));
$data = substr($data, 0, strlen($data)-($total - $size));
}
$this->deflateData($stream, $data, $options);
if ($options & self::SEND) {
@ -417,71 +463,8 @@ class File
$this->readStream($stream, self::COMPUTE);
$stream->rewind();
// incremental compression with deflate_add
// makes this second read unnecessary
// but it is only available from PHP 7.0
if (!$this->deflate && $stream instanceof DeflateStream && $this->method->equals(Method::DEFLATE())) {
$stream->addDeflateFilter($this->opt);
$this->zlen = new Bigint();
while (!$stream->eof()) {
$data = $stream->read(self::CHUNKED_READ_BLOCK_SIZE);
$this->zlen = $this->zlen->add(Bigint::init(strlen($data)));
}
$stream->rewind();
}
$this->addFileHeader();
$this->readStream($stream, self::SEND);
$this->addFileFooter();
}
/**
* Send CDR record for specified file.
*
* @return string
*/
public function getCdrFile(): string
{
$name = static::filterFilename($this->name);
// get attributes
$comment = $this->opt->getComment();
// get dos timestamp
$time = static::dosTime($this->opt->getTime()->getTimestamp());
$footer = $this->buildZip64ExtraBlock();
$fields = [
['V', ZipStream::CDR_FILE_SIGNATURE], // Central file header signature
['v', ZipStream::ZIP_VERSION_MADE_BY], // Made by version
['v', $this->version->getValue()], // Extract by version
['v', $this->bits], // General purpose bit flags - data descriptor flag set
['v', $this->method->getValue()], // Compression method
['V', $time], // Timestamp (DOS Format)
['V', $this->crc], // CRC32
['V', $this->zlen->getLowFF()], // Compressed Data Length
['V', $this->len->getLowFF()], // Original Data Length
['v', strlen($name)], // Length of filename
['v', strlen($footer)], // Extra data len (see above)
['v', strlen($comment)], // Length of comment
['v', 0], // Disk number
['v', 0], // Internal File Attributes
['V', 32], // External File Attributes
['V', $this->ofs->getLowFF()] // Relative offset of local header
];
// pack fields, then append name and comment
$header = ZipStream::packFields($fields);
return $header . $name . $footer . $comment;
}
/**
* @return Bigint
*/
public function getTotalLength(): Bigint
{
return $this->totalLength;
}
}

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace ZipStream\Option;
@ -7,11 +8,13 @@ use Psr\Http\Message\StreamInterface;
final class Archive
{
const DEFAULT_DEFLATE_LEVEL = 6;
public const DEFAULT_DEFLATE_LEVEL = 6;
/**
* @var string
*/
private $comment = '';
/**
* Size, in bytes, of the largest file to try
* and load into memory (used by
@ -22,6 +25,7 @@ final class Archive
* @var int
*/
private $largeFileSize = 20 * 1024 * 1024;
/**
* How to handle large files. Legal values are
* Method::STORE() (the default), or
@ -34,6 +38,7 @@ final class Archive
* @var Method
*/
private $largeFileMethod;
/**
* Boolean indicating whether or not to send
* the HTTP headers for this file.
@ -41,12 +46,14 @@ final class Archive
* @var bool
*/
private $sendHttpHeaders = false;
/**
* The method called to send headers
*
* @var Callable
*/
private $httpHeaderCallback = 'header';
/**
* Enable Zip64 extension, supporting very large
* archives (any size > 4 GB or file count > 64k)
@ -54,6 +61,7 @@ final class Archive
* @var bool
*/
private $enableZip64 = true;
/**
* Enable streaming files with single read where
* general purpose bit 3 indicates local file header
@ -64,6 +72,7 @@ final class Archive
* @var bool
*/
private $zeroHeader = false;
/**
* Enable reading file stat for determining file size.
* When a 32-bit system reads file size that is
@ -77,11 +86,13 @@ final class Archive
* @var bool
*/
private $statFiles = true;
/**
* Enable flush after every write to output stream.
* @var bool
*/
private $flushOutput = false;
/**
* HTTP Content-Disposition. Defaults to
* 'attachment', where
@ -93,6 +104,7 @@ final class Archive
* @var string
*/
private $contentDisposition = 'attachment';
/**
* Note that this does nothing if you are
* not sending HTTP headers.
@ -100,6 +112,7 @@ final class Archive
* @var string
*/
private $contentType = 'application/x-zip';
/**
* @var int
*/
@ -159,12 +172,12 @@ final class Archive
$this->sendHttpHeaders = $sendHttpHeaders;
}
public function getHttpHeaderCallback(): Callable
public function getHttpHeaderCallback(): callable
{
return $this->httpHeaderCallback;
}
public function setHttpHeaderCallback(Callable $httpHeaderCallback): void
public function setHttpHeaderCallback(callable $httpHeaderCallback): void
{
$this->httpHeaderCallback = $httpHeaderCallback;
}

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace ZipStream\Option;
@ -12,18 +13,22 @@ final class File
* @var string
*/
private $comment = '';
/**
* @var Method
*/
private $method;
/**
* @var int
*/
private $deflateLevel;
/**
* @var DateTimeInterface
*/
private $time;
/**
* @var int
*/

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace ZipStream\Option;
@ -11,9 +12,12 @@ use MyCLabs\Enum\Enum;
* @method static STORE(): Method
* @method static DEFLATE(): Method
* @psalm-immutable
* @psalm-template int
* @extends Enum<int>
*/
class Method extends Enum
{
const STORE = 0x00;
const DEFLATE = 0x08;
public const STORE = 0x00;
public const DEFLATE = 0x08;
}

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace ZipStream\Option;
@ -13,10 +14,14 @@ use MyCLabs\Enum\Enum;
* @method static DEFLATE(): Version
* @method static ZIP64(): Version
* @psalm-immutable
* @psalm-template int
* @extends Enum<int>
*/
class Version extends Enum
{
const STORE = 0x000A; // 1.00
const DEFLATE = 0x0014; // 2.00
const ZIP64 = 0x002D; // 4.50
public const STORE = 0x000A; // 1.00
public const DEFLATE = 0x0014; // 2.00
public const ZIP64 = 0x002D; // 4.50
}

View File

@ -1,8 +1,11 @@
<?php
declare(strict_types=1);
namespace ZipStream;
use function mb_strlen;
use Psr\Http\Message\StreamInterface;
use RuntimeException;
@ -22,6 +25,29 @@ class Stream implements StreamInterface
$this->stream = $stream;
}
/**
* 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(): string
{
try {
$this->seek(0);
} catch (RuntimeException $e) {
}
return (string) stream_get_contents($this->stream);
}
/**
* Closes the stream and any underlying resources.
*
@ -49,28 +75,6 @@ class Stream implements StreamInterface
return $result;
}
/**
* 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(): string
{
try {
$this->seek(0);
} catch (RuntimeException $e) {}
return (string) stream_get_contents($this->stream);
}
/**
* Seek to a position in the stream.
*
@ -86,10 +90,10 @@ class Stream implements StreamInterface
public function seek($offset, $whence = SEEK_SET): void
{
if (!$this->isSeekable()) {
throw new RuntimeException;
throw new RuntimeException();
}
if (fseek($this->stream, $offset, $whence) !== 0) {
throw new RuntimeException;
throw new RuntimeException();
}
}
@ -142,7 +146,7 @@ class Stream implements StreamInterface
{
$position = ftell($this->stream);
if ($position === false) {
throw new RuntimeException;
throw new RuntimeException();
}
return $position;
}
@ -182,12 +186,12 @@ class Stream implements StreamInterface
public function write($string): int
{
if (!$this->isWritable()) {
throw new RuntimeException;
throw new RuntimeException();
}
if (fwrite($this->stream, $string) === false) {
throw new RuntimeException;
throw new RuntimeException();
}
return \mb_strlen($string);
return mb_strlen($string);
}
/**
@ -212,16 +216,16 @@ class Stream implements StreamInterface
* 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.
* @throws RuntimeException if an error occurs.
*/
public function read($length): string
{
if (!$this->isReadable()) {
throw new RuntimeException;
throw new RuntimeException();
}
$result = fread($this->stream, $length);
if ($result === false) {
throw new RuntimeException;
throw new RuntimeException();
}
return $result;
}
@ -244,17 +248,17 @@ class Stream implements StreamInterface
* Returns the remaining contents in a string
*
* @return string
* @throws \RuntimeException if unable to read or an error occurs while
* @throws RuntimeException if unable to read or an error occurs while
* reading.
*/
public function getContents(): string
{
if (!$this->isReadable()) {
throw new RuntimeException;
throw new RuntimeException();
}
$result = stream_get_contents($this->stream);
if ($result === false) {
throw new RuntimeException;
throw new RuntimeException();
}
return $result;
}

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace ZipStream;
@ -80,19 +81,24 @@ class ZipStream
* to prevent file permissions issues upon extract (see #84)
* 0x603 is 00000110 00000011 in binary, so 6 and 3
*/
const ZIP_VERSION_MADE_BY = 0x603;
public const ZIP_VERSION_MADE_BY = 0x603;
/**
* The following signatures end with 0x4b50, which in ASCII is PK,
* The following signatures end with 0x4b50, which in ASCII is PK,
* the initials of the inventor Phil Katz.
* See https://en.wikipedia.org/wiki/Zip_(file_format)#File_headers
*/
const FILE_HEADER_SIGNATURE = 0x04034b50;
const CDR_FILE_SIGNATURE = 0x02014b50;
const CDR_EOF_SIGNATURE = 0x06054b50;
const DATA_DESCRIPTOR_SIGNATURE = 0x08074b50;
const ZIP64_CDR_EOF_SIGNATURE = 0x06064b50;
const ZIP64_CDR_LOCATOR_SIGNATURE = 0x07064b50;
public const FILE_HEADER_SIGNATURE = 0x04034b50;
public const CDR_FILE_SIGNATURE = 0x02014b50;
public const CDR_EOF_SIGNATURE = 0x06054b50;
public const DATA_DESCRIPTOR_SIGNATURE = 0x08074b50;
public const ZIP64_CDR_EOF_SIGNATURE = 0x06064b50;
public const ZIP64_CDR_LOCATOR_SIGNATURE = 0x07064b50;
/**
* Global Options
@ -293,7 +299,7 @@ class ZipStream
$options->defaultTo($this->opt);
$file = new File($this, $name, $options);
$file->processStream(new DeflateStream($stream));
$file->processStream(new Stream($stream));
}
/**
@ -375,34 +381,6 @@ class ZipStream
$this->clear();
}
/**
* Send ZIP64 CDR EOF (Central Directory Record End-of-File) record.
*
* @return void
*/
protected function addCdr64Eof(): void
{
$num_files = count($this->files);
$cdr_length = $this->cdr_ofs;
$cdr_offset = $this->ofs;
$fields = [
['V', static::ZIP64_CDR_EOF_SIGNATURE], // ZIP64 end of central file header signature
['P', 44], // Length of data below this header (length of block - 12) = 44
['v', static::ZIP_VERSION_MADE_BY], // Made by version
['v', Version::ZIP64], // Extract by version
['V', 0x00], // disk number
['V', 0x00], // no of disks
['P', $num_files], // no of entries on disk
['P', $num_files], // no of entries in cdr
['P', $cdr_length], // CDR size
['P', $cdr_offset], // CDR offset
];
$ret = static::packFields($fields);
$this->send($ret);
}
/**
* Create a format string and argument list for pack(), then call
* pack() and return the result.
@ -476,6 +454,62 @@ class ZipStream
}
}
/**
* Is this file larger than large_file_size?
*
* @param string $path
* @return bool
*/
public function isLargeFile(string $path): bool
{
if (!$this->opt->isStatFiles()) {
return false;
}
$stat = stat($path);
return $stat['size'] > $this->opt->getLargeFileSize();
}
/**
* Save file attributes for trailing CDR record.
*
* @param File $file
* @return void
*/
public function addToCdr(File $file): void
{
$file->ofs = $this->ofs;
$this->ofs = $this->ofs->add($file->getTotalLength());
$this->files[] = $file->getCdrFile();
}
/**
* Send ZIP64 CDR EOF (Central Directory Record End-of-File) record.
*
* @return void
*/
protected function addCdr64Eof(): void
{
$num_files = count($this->files);
$cdr_length = $this->cdr_ofs;
$cdr_offset = $this->ofs;
$fields = [
['V', static::ZIP64_CDR_EOF_SIGNATURE], // ZIP64 end of central file header signature
['P', 44], // Length of data below this header (length of block - 12) = 44
['v', static::ZIP_VERSION_MADE_BY], // Made by version
['v', Version::ZIP64], // Extract by version
['V', 0x00], // disk number
['V', 0x00], // no of disks
['P', $num_files], // no of entries on disk
['P', $num_files], // no of entries in cdr
['P', $cdr_length], // CDR size
['P', $cdr_offset], // CDR offset
];
$ret = static::packFields($fields);
$this->send($ret);
}
/**
* Send HTTP headers for this stream.
*
@ -495,13 +529,13 @@ class ZipStream
$disposition .= "; filename*=UTF-8''{$urlencoded}";
}
$headers = array(
$headers = [
'Content-Type' => $this->opt->getContentType(),
'Content-Disposition' => $disposition,
'Pragma' => 'public',
'Cache-Control' => 'public, must-revalidate',
'Content-Transfer-Encoding' => 'binary'
);
'Content-Transfer-Encoding' => 'binary',
];
$call = $this->opt->getHttpHeaderCallback();
foreach ($headers as $key => $val) {
@ -571,32 +605,4 @@ class ZipStream
$this->cdr_ofs = new Bigint();
$this->opt = new ArchiveOptions();
}
/**
* Is this file larger than large_file_size?
*
* @param string $path
* @return bool
*/
public function isLargeFile(string $path): bool
{
if (!$this->opt->isStatFiles()) {
return false;
}
$stat = stat($path);
return $stat['size'] > $this->opt->getLargeFileSize();
}
/**
* Save file attributes for trailing CDR record.
*
* @param File $file
* @return void
*/
public function addToCdr(File $file): void
{
$file->ofs = $this->ofs;
$this->ofs = $this->ofs->add($file->getTotalLength());
$this->files[] = $file->getCdrFile();
}
}