Merge commit from fork

This commit is contained in:
oleibman
2026-07-11 22:15:04 -07:00
committed by GitHub
parent 0577c74889
commit 85f2556b0b
6 changed files with 138 additions and 1 deletions
+23 -1
View File
@@ -64,6 +64,14 @@ class Gnumeric extends BaseReader
],
];
protected int $maxLength;
private const LENGTH_MULTIPLIER = [
'G' => 1024 * 1024 * 1024,
'M' => 1024 * 1024,
'K' => 1024,
];
/**
* Create a new Gnumeric.
*/
@@ -72,6 +80,20 @@ class Gnumeric extends BaseReader
parent::__construct();
$this->referenceHelper = ReferenceHelper::getInstance();
$this->securityScanner = XmlScanner::getInstance($this);
$limit = ini_get('memory_limit') ?: '128M';
$limit = trim(str_replace('-1', '128M', $limit));
$unit = strtoupper(substr($limit, -1));
$limit = (int) $limit;
$multiplier = self::LENGTH_MULTIPLIER[$unit] ?? 1;
$limit *= $multiplier;
$this->maxLength = intdiv($limit, 4);
}
public function setMaxLength(int $maxLength): self
{
$this->maxLength = $maxLength;
return $this;
}
/**
@@ -192,7 +214,7 @@ class Gnumeric extends BaseReader
if (str_starts_with($contents, "\x1f\x8b")) {
// Check if gzlib functions are available
if (function_exists('gzdecode')) {
$contents = @gzdecode($contents);
$contents = @gzdecode($contents, $this->maxLength);
if ($contents !== false) {
$data = $contents;
}
+19
View File
@@ -61,6 +61,9 @@ class OLERead
/** @var mixed[][] */
private array $props = [];
/** @var int[] */
private array $possibleLoop = [];
/**
* Read the file.
*/
@@ -137,7 +140,9 @@ class OLERead
$sbdBlock = $this->sbdStartBlock;
$this->smallBlockChain = '';
$this->possibleLoop = [];
while ($sbdBlock != -2) {
$this->catchLoop($sbdBlock);
$pos = ($sbdBlock + 1) * self::BIG_BLOCK_SIZE;
$this->smallBlockChain .= substr($this->data, $pos, 4 * $bbs);
@@ -153,6 +158,14 @@ class OLERead
$this->readPropertySets();
}
private function catchLoop(int $sbdBlock): void
{
if (in_array($sbdBlock, $this->possibleLoop, true)) {
throw new ReaderException('Detected loop while iterating blocks');
}
$this->possibleLoop[] = $sbdBlock;
}
/**
* Extract binary stream data.
*/
@@ -172,7 +185,9 @@ class OLERead
/** @var int */
$block = $this->props[$stream]['startBlock'];
$this->possibleLoop = [];
while ($block != -2) {
$this->catchLoop($block);
$pos = $block * self::SMALL_BLOCK_SIZE;
$streamData .= substr($rootdata, $pos, self::SMALL_BLOCK_SIZE);
@@ -195,7 +210,9 @@ class OLERead
/** @var int */
$block = $this->props[$stream]['startBlock'];
$this->possibleLoop = [];
while ($block != -2) {
$this->catchLoop($block);
$pos = ($block + 1) * self::BIG_BLOCK_SIZE;
$streamData .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
$block = self::getInt4d($this->bigBlockChain, $block * 4);
@@ -215,7 +232,9 @@ class OLERead
{
$data = '';
$this->possibleLoop = [];
while ($block != -2) {
$this->catchLoop($block);
$pos = ($block + 1) * self::BIG_BLOCK_SIZE;
$data .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
$block = self::getInt4d($this->bigBlockChain, $block * 4);
@@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Reader\Gnumeric;
use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
use PhpOffice\PhpSpreadsheet\Reader\Gnumeric;
use PHPUnit\Framework\TestCase;
class LargeDecompressionTest extends TestCase
{
private const FILENAME = 'tests/data/Reader/Gnumeric/gzbomb.gnumeric';
public function testEnoughMemoryCanRead(): void
{
$reader = new Gnumeric();
self::assertTrue($reader->canRead(self::FILENAME));
}
public function testNotEnoughMemoryCanRead(): void
{
$reader = new Gnumeric();
$reader->setMaxLength(64 * 1024 * 1024);
self::assertFalse($reader->canRead(self::FILENAME));
}
public function testNotEnoughMemoryListNames(): void
{
$this->expectException(ReaderException::class);
$this->expectExceptionMessage('invalid Gnumeric file');
$reader = new Gnumeric();
$reader->setMaxLength(64 * 1024 * 1024);
$reader->listWorksheetNames(self::FILENAME);
}
public function testNotEnoughMemoryListInfo(): void
{
$this->expectException(ReaderException::class);
$this->expectExceptionMessage('invalid Gnumeric file');
$reader = new Gnumeric();
$reader->setMaxLength(64 * 1024 * 1024);
$reader->listWorksheetInfo(self::FILENAME);
}
public function testNotEnoughMemoryLoad(): void
{
$this->expectException(ReaderException::class);
$this->expectExceptionMessage('invalid Gnumeric file');
$reader = new Gnumeric();
$reader->setMaxLength(64 * 1024 * 1024);
$reader->load(self::FILENAME);
}
}
@@ -0,0 +1,42 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xls;
use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
use PhpOffice\PhpSpreadsheet\Reader\Xls as XlsReader;
use PHPUnit\Framework\TestCase;
class OleLoopTest extends TestCase
{
private const FILENAME = 'tests/data/Reader/XLS/oleloop.xls';
public function testDetectLoopCanRead(): void
{
$reader = new XlsReader();
self::assertFalse($reader->canRead(self::FILENAME));
}
public function testDetectLoopListNames(): void
{
$this->expectException(ReaderException::class);
$this->expectExceptionMessage('Detected loop');
$reader = new XlsReader();
$reader->listWorksheetNames(self::FILENAME);
}
public function testDetectLoopListInfo(): void
{
$this->expectException(ReaderException::class);
$this->expectExceptionMessage('Detected loop');
$reader = new XlsReader();
$reader->listWorksheetInfo(self::FILENAME);
}
public function testDetectLoopLoad(): void
{
$this->expectException(ReaderException::class);
$this->expectExceptionMessage('Detected loop');
$reader = new XlsReader();
$reader->load(self::FILENAME);
}
}
Binary file not shown.
Binary file not shown.