From ab68313384768484d0fa2fd5e08f1de897e669b1 Mon Sep 17 00:00:00 2001 From: Paul Holden Date: Tue, 11 Feb 2025 09:55:13 +0000 Subject: [PATCH] MDL-84171 libraries: upgrade to version 3.1.2 of ZipStream. --- lib/thirdpartylibs.xml | 2 +- lib/zipstream/composer.json | 15 ++++--- lib/zipstream/readme_moodle.txt | 2 +- lib/zipstream/src/Exception.php | 4 +- lib/zipstream/src/File.php | 26 +++++++---- lib/zipstream/src/PackField.php | 5 +-- lib/zipstream/src/Time.php | 20 +++------ .../Zip64/ExtendedInformationExtraField.php | 3 +- lib/zipstream/src/ZipStream.php | 45 +++++++++++-------- 9 files changed, 67 insertions(+), 55 deletions(-) diff --git a/lib/thirdpartylibs.xml b/lib/thirdpartylibs.xml index c19400efef3..36d18307669 100644 --- a/lib/thirdpartylibs.xml +++ b/lib/thirdpartylibs.xml @@ -583,7 +583,7 @@ All rights reserved. zipstream ZipStream-PHP PHP ZIP Streaming Library - 3.1.0 + 3.1.2 MIT https://github.com/maennchen/ZipStream-PHP diff --git a/lib/zipstream/composer.json b/lib/zipstream/composer.json index 98c536a43d9..6ecd503a66c 100644 --- a/lib/zipstream/composer.json +++ b/lib/zipstream/composer.json @@ -22,18 +22,19 @@ } ], "require": { - "php-64bit": "^8.1", + "php-64bit": "^8.2", "ext-mbstring": "*", "ext-zlib": "*" }, "require-dev": { - "phpunit/phpunit": "^10.0", + "phpunit/phpunit": "^11.0", "guzzlehttp/guzzle": "^7.5", "ext-zip": "*", "mikey179/vfsstream": "^1.6", "php-coveralls/php-coveralls": "^2.5", "friendsofphp/php-cs-fixer": "^3.16", - "vimeo/psalm": "^5.0" + "vimeo/psalm": "^6.0", + "brianium/paratest": "^7.7" }, "suggest": { "psr/http-message": "^2.0", @@ -46,13 +47,17 @@ "@test:formatted", "@test:lint" ], - "test:unit": "phpunit --coverage-clover=coverage.clover.xml --coverage-html cov", + "test:unit:setup-cov": "@putenv XDEBUG_MODE=coverage", + "test:unit": "paratest --functional", + "test:unit:cov": ["@test:unit:setup-cov", "@test:unit --coverage-clover=coverage.clover.xml --coverage-html cov"], "test:unit:slow": "@test:unit --group slow", + "test:unit:slow:cov": ["@test:unit:setup-cov", "@test:unit --coverage-clover=coverage.clover.xml --coverage-html cov --group slow"], "test:unit:fast": "@test:unit --exclude-group slow", + "test:unit:fast:cov": ["@test:unit:setup-cov", "@test:unit --coverage-clover=coverage.clover.xml --coverage-html cov --exclude-group slow"], "test:formatted": "@format --dry-run --stop-on-violation --using-cache=no", "test:lint": "psalm --stats --show-info=true --find-unused-psalm-suppress", "coverage:report": "php-coveralls --coverage_clover=coverage.clover.xml --json_path=coveralls-upload.json --insecure", - "install:tools": "phive install --trust-gpg-keys 0x67F861C3D889C656", + "install:tools": "phive install --trust-gpg-keys 0x67F861C3D889C656 --trust-gpg-keys 0x8AC0BAA79732DD42", "docs:generate": "tools/phpdocumentor --sourcecode" }, "autoload": { diff --git a/lib/zipstream/readme_moodle.txt b/lib/zipstream/readme_moodle.txt index ed1c0364c74..844609adf40 100644 --- a/lib/zipstream/readme_moodle.txt +++ b/lib/zipstream/readme_moodle.txt @@ -2,7 +2,7 @@ Instructions to import ZipStream into Moodle: 1/ Download from https://github.com/maennchen/ZipStream-PHP/releases/ -2/ Copy the LICENSE file and the src folder into the lib/zipstream folder +2/ Copy the LICENSE & composer.json files, and the src/ folder into the lib/zipstream folder 3/ Ensure any dependencies required are also imported, e.g.: - php-64bit diff --git a/lib/zipstream/src/Exception.php b/lib/zipstream/src/Exception.php index 27f4f30106f..2e81e307bb3 100644 --- a/lib/zipstream/src/Exception.php +++ b/lib/zipstream/src/Exception.php @@ -4,6 +4,4 @@ declare(strict_types=1); namespace ZipStream; -abstract class Exception extends \Exception -{ -} +abstract class Exception extends \Exception {} diff --git a/lib/zipstream/src/File.php b/lib/zipstream/src/File.php index 3f35de4664d..1498e4d6be2 100644 --- a/lib/zipstream/src/File.php +++ b/lib/zipstream/src/File.php @@ -95,7 +95,7 @@ class File if ($this->enableZeroHeader) { // No calculation required - } elseif ($this->isSimulation() && $forecastSize) { + } elseif ($this->isSimulation() && $forecastSize !== null) { $this->uncompressedSize = $forecastSize; $this->compressedSize = $forecastSize; } else { @@ -107,12 +107,14 @@ class File $this->addFileHeader(); - $detectedSize = $forecastSize ?? $this->compressedSize; + $detectedSize = $forecastSize ?? ($this->compressedSize > 0 ? $this->compressedSize : null); if ( $this->isSimulation() && - $detectedSize > 0 + $detectedSize !== null ) { + $this->uncompressedSize = $detectedSize; + $this->compressedSize = $detectedSize; ($this->recordSentBytes)($detectedSize); } else { $this->readStream(send: true); @@ -158,7 +160,7 @@ class File if ($this->compressionMethod !== CompressionMethod::STORE) { return null; } - if ($this->exactSize) { + if ($this->exactSize !== null) { return $this->exactSize; } $fstat = fstat($this->unpackStream()); @@ -184,7 +186,7 @@ class File $zip64Enabled = $footer !== ''; - if($zip64Enabled) { + if ($zip64Enabled) { $this->version = Version::ZIP64; } @@ -331,6 +333,10 @@ class File $data = fread($this->unpackStream(), $readLength); + if ($data === false) { + throw new ResourceActionException('fread', $this->unpackStream()); + } + hash_update($hash, $data); $this->uncompressedSize += strlen($data); @@ -341,6 +347,10 @@ class File $data, feof($this->unpackStream()) ? ZLIB_FINISH : ZLIB_NO_FLUSH ); + + if ($data === false) { + throw new RuntimeException('deflate_add failed'); + } } $this->compressedSize += strlen($data); @@ -350,7 +360,7 @@ class File } } - if ($this->exactSize && $this->uncompressedSize !== $this->exactSize) { + if ($this->exactSize !== null && $this->uncompressedSize !== $this->exactSize) { throw new FileSizeIncorrectException(expectedSize: $this->exactSize, actualSize: $this->uncompressedSize); } @@ -359,7 +369,7 @@ class File private function compressionInit(): ?DeflateContext { - switch($this->compressionMethod) { + switch ($this->compressionMethod) { case CompressionMethod::STORE: // Noting to do return null; @@ -390,7 +400,7 @@ class File return CentralDirectoryFileHeader::generate( versionMadeBy: ZipStream::ZIP_VERSION_MADE_BY, - versionNeededToExtract:$this->version->value, + versionNeededToExtract: $this->version->value, generalPurposeBitFlag: $this->generalPurposeBitFlag, compressionMethod: $this->compressionMethod, lastModificationDateTime: $this->lastModificationDateTime, diff --git a/lib/zipstream/src/PackField.php b/lib/zipstream/src/PackField.php index 3370dd8d0ee..892b4009a62 100644 --- a/lib/zipstream/src/PackField.php +++ b/lib/zipstream/src/PackField.php @@ -19,8 +19,7 @@ class PackField public function __construct( public readonly string $format, public readonly int|string $value - ) { - } + ) {} /** * Create a format string and argument list for pack(), then call @@ -33,7 +32,7 @@ class PackField }, ''); $args = array_map(function (self $field) { - switch($field->format) { + switch ($field->format) { case 'V': if ($field->value > self::MAX_V) { throw new RuntimeException(print_r($field->value, true) . ' is larger than 32 bits'); diff --git a/lib/zipstream/src/Time.php b/lib/zipstream/src/Time.php index 4bfba3cc53d..1b4121ca9fc 100644 --- a/lib/zipstream/src/Time.php +++ b/lib/zipstream/src/Time.php @@ -26,20 +26,14 @@ abstract class Time $dateTime = DateTimeImmutable::createFromInterface($dateTime)->sub(new DateInterval('P1980Y')); - ['year' => $year, - 'mon' => $month, - 'mday' => $day, - 'hours' => $hour, - 'minutes' => $minute, - 'seconds' => $second - ] = getdate($dateTime->getTimestamp()); + [$year, $month, $day, $hour, $minute, $second] = explode(' ', $dateTime->format('Y n j G i s')); return - ($year << 25) | - ($month << 21) | - ($day << 16) | - ($hour << 11) | - ($minute << 5) | - ($second >> 1); + ((int) $year << 25) | + ((int) $month << 21) | + ((int) $day << 16) | + ((int) $hour << 11) | + ((int) $minute << 5) | + ((int) $second >> 1); } } diff --git a/lib/zipstream/src/Zip64/ExtendedInformationExtraField.php b/lib/zipstream/src/Zip64/ExtendedInformationExtraField.php index b647ce6cd54..aaac51c83c6 100644 --- a/lib/zipstream/src/Zip64/ExtendedInformationExtraField.php +++ b/lib/zipstream/src/Zip64/ExtendedInformationExtraField.php @@ -23,8 +23,7 @@ abstract class ExtendedInformationExtraField new PackField(format: 'v', value: self::TAG), new PackField( format: 'v', - value: - ($originalSize === null ? 0 : 8) + + value: ($originalSize === null ? 0 : 8) + ($compressedSize === null ? 0 : 8) + ($relativeHeaderOffset === null ? 0 : 8) + ($diskStartNumber === null ? 0 : 4) diff --git a/lib/zipstream/src/ZipStream.php b/lib/zipstream/src/ZipStream.php index cd308a4932b..698ffbb32be 100644 --- a/lib/zipstream/src/ZipStream.php +++ b/lib/zipstream/src/ZipStream.php @@ -59,7 +59,7 @@ use ZipStream\Exception\ResourceActionException; * * // read and add each file to the archive * foreach ($files as $path) - * $zip->addFileFormPath(fileName: $path, $path); + * $zip->addFileFromPath(fileName: $path, $path); * * // write archive footer to stream * $zip->finish(); @@ -263,7 +263,7 @@ class ZipStream ): void { $this->addFileFromCallback( fileName: $fileName, - callback: fn () => $data, + callback: fn() => $data, comment: $comment, compressionMethod: $compressionMethod, deflateLevel: $deflateLevel, @@ -293,7 +293,7 @@ class ZipStream * // add a file named 'bigfile.rar' from the local file * // '/usr/share/bigfile.rar' with a comment and a last-modified * // time of two hours ago - * $zip->addFile( + * $zip->addFileFromPath( * fileName: 'bigfile.rar', * path: '/usr/share/bigfile.rar', * comment: 'this is a comment about bigfile.rar', @@ -330,7 +330,8 @@ class ZipStream throw new FileNotReadableException($path); } - if ($fileTime = filemtime($path)) { + $fileTime = filemtime($path); + if ($fileTime !== false) { $lastModificationDateTime ??= (new DateTimeImmutable())->setTimestamp($fileTime); } @@ -394,7 +395,7 @@ class ZipStream ): void { $this->addFileFromCallback( fileName: $fileName, - callback: fn () => $stream, + callback: fn() => $stream, comment: $comment, compressionMethod: $compressionMethod, deflateLevel: $deflateLevel, @@ -473,7 +474,7 @@ class ZipStream ): void { $this->addFileFromCallback( fileName: $fileName, - callback: fn () => $stream, + callback: fn() => $stream, comment: $comment, compressionMethod: $compressionMethod, deflateLevel: $deflateLevel, @@ -494,7 +495,7 @@ class ZipStream * * ```php * foreach($files as $name => $size) { - * $archive->addFileFromPsr7Stream( + * $archive->addFileFromCallback( * fileName: 'streamfile.txt', * exactSize: $size, * callback: function() use($name): Psr\Http\Message\StreamInterface { @@ -563,11 +564,11 @@ class ZipStream dataCallback: function () use ($callback, $maxSize) { $data = $callback(); - if(is_resource($data)) { + if (is_resource($data)) { return $data; } - if($data instanceof StreamInterface) { + if ($data instanceof StreamInterface) { return StreamWrapper::getResource($data); } @@ -611,7 +612,7 @@ class ZipStream enableZeroHeader: $enableZeroHeader ?? $this->defaultEnableZeroHeader, ); - if($this->operationMode !== OperationMode::NORMAL) { + if ($this->operationMode !== OperationMode::NORMAL) { $this->recordedSimulation[] = $file; } @@ -629,7 +630,7 @@ class ZipStream * * ```php * // add a directory named 'world/' - * $zip->addFile(fileName: 'world/'); + * $zip->addDirectory(fileName: 'world/'); * ``` */ public function addDirectory( @@ -676,11 +677,11 @@ class ZipStream */ public function executeSimulation(): void { - if($this->operationMode !== OperationMode::NORMAL) { + if ($this->operationMode !== OperationMode::NORMAL) { throw new RuntimeException('Zip simulation is not finished.'); } - foreach($this->recordedSimulation as $file) { + foreach ($this->recordedSimulation as $file) { $this->centralDirectoryRecords[] = $file->cloneSimulationExecution()->process(); } @@ -769,7 +770,13 @@ class ZipStream if (is_resource($outputStream)) { return $outputStream; } - return fopen('php://output', 'wb'); + $resource = fopen('php://output', 'wb'); + + if ($resource === false) { + throw new RuntimeException('fopen of php://output failed'); + } + + return $resource; } /** @@ -815,15 +822,15 @@ class ZipStream } } - /** - * Send HTTP headers for this stream. - */ + /** + * Send HTTP headers for this stream. + */ private function sendHttpHeaders(): void { // grab content disposition $disposition = $this->contentDisposition; - if ($this->outputName) { + if ($this->outputName !== null) { // Various different browsers dislike various characters here. Strip them all for safety. $safeOutput = trim(str_replace(['"', "'", '\\', ';', "\n", "\r"], '', $this->outputName)); @@ -854,7 +861,7 @@ class ZipStream $this->centralDirectoryRecords = []; $this->offset = 0; - if($this->operationMode === OperationMode::NORMAL) { + if ($this->operationMode === OperationMode::NORMAL) { $this->ready = false; $this->recordedSimulation = []; } else {