Skip to content

Commit

Permalink
"!" characters in Worksheet title will make reference formulas crash P…
Browse files Browse the repository at this point in the history
…HPOffice#325

 Bugfix: replace explode by "!" with special function, that extracts sheet name from reference
  • Loading branch information
bayzhanov committed Sep 6, 2018
1 parent bebfb1e commit 46b2b87
Show file tree
Hide file tree
Showing 14 changed files with 46 additions and 73 deletions.
19 changes: 7 additions & 12 deletions src/PhpSpreadsheet/Calculation/Calculation.php
Original file line number Diff line number Diff line change
Expand Up @@ -3478,19 +3478,15 @@ private function _parseFormula($formula, Cell $pCell = null)
$testPrevOp = $stack->last(1);
if ($testPrevOp['value'] == ':') {
$startRowColRef = $output[count($output) - 1]['value'];
$rangeWS1 = '';
if (strpos('!', $startRowColRef) !== false) {
list($rangeWS1, $startRowColRef) = explode('!', $startRowColRef);
}
list($rangeWS1, $startRowColRef) = Worksheet::extractSheetTitle($startRowColRef, true);
if ($rangeWS1 != '') {
$rangeWS1 .= '!';
}
$rangeWS2 = $rangeWS1;
if (strpos('!', $val) !== false) {
list($rangeWS2, $val) = explode('!', $val);
}
list($rangeWS2, $val) = Worksheet::extractSheetTitle($val, true);
if ($rangeWS2 != '') {
$rangeWS2 .= '!';
} else {
$rangeWS2 = $rangeWS1;
}
if ((is_int($startRowColRef)) && (ctype_digit($val)) &&
($startRowColRef <= 1048576) && ($val <= 1048576)) {
Expand Down Expand Up @@ -3665,13 +3661,12 @@ private function processTokenStack($tokens, $cellID = null, Cell $pCell = null)
case ':': // Range
$sheet1 = $sheet2 = '';
if (strpos($operand1Data['reference'], '!') !== false) {
list($sheet1, $operand1Data['reference']) = explode('!', $operand1Data['reference']);
list($sheet1, $operand1Data['reference']) = Worksheet::extractSheetTitle($operand1Data['reference'], true);
} else {
$sheet1 = ($pCellParent !== null) ? $pCellWorksheet->getTitle() : '';
}
if (strpos($operand2Data['reference'], '!') !== false) {
list($sheet2, $operand2Data['reference']) = explode('!', $operand2Data['reference']);
} else {
list($sheet2, $operand2Data['reference']) = Worksheet::extractSheetTitle($operand2Data['reference'], true);
if (empty($sheet2)) {
$sheet2 = $sheet1;
}
if ($sheet1 == $sheet2) {
Expand Down
15 changes: 6 additions & 9 deletions src/PhpSpreadsheet/Calculation/LookupRef.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;

class LookupRef
{
Expand Down Expand Up @@ -96,9 +97,7 @@ public static function COLUMN($cellAddress = null)
return (int) Coordinate::columnIndexFromString($columnKey);
}
} else {
if (strpos($cellAddress, '!') !== false) {
list($sheet, $cellAddress) = explode('!', $cellAddress);
}
list($sheet, $cellAddress) = Worksheet::extractSheetTitle($cellAddress, true);
if (strpos($cellAddress, ':') !== false) {
list($startAddress, $endAddress) = explode(':', $cellAddress);
$startAddress = preg_replace('/[^a-z]/i', '', $startAddress);
Expand Down Expand Up @@ -175,9 +174,7 @@ public static function ROW($cellAddress = null)
}
}
} else {
if (strpos($cellAddress, '!') !== false) {
list($sheet, $cellAddress) = explode('!', $cellAddress);
}
list($sheet, $cellAddress) = Worksheet::extractSheetTitle($cellAddress, true);
if (strpos($cellAddress, ':') !== false) {
list($startAddress, $endAddress) = explode(':', $cellAddress);
$startAddress = preg_replace('/\D/', '', $startAddress);
Expand Down Expand Up @@ -297,7 +294,7 @@ public static function INDIRECT($cellAddress = null, Cell $pCell = null)
}

if (strpos($cellAddress, '!') !== false) {
list($sheetName, $cellAddress) = explode('!', $cellAddress);
list($sheetName, $cellAddress) = Worksheet::extractSheetTitle($cellAddress, true);
$sheetName = trim($sheetName, "'");
$pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName);
} else {
Expand All @@ -308,7 +305,7 @@ public static function INDIRECT($cellAddress = null, Cell $pCell = null)
}

if (strpos($cellAddress, '!') !== false) {
list($sheetName, $cellAddress) = explode('!', $cellAddress);
list($sheetName, $cellAddress) = Worksheet::extractSheetTitle($cellAddress, true);
$sheetName = trim($sheetName, "'");
$pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName);
} else {
Expand Down Expand Up @@ -361,7 +358,7 @@ public static function OFFSET($cellAddress = null, $rows = 0, $columns = 0, $hei

$sheetName = null;
if (strpos($cellAddress, '!')) {
list($sheetName, $cellAddress) = explode('!', $cellAddress);
list($sheetName, $cellAddress) = Worksheet::extractSheetTitle($cellAddress, true);
$sheetName = trim($sheetName, "'");
}
if (strpos($cellAddress, ':')) {
Expand Down
13 changes: 3 additions & 10 deletions src/PhpSpreadsheet/Cell/Coordinate.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace PhpOffice\PhpSpreadsheet\Cell;

use PhpOffice\PhpSpreadsheet\Exception;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;

/**
* Helper class to manipulate cell coordinates.
Expand Down Expand Up @@ -70,11 +71,7 @@ public static function absoluteReference($pCoordinateString)
}

// Split out any worksheet name from the reference
$worksheet = '';
$cellAddress = explode('!', $pCoordinateString);
if (count($cellAddress) > 1) {
list($worksheet, $pCoordinateString) = $cellAddress;
}
list($worksheet, $pCoordinateString) = Worksheet::extractSheetTitle($pCoordinateString, true);
if ($worksheet > '') {
$worksheet .= '!';
}
Expand Down Expand Up @@ -105,11 +102,7 @@ public static function absoluteCoordinate($pCoordinateString)
}

// Split out any worksheet name from the coordinate
$worksheet = '';
$cellAddress = explode('!', $pCoordinateString);
if (count($cellAddress) > 1) {
list($worksheet, $pCoordinateString) = $cellAddress;
}
list($worksheet, $pCoordinateString) = Worksheet::extractSheetTitle($pCoordinateString, true);
if ($worksheet > '') {
$worksheet .= '!';
}
Expand Down
6 changes: 1 addition & 5 deletions src/PhpSpreadsheet/Chart/DataSeriesValues.php
Original file line number Diff line number Diff line change
Expand Up @@ -354,11 +354,7 @@ public function refresh(Worksheet $worksheet, $flatten = true)
}
unset($dataValue);
} else {
$cellRange = explode('!', $this->dataSource);
if (count($cellRange) > 1) {
list(, $cellRange) = $cellRange;
}

list($worksheet, $cellRange) = Worksheet::extractSheetTitle($this->dataSource, true);
$dimensions = Coordinate::rangeDimension(str_replace('$', '', $cellRange));
if (($dimensions[0] == 1) || ($dimensions[1] == 1)) {
$this->dataValues = Functions::flattenArray($newDataValues);
Expand Down
3 changes: 2 additions & 1 deletion src/PhpSpreadsheet/Reader/Gnumeric.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use PhpOffice\PhpSpreadsheet\Style\Borders;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Font;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use XMLReader;

class Gnumeric extends BaseReader
Expand Down Expand Up @@ -784,7 +785,7 @@ public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
continue;
}

$range = explode('!', $range);
$range = Worksheet::extractSheetTitle($range, true);
$range[0] = trim($range[0], "'");
if ($worksheet = $spreadsheet->getSheetByName($range[0])) {
$extractedRange = str_replace('$', '', $range[1]);
Expand Down
11 changes: 5 additions & 6 deletions src/PhpSpreadsheet/Reader/Xls.php
Original file line number Diff line number Diff line change
Expand Up @@ -1213,7 +1213,7 @@ public function load($pFilename)
// $range should look like one of these
// Foo!$C$7:$J$66
// Bar!$A$1:$IV$2
$explodes = explode('!', $range); // FIXME: what if sheetname contains exclamation mark?
$explodes = Worksheet::extractSheetTitle($range, true);
$sheetName = trim($explodes[0], "'");
if (count($explodes) == 2) {
if (strpos($explodes[1], ':') === false) {
Expand Down Expand Up @@ -1243,8 +1243,8 @@ public function load($pFilename)
// $range should look like this one of these
// Sheet!$A$1:$B$65536
// Sheet!$A$1:$IV$2
$explodes = explode('!', $range);
if (count($explodes) == 2) {
if (strpos($range, '!') !== false) {
$explodes = Worksheet::extractSheetTitle($range, true);
if ($docSheet = $this->spreadsheet->getSheetByName($explodes[0])) {
$extractedRange = $explodes[1];
$extractedRange = str_replace('$', '', $extractedRange);
Expand All @@ -1270,9 +1270,8 @@ public function load($pFilename)
}
} else {
// Extract range
$explodes = explode('!', $definedName['formula']);

if (count($explodes) == 2) {
if (strpos($definedName['formula'], '!') !== false) {
$explodes = Worksheet::extractSheetTitle($definedName['formula'], true);
if (($docSheet = $this->spreadsheet->getSheetByName($explodes[0])) ||
($docSheet = $this->spreadsheet->getSheetByName(trim($explodes[0], "'")))) {
$extractedRange = $explodes[1];
Expand Down
10 changes: 4 additions & 6 deletions src/PhpSpreadsheet/Reader/Xlsx.php
Original file line number Diff line number Diff line change
Expand Up @@ -1833,8 +1833,7 @@ public function load($pFilename)
$rangeSets = preg_split("/'(.*?)'(?:![A-Z0-9]+:[A-Z0-9]+,?)/", $extractedRange, PREG_SPLIT_NO_EMPTY);
$newRangeSets = [];
foreach ($rangeSets as $rangeSet) {
$range = explode('!', $rangeSet); // FIXME: what if sheetname contains exclamation mark?
$rangeSet = isset($range[1]) ? $range[1] : $range[0];
list($sheetName, $rangeSet) = Worksheet::extractSheetTitle($rangeSet, true);
if (strpos($rangeSet, ':') === false) {
$rangeSet = $rangeSet . ':' . $rangeSet;
}
Expand Down Expand Up @@ -1881,8 +1880,8 @@ public function load($pFilename)
break;
default:
if ($mapSheetId[(int) $definedName['localSheetId']] !== null) {
$range = explode('!', (string) $definedName);
if (count($range) == 2) {
if (strpos((string) $definedName, '!') !== false) {
$range = Worksheet::extractSheetTitle((string) $definedName, true);
$range[0] = str_replace("''", "'", $range[0]);
$range[0] = str_replace("'", '', $range[0]);
if ($worksheet = $docSheet->getParent()->getSheetByName($range[0])) {
Expand All @@ -1908,8 +1907,7 @@ public function load($pFilename)
$locatedSheet = $excel->getSheetByName($extractedSheetName);

// Modify range
$range = explode('!', $extractedRange);
$extractedRange = isset($range[1]) ? $range[1] : $range[0];
list($worksheetName, $extractedRange) = Worksheet::extractSheetTitle($extractedRange, true);
}

if ($locatedSheet !== null) {
Expand Down
7 changes: 2 additions & 5 deletions src/PhpSpreadsheet/Worksheet/AutoFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,8 @@ public function getRange()
*/
public function setRange($pRange)
{
// Uppercase coordinate
$cellAddress = explode('!', strtoupper($pRange));
if (count($cellAddress) > 1) {
list($worksheet, $pRange) = $cellAddress;
}
// extract coordinate
list($worksheet, $pRange) = Worksheet::extractSheetTitle($pRange, true);

if (strpos($pRange, ':') !== false) {
$this->range = $pRange;
Expand Down
6 changes: 3 additions & 3 deletions src/PhpSpreadsheet/Worksheet/Worksheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -2729,12 +2729,12 @@ public function getHashCode()
public static function extractSheetTitle($pRange, $returnRange = false)
{
// Sheet title included?
if (($sep = strpos($pRange, '!')) === false) {
return '';
if (($sep = strrpos($pRange, '!')) === false) {
return $returnRange ? ['', $pRange] : '';
}

if ($returnRange) {
return [trim(substr($pRange, 0, $sep), "'"), substr($pRange, $sep + 1)];
return [substr($pRange, 0, $sep), substr($pRange, $sep + 1)];
}

return substr($pRange, $sep + 1);
Expand Down
5 changes: 3 additions & 2 deletions src/PhpSpreadsheet/Writer/Xls/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace PhpOffice\PhpSpreadsheet\Writer\Xls;

use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet as PhpspreadsheetWorksheet;
use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;

// Original file header of PEAR::Spreadsheet_Excel_Writer_Parser (used as the base for this class):
Expand Down Expand Up @@ -643,7 +644,7 @@ private function convertRange2d($range, $class = 0)
private function convertRange3d($token)
{
// Split the ref at the ! symbol
list($ext_ref, $range) = explode('!', $token);
list($ext_ref, $range) = PhpspreadsheetWorksheet::extractSheetTitle($token, true);

// Convert the external reference part (different for BIFF8)
$ext_ref = $this->getRefIndex($ext_ref);
Expand Down Expand Up @@ -695,7 +696,7 @@ private function convertRef2d($cell)
private function convertRef3d($cell)
{
// Split the ref at the ! symbol
list($ext_ref, $cell) = explode('!', $cell);
list($ext_ref, $cell) = PhpspreadsheetWorksheet::extractSheetTitle($cell, true);

// Convert the external reference part (different for BIFF8)
$ext_ref = $this->getRefIndex($ext_ref);
Expand Down
4 changes: 1 addition & 3 deletions src/PhpSpreadsheet/Writer/Xlsx/Workbook.php
Original file line number Diff line number Diff line change
Expand Up @@ -339,9 +339,7 @@ private function writeDefinedNameForAutofilter(XMLWriter $objWriter, Worksheet $
$range = Coordinate::splitRange($autoFilterRange);
$range = $range[0];
// Strip any worksheet ref so we can make the cell ref absolute
if (strpos($range[0], '!') !== false) {
list($ws, $range[0]) = explode('!', $range[0]);
}
list($ws, $range[0]) = Worksheet::extractSheetTitle($range[0], true);

$range[0] = Coordinate::absoluteCoordinate($range[0]);
$range[1] = Coordinate::absoluteCoordinate($range[1]);
Expand Down
4 changes: 1 addition & 3 deletions src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -748,9 +748,7 @@ private function writeAutoFilter(XMLWriter $objWriter, PhpspreadsheetWorksheet $
$range = Coordinate::splitRange($autoFilterRange);
$range = $range[0];
// Strip any worksheet ref
if (strpos($range[0], '!') !== false) {
list($ws, $range[0]) = explode('!', $range[0]);
}
list($ws, $range[0]) = PhpspreadsheetWorksheet::extractSheetTitle($range[0], true);
$range = implode(':', $range);

$objWriter->writeAttribute('ref', str_replace('$', '', $range));
Expand Down
8 changes: 4 additions & 4 deletions tests/data/CellAbsoluteCoordinate.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@
'\'Worksheet1\'!$AI256',
],
[
'\'Worksheet1\'!$AI$256',
'\'Worksheet1\'!AI$256',
'\'Work!sheet1!\'!$AI$256',
'\'Work!sheet1!\'!AI$256',
],
[
'\'Worksheet1\'!$AI$256',
'\'Worksheet1\'!$AI$256',
'\'Work!sheet1!\'!$AI$256',
'\'Work!sheet1!\'!$AI$256',
],
];
8 changes: 4 additions & 4 deletions tests/data/CellAbsoluteReference.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@
'AI2012',
],
[
'\'Worksheet1\'!$AI$256',
'\'Worksheet1\'!AI256',
'\'Work!sheet1\'!$AI$256',
'\'Work!sheet1\'!AI256',
],
[
'Worksheet1!$AI$256',
'Worksheet1!AI256',
'Work!sheet1!$AI$256',
'Work!sheet1!AI256',
],
[
'\'Data Worksheet\'!$AI$256',
Expand Down

0 comments on commit 46b2b87

Please sign in to comment.