mirror of
https://github.com/moodle/moodle.git
synced 2025-08-04 08:26:37 +02:00
MDL-76923 Libraries: Upgrade ZipStream to 2.4.0
This commit is contained in:
parent
9ee4f8db8b
commit
6a82ef2474
18 changed files with 301 additions and 310 deletions
|
@ -584,7 +584,7 @@ All rights reserved.</copyright>
|
||||||
<location>zipstream</location>
|
<location>zipstream</location>
|
||||||
<name>ZipStream-PHP</name>
|
<name>ZipStream-PHP</name>
|
||||||
<description>PHP ZIP Streaming Library</description>
|
<description>PHP ZIP Streaming Library</description>
|
||||||
<version>2.2.0</version>
|
<version>2.4.0</version>
|
||||||
<license>MIT</license>
|
<license>MIT</license>
|
||||||
<repository>https://github.com/maennchen/ZipStream-PHP</repository>
|
<repository>https://github.com/maennchen/ZipStream-PHP</repository>
|
||||||
<copyrights>
|
<copyrights>
|
||||||
|
|
|
@ -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).
|
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
|
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.
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace ZipStream;
|
namespace ZipStream;
|
||||||
|
@ -22,22 +23,6 @@ class Bigint
|
||||||
$this->fillBytes($value, 0, 8);
|
$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
|
* Get an instance
|
||||||
*
|
*
|
||||||
|
@ -58,7 +43,7 @@ class Bigint
|
||||||
*/
|
*/
|
||||||
public static function fromLowHigh(int $low, int $high): self
|
public static function fromLowHigh(int $low, int $high): self
|
||||||
{
|
{
|
||||||
$bigint = new Bigint();
|
$bigint = new self();
|
||||||
$bigint->fillBytes($low, 0, 4);
|
$bigint->fillBytes($low, 0, 4);
|
||||||
$bigint->fillBytes($high, 4, 4);
|
$bigint->fillBytes($high, 4, 4);
|
||||||
return $bigint;
|
return $bigint;
|
||||||
|
@ -150,7 +135,7 @@ class Bigint
|
||||||
* @param Bigint $other
|
* @param Bigint $other
|
||||||
* @return Bigint
|
* @return Bigint
|
||||||
*/
|
*/
|
||||||
public function add(Bigint $other): Bigint
|
public function add(self $other): self
|
||||||
{
|
{
|
||||||
$result = clone $this;
|
$result = clone $this;
|
||||||
$overflow = false;
|
$overflow = false;
|
||||||
|
@ -166,8 +151,24 @@ class Bigint
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($overflow) {
|
if ($overflow) {
|
||||||
throw new OverflowException;
|
throw new OverflowException();
|
||||||
}
|
}
|
||||||
return $result;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,70 +1,27 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace ZipStream;
|
namespace ZipStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
class DeflateStream extends Stream
|
class DeflateStream extends Stream
|
||||||
{
|
{
|
||||||
protected $filter;
|
public function __construct($stream)
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Option\File
|
|
||||||
*/
|
|
||||||
protected $options;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rewind stream
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function rewind(): void
|
|
||||||
{
|
{
|
||||||
// deflate filter needs to be removed before rewind
|
parent::__construct($stream);
|
||||||
if ($this->filter) {
|
trigger_error('Class ' . __CLASS__ . ' is deprecated, delation will be handled internally instead', E_USER_DEPRECATED);
|
||||||
$this->removeDeflateFilter();
|
|
||||||
$this->seek(0);
|
|
||||||
$this->addDeflateFilter($this->options);
|
|
||||||
} else {
|
|
||||||
rewind($this->stream);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the deflate filter
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function removeDeflateFilter(): void
|
public function removeDeflateFilter(): void
|
||||||
{
|
{
|
||||||
if (!$this->filter) {
|
trigger_error('Method ' . __METHOD__ . ' is deprecated', E_USER_DEPRECATED);
|
||||||
return;
|
|
||||||
}
|
|
||||||
stream_filter_remove($this->filter);
|
|
||||||
$this->filter = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a deflate filter
|
|
||||||
*
|
|
||||||
* @param Option\File $options
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function addDeflateFilter(Option\File $options): void
|
public function addDeflateFilter(Option\File $options): void
|
||||||
{
|
{
|
||||||
$this->options = $options;
|
trigger_error('Method ' . __METHOD__ . ' is deprecated', E_USER_DEPRECATED);
|
||||||
// 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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace ZipStream;
|
namespace ZipStream;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace ZipStream\Exception;
|
namespace ZipStream\Exception;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace ZipStream\Exception;
|
namespace ZipStream\Exception;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace ZipStream\Exception;
|
namespace ZipStream\Exception;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace ZipStream\Exception;
|
namespace ZipStream\Exception;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace ZipStream\Exception;
|
namespace ZipStream\Exception;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace ZipStream\Exception;
|
namespace ZipStream\Exception;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace ZipStream;
|
namespace ZipStream;
|
||||||
|
|
||||||
|
use HashContext;
|
||||||
use Psr\Http\Message\StreamInterface;
|
use Psr\Http\Message\StreamInterface;
|
||||||
use RuntimeException;
|
|
||||||
use ZipStream\Exception\EncodingException;
|
|
||||||
use ZipStream\Exception\FileNotFoundException;
|
use ZipStream\Exception\FileNotFoundException;
|
||||||
use ZipStream\Exception\FileNotReadableException;
|
use ZipStream\Exception\FileNotReadableException;
|
||||||
use ZipStream\Exception\OverflowException;
|
use ZipStream\Exception\OverflowException;
|
||||||
|
@ -15,13 +15,15 @@ use ZipStream\Option\Version;
|
||||||
|
|
||||||
class File
|
class File
|
||||||
{
|
{
|
||||||
const HASH_ALGORITHM = 'crc32b';
|
public const HASH_ALGORITHM = 'crc32b';
|
||||||
|
|
||||||
const BIT_ZERO_HEADER = 0x0008;
|
public const BIT_ZERO_HEADER = 0x0008;
|
||||||
const BIT_EFS_UTF8 = 0x0800;
|
|
||||||
|
|
||||||
const COMPUTE = 1;
|
public const BIT_EFS_UTF8 = 0x0800;
|
||||||
const SEND = 2;
|
|
||||||
|
public const COMPUTE = 1;
|
||||||
|
|
||||||
|
public const SEND = 2;
|
||||||
|
|
||||||
private const CHUNKED_READ_BLOCK_SIZE = 1048576;
|
private const CHUNKED_READ_BLOCK_SIZE = 1048576;
|
||||||
|
|
||||||
|
@ -39,6 +41,7 @@ class File
|
||||||
* @var Bigint
|
* @var Bigint
|
||||||
*/
|
*/
|
||||||
public $len;
|
public $len;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Bigint
|
* @var Bigint
|
||||||
*/
|
*/
|
||||||
|
@ -78,7 +81,7 @@ class File
|
||||||
private $deflate;
|
private $deflate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \HashContext
|
* @var HashContext
|
||||||
*/
|
*/
|
||||||
private $hash;
|
private $hash;
|
||||||
|
|
||||||
|
@ -117,7 +120,7 @@ class File
|
||||||
} else {
|
} else {
|
||||||
$this->method = $this->zip->opt->getLargeFileMethod();
|
$this->method = $this->zip->opt->getLargeFileMethod();
|
||||||
|
|
||||||
$stream = new DeflateStream(fopen($path, 'rb'));
|
$stream = new Stream(fopen($path, 'rb'));
|
||||||
$this->processStream($stream);
|
$this->processStream($stream);
|
||||||
$stream->close();
|
$stream->close();
|
||||||
}
|
}
|
||||||
|
@ -162,21 +165,17 @@ class File
|
||||||
// Sets Bit 11: Language encoding flag (EFS). If this bit is set,
|
// Sets Bit 11: Language encoding flag (EFS). If this bit is set,
|
||||||
// the filename and comment fields for this file
|
// the filename and comment fields for this file
|
||||||
// MUST be encoded using UTF-8. (see APPENDIX D)
|
// MUST be encoded using UTF-8. (see APPENDIX D)
|
||||||
if (!mb_check_encoding($name, 'UTF-8') ||
|
if (mb_check_encoding($name, 'UTF-8') &&
|
||||||
!mb_check_encoding($comment, '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.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$this->bits |= self::BIT_EFS_UTF8;
|
$this->bits |= self::BIT_EFS_UTF8;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->method->equals(Method::DEFLATE())) {
|
if ($this->method->equals(Method::DEFLATE())) {
|
||||||
$this->version = Version::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();
|
$this->zip->opt->isEnableZip64();
|
||||||
|
|
||||||
$footer = $this->buildZip64ExtraBlock($force);
|
$footer = $this->buildZip64ExtraBlock($force);
|
||||||
|
@ -228,6 +227,97 @@ class File
|
||||||
return str_replace(['\\', ':', '*', '?', '"', '<', '>', '|'], '_', $filename);
|
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.
|
* Convert a UNIX timestamp to a DOS timestamp.
|
||||||
*
|
*
|
||||||
|
@ -241,14 +331,14 @@ class File
|
||||||
|
|
||||||
// set lower-bound on dates
|
// set lower-bound on dates
|
||||||
if ($d['year'] < 1980) {
|
if ($d['year'] < 1980) {
|
||||||
$d = array(
|
$d = [
|
||||||
'year' => 1980,
|
'year' => 1980,
|
||||||
'mon' => 1,
|
'mon' => 1,
|
||||||
'mday' => 1,
|
'mday' => 1,
|
||||||
'hours' => 0,
|
'hours' => 0,
|
||||||
'minutes' => 0,
|
'minutes' => 0,
|
||||||
'seconds' => 0
|
'seconds' => 0,
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove extra years from 1980
|
// remove extra years from 1980
|
||||||
|
@ -266,7 +356,6 @@ class File
|
||||||
|
|
||||||
protected function buildZip64ExtraBlock(bool $force = false): string
|
protected function buildZip64ExtraBlock(bool $force = false): string
|
||||||
{
|
{
|
||||||
|
|
||||||
$fields = [];
|
$fields = [];
|
||||||
if ($this->len->isOver32($force)) {
|
if ($this->len->isOver32($force)) {
|
||||||
$fields[] = ['P', $this->len]; // Length of original data
|
$fields[] = ['P', $this->len]; // Length of original data
|
||||||
|
@ -303,49 +392,6 @@ class File
|
||||||
return ZipStream::packFields($fields);
|
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
|
protected function processStreamWithZeroHeader(StreamInterface $stream): void
|
||||||
{
|
{
|
||||||
$this->bits |= self::BIT_ZERO_HEADER;
|
$this->bits |= self::BIT_ZERO_HEADER;
|
||||||
|
@ -417,71 +463,8 @@ class File
|
||||||
$this->readStream($stream, self::COMPUTE);
|
$this->readStream($stream, self::COMPUTE);
|
||||||
$stream->rewind();
|
$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->addFileHeader();
|
||||||
$this->readStream($stream, self::SEND);
|
$this->readStream($stream, self::SEND);
|
||||||
$this->addFileFooter();
|
$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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace ZipStream\Option;
|
namespace ZipStream\Option;
|
||||||
|
@ -7,11 +8,13 @@ use Psr\Http\Message\StreamInterface;
|
||||||
|
|
||||||
final class Archive
|
final class Archive
|
||||||
{
|
{
|
||||||
const DEFAULT_DEFLATE_LEVEL = 6;
|
public const DEFAULT_DEFLATE_LEVEL = 6;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $comment = '';
|
private $comment = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size, in bytes, of the largest file to try
|
* Size, in bytes, of the largest file to try
|
||||||
* and load into memory (used by
|
* and load into memory (used by
|
||||||
|
@ -22,6 +25,7 @@ final class Archive
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
private $largeFileSize = 20 * 1024 * 1024;
|
private $largeFileSize = 20 * 1024 * 1024;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How to handle large files. Legal values are
|
* How to handle large files. Legal values are
|
||||||
* Method::STORE() (the default), or
|
* Method::STORE() (the default), or
|
||||||
|
@ -34,6 +38,7 @@ final class Archive
|
||||||
* @var Method
|
* @var Method
|
||||||
*/
|
*/
|
||||||
private $largeFileMethod;
|
private $largeFileMethod;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Boolean indicating whether or not to send
|
* Boolean indicating whether or not to send
|
||||||
* the HTTP headers for this file.
|
* the HTTP headers for this file.
|
||||||
|
@ -41,12 +46,14 @@ final class Archive
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
private $sendHttpHeaders = false;
|
private $sendHttpHeaders = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The method called to send headers
|
* The method called to send headers
|
||||||
*
|
*
|
||||||
* @var Callable
|
* @var Callable
|
||||||
*/
|
*/
|
||||||
private $httpHeaderCallback = 'header';
|
private $httpHeaderCallback = 'header';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable Zip64 extension, supporting very large
|
* Enable Zip64 extension, supporting very large
|
||||||
* archives (any size > 4 GB or file count > 64k)
|
* archives (any size > 4 GB or file count > 64k)
|
||||||
|
@ -54,6 +61,7 @@ final class Archive
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
private $enableZip64 = true;
|
private $enableZip64 = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable streaming files with single read where
|
* Enable streaming files with single read where
|
||||||
* general purpose bit 3 indicates local file header
|
* general purpose bit 3 indicates local file header
|
||||||
|
@ -64,6 +72,7 @@ final class Archive
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
private $zeroHeader = false;
|
private $zeroHeader = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable reading file stat for determining file size.
|
* Enable reading file stat for determining file size.
|
||||||
* When a 32-bit system reads file size that is
|
* When a 32-bit system reads file size that is
|
||||||
|
@ -77,11 +86,13 @@ final class Archive
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
private $statFiles = true;
|
private $statFiles = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable flush after every write to output stream.
|
* Enable flush after every write to output stream.
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
private $flushOutput = false;
|
private $flushOutput = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP Content-Disposition. Defaults to
|
* HTTP Content-Disposition. Defaults to
|
||||||
* 'attachment', where
|
* 'attachment', where
|
||||||
|
@ -93,6 +104,7 @@ final class Archive
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $contentDisposition = 'attachment';
|
private $contentDisposition = 'attachment';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note that this does nothing if you are
|
* Note that this does nothing if you are
|
||||||
* not sending HTTP headers.
|
* not sending HTTP headers.
|
||||||
|
@ -100,6 +112,7 @@ final class Archive
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $contentType = 'application/x-zip';
|
private $contentType = 'application/x-zip';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
|
@ -159,12 +172,12 @@ final class Archive
|
||||||
$this->sendHttpHeaders = $sendHttpHeaders;
|
$this->sendHttpHeaders = $sendHttpHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHttpHeaderCallback(): Callable
|
public function getHttpHeaderCallback(): callable
|
||||||
{
|
{
|
||||||
return $this->httpHeaderCallback;
|
return $this->httpHeaderCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setHttpHeaderCallback(Callable $httpHeaderCallback): void
|
public function setHttpHeaderCallback(callable $httpHeaderCallback): void
|
||||||
{
|
{
|
||||||
$this->httpHeaderCallback = $httpHeaderCallback;
|
$this->httpHeaderCallback = $httpHeaderCallback;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace ZipStream\Option;
|
namespace ZipStream\Option;
|
||||||
|
@ -12,18 +13,22 @@ final class File
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $comment = '';
|
private $comment = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Method
|
* @var Method
|
||||||
*/
|
*/
|
||||||
private $method;
|
private $method;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
private $deflateLevel;
|
private $deflateLevel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var DateTimeInterface
|
* @var DateTimeInterface
|
||||||
*/
|
*/
|
||||||
private $time;
|
private $time;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace ZipStream\Option;
|
namespace ZipStream\Option;
|
||||||
|
@ -11,9 +12,12 @@ use MyCLabs\Enum\Enum;
|
||||||
* @method static STORE(): Method
|
* @method static STORE(): Method
|
||||||
* @method static DEFLATE(): Method
|
* @method static DEFLATE(): Method
|
||||||
* @psalm-immutable
|
* @psalm-immutable
|
||||||
|
* @psalm-template int
|
||||||
|
* @extends Enum<int>
|
||||||
*/
|
*/
|
||||||
class Method extends Enum
|
class Method extends Enum
|
||||||
{
|
{
|
||||||
const STORE = 0x00;
|
public const STORE = 0x00;
|
||||||
const DEFLATE = 0x08;
|
|
||||||
|
public const DEFLATE = 0x08;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace ZipStream\Option;
|
namespace ZipStream\Option;
|
||||||
|
@ -13,10 +14,14 @@ use MyCLabs\Enum\Enum;
|
||||||
* @method static DEFLATE(): Version
|
* @method static DEFLATE(): Version
|
||||||
* @method static ZIP64(): Version
|
* @method static ZIP64(): Version
|
||||||
* @psalm-immutable
|
* @psalm-immutable
|
||||||
|
* @psalm-template int
|
||||||
|
* @extends Enum<int>
|
||||||
*/
|
*/
|
||||||
class Version extends Enum
|
class Version extends Enum
|
||||||
{
|
{
|
||||||
const STORE = 0x000A; // 1.00
|
public const STORE = 0x000A; // 1.00
|
||||||
const DEFLATE = 0x0014; // 2.00
|
|
||||||
const ZIP64 = 0x002D; // 4.50
|
public const DEFLATE = 0x0014; // 2.00
|
||||||
|
|
||||||
|
public const ZIP64 = 0x002D; // 4.50
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace ZipStream;
|
namespace ZipStream;
|
||||||
|
|
||||||
|
use function mb_strlen;
|
||||||
|
|
||||||
use Psr\Http\Message\StreamInterface;
|
use Psr\Http\Message\StreamInterface;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
|
|
||||||
|
@ -22,6 +25,29 @@ class Stream implements StreamInterface
|
||||||
$this->stream = $stream;
|
$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.
|
* Closes the stream and any underlying resources.
|
||||||
*
|
*
|
||||||
|
@ -49,28 +75,6 @@ class Stream implements StreamInterface
|
||||||
return $result;
|
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.
|
* Seek to a position in the stream.
|
||||||
*
|
*
|
||||||
|
@ -86,10 +90,10 @@ class Stream implements StreamInterface
|
||||||
public function seek($offset, $whence = SEEK_SET): void
|
public function seek($offset, $whence = SEEK_SET): void
|
||||||
{
|
{
|
||||||
if (!$this->isSeekable()) {
|
if (!$this->isSeekable()) {
|
||||||
throw new RuntimeException;
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
if (fseek($this->stream, $offset, $whence) !== 0) {
|
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);
|
$position = ftell($this->stream);
|
||||||
if ($position === false) {
|
if ($position === false) {
|
||||||
throw new RuntimeException;
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
return $position;
|
return $position;
|
||||||
}
|
}
|
||||||
|
@ -182,12 +186,12 @@ class Stream implements StreamInterface
|
||||||
public function write($string): int
|
public function write($string): int
|
||||||
{
|
{
|
||||||
if (!$this->isWritable()) {
|
if (!$this->isWritable()) {
|
||||||
throw new RuntimeException;
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
if (fwrite($this->stream, $string) === false) {
|
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.
|
* call returns fewer bytes.
|
||||||
* @return string Returns the data read from the stream, or an empty string
|
* @return string Returns the data read from the stream, or an empty string
|
||||||
* if no bytes are available.
|
* if no bytes are available.
|
||||||
* @throws \RuntimeException if an error occurs.
|
* @throws RuntimeException if an error occurs.
|
||||||
*/
|
*/
|
||||||
public function read($length): string
|
public function read($length): string
|
||||||
{
|
{
|
||||||
if (!$this->isReadable()) {
|
if (!$this->isReadable()) {
|
||||||
throw new RuntimeException;
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
$result = fread($this->stream, $length);
|
$result = fread($this->stream, $length);
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
throw new RuntimeException;
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
@ -244,17 +248,17 @@ class Stream implements StreamInterface
|
||||||
* Returns the remaining contents in a string
|
* Returns the remaining contents in a string
|
||||||
*
|
*
|
||||||
* @return 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.
|
* reading.
|
||||||
*/
|
*/
|
||||||
public function getContents(): string
|
public function getContents(): string
|
||||||
{
|
{
|
||||||
if (!$this->isReadable()) {
|
if (!$this->isReadable()) {
|
||||||
throw new RuntimeException;
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
$result = stream_get_contents($this->stream);
|
$result = stream_get_contents($this->stream);
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
throw new RuntimeException;
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace ZipStream;
|
namespace ZipStream;
|
||||||
|
@ -80,19 +81,24 @@ class ZipStream
|
||||||
* to prevent file permissions issues upon extract (see #84)
|
* to prevent file permissions issues upon extract (see #84)
|
||||||
* 0x603 is 00000110 00000011 in binary, so 6 and 3
|
* 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.
|
* the initials of the inventor Phil Katz.
|
||||||
* See https://en.wikipedia.org/wiki/Zip_(file_format)#File_headers
|
* See https://en.wikipedia.org/wiki/Zip_(file_format)#File_headers
|
||||||
*/
|
*/
|
||||||
const FILE_HEADER_SIGNATURE = 0x04034b50;
|
public const FILE_HEADER_SIGNATURE = 0x04034b50;
|
||||||
const CDR_FILE_SIGNATURE = 0x02014b50;
|
|
||||||
const CDR_EOF_SIGNATURE = 0x06054b50;
|
public const CDR_FILE_SIGNATURE = 0x02014b50;
|
||||||
const DATA_DESCRIPTOR_SIGNATURE = 0x08074b50;
|
|
||||||
const ZIP64_CDR_EOF_SIGNATURE = 0x06064b50;
|
public const CDR_EOF_SIGNATURE = 0x06054b50;
|
||||||
const ZIP64_CDR_LOCATOR_SIGNATURE = 0x07064b50;
|
|
||||||
|
public const DATA_DESCRIPTOR_SIGNATURE = 0x08074b50;
|
||||||
|
|
||||||
|
public const ZIP64_CDR_EOF_SIGNATURE = 0x06064b50;
|
||||||
|
|
||||||
|
public const ZIP64_CDR_LOCATOR_SIGNATURE = 0x07064b50;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global Options
|
* Global Options
|
||||||
|
@ -293,7 +299,7 @@ class ZipStream
|
||||||
$options->defaultTo($this->opt);
|
$options->defaultTo($this->opt);
|
||||||
|
|
||||||
$file = new File($this, $name, $options);
|
$file = new File($this, $name, $options);
|
||||||
$file->processStream(new DeflateStream($stream));
|
$file->processStream(new Stream($stream));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -375,34 +381,6 @@ class ZipStream
|
||||||
$this->clear();
|
$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
|
* Create a format string and argument list for pack(), then call
|
||||||
* pack() and return the result.
|
* 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.
|
* Send HTTP headers for this stream.
|
||||||
*
|
*
|
||||||
|
@ -495,13 +529,13 @@ class ZipStream
|
||||||
$disposition .= "; filename*=UTF-8''{$urlencoded}";
|
$disposition .= "; filename*=UTF-8''{$urlencoded}";
|
||||||
}
|
}
|
||||||
|
|
||||||
$headers = array(
|
$headers = [
|
||||||
'Content-Type' => $this->opt->getContentType(),
|
'Content-Type' => $this->opt->getContentType(),
|
||||||
'Content-Disposition' => $disposition,
|
'Content-Disposition' => $disposition,
|
||||||
'Pragma' => 'public',
|
'Pragma' => 'public',
|
||||||
'Cache-Control' => 'public, must-revalidate',
|
'Cache-Control' => 'public, must-revalidate',
|
||||||
'Content-Transfer-Encoding' => 'binary'
|
'Content-Transfer-Encoding' => 'binary',
|
||||||
);
|
];
|
||||||
|
|
||||||
$call = $this->opt->getHttpHeaderCallback();
|
$call = $this->opt->getHttpHeaderCallback();
|
||||||
foreach ($headers as $key => $val) {
|
foreach ($headers as $key => $val) {
|
||||||
|
@ -571,32 +605,4 @@ class ZipStream
|
||||||
$this->cdr_ofs = new Bigint();
|
$this->cdr_ofs = new Bigint();
|
||||||
$this->opt = new ArchiveOptions();
|
$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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue