From 19c4a0e90212a0ba179e40bfb0a3ee1a7e3de4a1 Mon Sep 17 00:00:00 2001 From: Robin D'Arcy Date: Wed, 30 May 2018 22:54:38 +0100 Subject: [PATCH] Throw exception for invalid range to prevent infinite loop Fixes #519 Closes #521 --- CHANGELOG.md | 1 + src/PhpSpreadsheet/Cell/Coordinate.php | 44 +++++++++++++++++--------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c3b3af8db..16e3023fce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Xlsx loaded an extra empty comment for each real comment - [#375](https://github.com/PHPOffice/PhpSpreadsheet/issues/375) - Xlsx reader do not read rows and columns filtered out in readFilter at all - [#370](https://github.com/PHPOffice/PhpSpreadsheet/issues/370) - Make newer Excel versions properly recalculate formulas on document open - [#456](https://github.com/PHPOffice/PhpSpreadsheet/issues/456) +- `Coordinate::extractAllCellReferencesInRange()` throws an exception for an invalid range – [#519](https://github.com/PHPOffice/PhpSpreadsheet/issues/519) ## [1.2.1] - 2018-04-10 diff --git a/src/PhpSpreadsheet/Cell/Coordinate.php b/src/PhpSpreadsheet/Cell/Coordinate.php index 366ec492ce..077e8d0628 100644 --- a/src/PhpSpreadsheet/Cell/Coordinate.php +++ b/src/PhpSpreadsheet/Cell/Coordinate.php @@ -340,7 +340,7 @@ public static function extractAllCellReferencesInRange($pRange) // Explode spaces $cellBlocks = self::getCellBlocksFromRangeString($pRange); foreach ($cellBlocks as $cellBlock) { - $returnValue = array_merge($returnValue, self::getReferencesForCellBlock($cellBlock)); + $returnValue = array_merge($returnValue, static::getReferencesForCellBlock($cellBlock)); } // Sort the result by column and row @@ -360,6 +360,8 @@ public static function extractAllCellReferencesInRange($pRange) * * @param string $cellBlock A cell range e.g. A4:B5 * + * @throws Exception + * * @return array All individual cells in that range */ private static function getReferencesForCellBlock($cellBlock) @@ -383,25 +385,23 @@ private static function getReferencesForCellBlock($cellBlock) // Range... list($rangeStart, $rangeEnd) = $range; - list($startColumn, $startRow) = self::coordinateFromString($rangeStart); - list($endColumn, $endRow) = self::coordinateFromString($rangeEnd); - $startColumnIndex = self::columnIndexFromString($startColumn); - $endColumnIndex = self::columnIndexFromString($endColumn); - ++$endColumnIndex; + list($startCol, $startRow) = static::extractColumnAndRow($rangeStart); + list($endCol, $endRow) = static::extractColumnAndRow($rangeEnd); + ++$endCol; // Current data - $currentColumnIndex = $startColumnIndex; + $currentCol = $startCol; $currentRow = $startRow; - self::validateRange($cellBlock, $startColumnIndex, $endColumnIndex, $currentRow, $endRow); + static::validateRange($cellBlock, $startCol, $endCol, $currentRow, $endRow); // Loop cells - while ($currentColumnIndex < $endColumnIndex) { + while ($currentCol < $endCol) { while ($currentRow <= $endRow) { - $returnValue[] = self::stringFromColumnIndex($currentColumnIndex) . $currentRow; + $returnValue[] = $currentCol . $currentRow; ++$currentRow; } - ++$currentColumnIndex; + ++$currentCol; $currentRow = $startRow; } } @@ -409,6 +409,18 @@ private static function getReferencesForCellBlock($cellBlock) return $returnValue; } + /** + * Extract the column and row from a cell reference in the format [$column, $row]. + * + * @param string $cell + * + * @return array + */ + private static function extractColumnAndRow($cell) + { + return sscanf($cell, '%[A-Z]%d'); + } + /** * Convert an associative array of single cell coordinates to values to an associative array * of cell ranges to values. Only adjacent cell coordinates with the same @@ -512,14 +524,16 @@ private static function getCellBlocksFromRangeString($pRange) * row. * * @param string $cellBlock The original range, for displaying a meaningful error message - * @param int $startColumnIndex - * @param int $endColumnIndex + * @param string $startCol + * @param string $endCol * @param int $currentRow * @param int $endRow + * + * @throws Exception */ - private static function validateRange($cellBlock, $startColumnIndex, $endColumnIndex, $currentRow, $endRow) + private static function validateRange($cellBlock, $startCol, $endCol, $currentRow, $endRow) { - if ($startColumnIndex >= $endColumnIndex || $currentRow > $endRow) { + if ($startCol >= $endCol || $currentRow > $endRow) { throw new Exception('Invalid range: "' . $cellBlock . '"'); } }