Skip to content

Commit d813d7e

Browse files
authored
Merge pull request #4360 from oleibman/issue4536
Xlsx Reader Defined Name on Sheet with Apostrophe in Title
2 parents 82ac7ab + 898ec44 commit d813d7e

29 files changed

+387
-99
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
3232
### Fixed
3333

3434
- Refactor Helper/Html. [PR #4359](https://github.com/PHPOffice/PhpSpreadsheet/pull/4359)
35+
- Better handling of defined names on sheets whose titles include apostrophes. [Issue #4356](https://github.com/PHPOffice/PhpSpreadsheet/issues/4356) [Issue #4362](https://github.com/PHPOffice/PhpSpreadsheet/issues/4362) [Issue #4376](https://github.com/PHPOffice/PhpSpreadsheet/issues/4376) [PR #4360](https://github.com/PHPOffice/PhpSpreadsheet/pull/4360)
3536

3637
## 2025-02-08 - 4.0.0
3738

src/PhpSpreadsheet/Calculation/Calculation.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4408,7 +4408,9 @@ private function internalParseFormula(string $formula, ?Cell $cell = null): bool
44084408
if ($rangeWS1 !== '') {
44094409
$rangeWS1 .= '!';
44104410
}
4411-
$rangeSheetRef = trim($rangeSheetRef, "'");
4411+
if (str_starts_with($rangeSheetRef, "'")) {
4412+
$rangeSheetRef = Worksheet::unApostrophizeTitle($rangeSheetRef);
4413+
}
44124414
[$rangeWS2, $val] = Worksheet::extractSheetTitle($val, true);
44134415
if ($rangeWS2 !== '') {
44144416
$rangeWS2 .= '!';
@@ -4766,18 +4768,18 @@ private function processTokenStack(mixed $tokens, ?string $cellID = null, ?Cell
47664768
}
47674769
}
47684770
if (str_contains($operand1Data['reference'] ?? '', '!')) {
4769-
[$sheet1, $operand1Data['reference']] = Worksheet::extractSheetTitle($operand1Data['reference'], true);
4771+
[$sheet1, $operand1Data['reference']] = Worksheet::extractSheetTitle($operand1Data['reference'], true, true);
47704772
} else {
47714773
$sheet1 = ($pCellWorksheet !== null) ? $pCellWorksheet->getTitle() : '';
47724774
}
47734775
$sheet1 ??= '';
47744776

4775-
[$sheet2, $operand2Data['reference']] = Worksheet::extractSheetTitle($operand2Data['reference'], true);
4777+
[$sheet2, $operand2Data['reference']] = Worksheet::extractSheetTitle($operand2Data['reference'], true, true);
47764778
if (empty($sheet2)) {
47774779
$sheet2 = $sheet1;
47784780
}
47794781

4780-
if (trim($sheet1, "'") === trim($sheet2, "'")) {
4782+
if ($sheet1 === $sheet2) {
47814783
if ($operand1Data['reference'] === null && $cell !== null) {
47824784
if (is_array($operand1Data['value'])) {
47834785
$operand1Data['reference'] = $cell->getCoordinate();
@@ -5495,7 +5497,7 @@ public function extractCellRange(string &$range = 'A1', ?Worksheet $worksheet =
54955497
$worksheetName = $worksheet->getTitle();
54965498

54975499
if (str_contains($range, '!')) {
5498-
[$worksheetName, $range] = Worksheet::extractSheetTitle($range, true);
5500+
[$worksheetName, $range] = Worksheet::extractSheetTitle($range, true, true);
54995501
$worksheet = ($this->spreadsheet === null) ? null : $this->spreadsheet->getSheetByName($worksheetName);
55005502
}
55015503

@@ -5557,7 +5559,7 @@ public function extractNamedRange(string &$range = 'A1', ?Worksheet $worksheet =
55575559

55585560
if ($worksheet !== null) {
55595561
if (str_contains($range, '!')) {
5560-
[$worksheetName, $range] = Worksheet::extractSheetTitle($range, true);
5562+
[$worksheetName, $range] = Worksheet::extractSheetTitle($range, true, true);
55615563
$worksheet = ($this->spreadsheet === null) ? null : $this->spreadsheet->getSheetByName($worksheetName);
55625564
}
55635565

src/PhpSpreadsheet/Calculation/Information/Value.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public static function isRef(mixed $value, ?Cell $cell = null): bool
4545

4646
$cellValue = Functions::trimTrailingRange($value);
4747
if (preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/ui', $cellValue) === 1) {
48-
[$worksheet, $cellValue] = Worksheet::extractSheetTitle($cellValue, true);
48+
[$worksheet, $cellValue] = Worksheet::extractSheetTitle($cellValue, true, true);
4949
if (!empty($worksheet) && $cell->getWorksheet()->getParentOrThrow()->getSheetByName($worksheet) === null) {
5050
return false;
5151
}

src/PhpSpreadsheet/Calculation/Internal/ExcelArrayPseudoFunctions.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public static function single(string $cellReference, Cell $cell): mixed
1515
{
1616
$worksheet = $cell->getWorksheet();
1717

18-
[$referenceWorksheetName, $referenceCellCoordinate] = Worksheet::extractSheetTitle($cellReference, true);
18+
[$referenceWorksheetName, $referenceCellCoordinate] = Worksheet::extractSheetTitle($cellReference, true, true);
1919
if (preg_match('/^([$]?[a-z]{1,3})([$]?([0-9]{1,7})):([$]?[a-z]{1,3})([$]?([0-9]{1,7}))$/i', "$referenceCellCoordinate", $matches) === 1) {
2020
$ourRow = $cell->getRow();
2121
$firstRow = (int) $matches[3];
@@ -44,7 +44,7 @@ public static function anchorArray(string $cellReference, Cell $cell): array|str
4444
//$coordinate = $cell->getCoordinate();
4545
$worksheet = $cell->getWorksheet();
4646

47-
[$referenceWorksheetName, $referenceCellCoordinate] = Worksheet::extractSheetTitle($cellReference, true);
47+
[$referenceWorksheetName, $referenceCellCoordinate] = Worksheet::extractSheetTitle($cellReference, true, true);
4848
$referenceCell = ($referenceWorksheetName === '')
4949
? $worksheet->getCell((string) $referenceCellCoordinate)
5050
: $worksheet->getParentOrThrow()

src/PhpSpreadsheet/Calculation/LookupRef/Helpers.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,7 @@ public static function extractWorksheet(string $cellAddress, Cell $cell): array
6161
{
6262
$sheetName = '';
6363
if (str_contains($cellAddress, '!')) {
64-
[$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
65-
$sheetName = trim($sheetName, "'");
64+
[$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true, true);
6665
}
6766

6867
$worksheet = ($sheetName !== '')

src/PhpSpreadsheet/Calculation/LookupRef/Offset.php

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
88
use PhpOffice\PhpSpreadsheet\Cell\Cell;
99
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
10+
use PhpOffice\PhpSpreadsheet\Worksheet\Validations;
1011
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
1112

1213
class Offset
@@ -55,19 +56,22 @@ public static function OFFSET(?string $cellAddress = null, mixed $rows = 0, mixe
5556
if (!is_object($cell)) {
5657
return ExcelError::REF();
5758
}
59+
$sheet = $cell->getParent()?->getParent(); // worksheet
60+
if ($sheet !== null) {
61+
$cellAddress = Validations::definedNameToCoordinate($cellAddress, $sheet);
62+
}
5863

5964
[$cellAddress, $worksheet] = self::extractWorksheet($cellAddress, $cell);
6065

6166
$startCell = $endCell = $cellAddress;
6267
if (strpos($cellAddress, ':')) {
6368
[$startCell, $endCell] = explode(':', $cellAddress);
6469
}
65-
[$startCellColumn, $startCellRow] = Coordinate::coordinateFromString($startCell);
66-
[$endCellColumn, $endCellRow] = Coordinate::coordinateFromString($endCell);
70+
[$startCellColumn, $startCellRow] = Coordinate::indexesFromString($startCell);
71+
[, $endCellRow, $endCellColumn] = Coordinate::indexesFromString($endCell);
6772

6873
$startCellRow += $rows;
69-
$startCellColumn = Coordinate::columnIndexFromString($startCellColumn) - 1;
70-
$startCellColumn += $columns;
74+
$startCellColumn += $columns - 1;
7175

7276
if (($startCellRow <= 0) || ($startCellColumn < 0)) {
7377
return ExcelError::REF();
@@ -103,8 +107,7 @@ private static function extractWorksheet(?string $cellAddress, Cell $cell): arra
103107

104108
$sheetName = '';
105109
if (str_contains($cellAddress, '!')) {
106-
[$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
107-
$sheetName = trim($sheetName, "'");
110+
[$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true, true);
108111
}
109112

110113
$worksheet = ($sheetName !== '')

src/PhpSpreadsheet/Chart/DataSeriesValues.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ public function refresh(Worksheet $worksheet, bool $flatten = true): void
446446
}
447447
unset($dataValue);
448448
} else {
449-
[$worksheet, $cellRange] = Worksheet::extractSheetTitle($this->dataSource, true);
449+
[, $cellRange] = Worksheet::extractSheetTitle($this->dataSource, true);
450450
$dimensions = Coordinate::rangeDimension(str_replace('$', '', $cellRange ?? ''));
451451
if (($dimensions[0] == 1) || ($dimensions[1] == 1)) {
452452
$this->dataValues = Functions::flattenArray($newDataValues);

src/PhpSpreadsheet/Reader/Gnumeric.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -525,8 +525,8 @@ private function processDefinedNames(?SimpleXMLElement $gnmXML): void
525525
continue;
526526
}
527527

528-
[$worksheetName] = Worksheet::extractSheetTitle($value, true);
529-
$worksheetName = trim($worksheetName, "'");
528+
$value = str_replace("\\'", "''", $value);
529+
[$worksheetName] = Worksheet::extractSheetTitle($value, true, true);
530530
$worksheet = $this->spreadsheet->getSheetByName($worksheetName);
531531
// Worksheet might still be null if we're only loading selected sheets rather than the full spreadsheet
532532
if ($worksheet !== null) {

src/PhpSpreadsheet/Reader/Ods/DefinedNames.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ protected function readDefinedExpressions(DOMElement $workbookData): void
6060
*/
6161
private function addDefinedName(string $baseAddress, string $definedName, string $value): void
6262
{
63-
[$sheetReference] = Worksheet::extractSheetTitle($baseAddress, true);
63+
[$sheetReference] = Worksheet::extractSheetTitle($baseAddress, true, true);
6464
$worksheet = $this->spreadsheet->getSheetByName($sheetReference);
6565
// Worksheet might still be null if we're only loading selected sheets rather than the full spreadsheet
6666
if ($worksheet !== null) {

src/PhpSpreadsheet/Reader/Xls/LoadSpreadsheet.php

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -588,8 +588,8 @@ protected function loadSpreadsheetFromFile2(string $filename, Xls $xls): Spreads
588588
// $range should look like one of these
589589
// Foo!$C$7:$J$66
590590
// Bar!$A$1:$IV$2
591-
$explodes = Worksheet::extractSheetTitle($range, true);
592-
$sheetName = trim($explodes[0], "'");
591+
$explodes = Worksheet::extractSheetTitle($range, true, true);
592+
$sheetName = (string) $explodes[0];
593593
if (!str_contains($explodes[1], ':')) {
594594
$explodes[1] = $explodes[1] . ':' . $explodes[1];
595595
}
@@ -617,8 +617,9 @@ protected function loadSpreadsheetFromFile2(string $filename, Xls $xls): Spreads
617617
// Sheet!$A$1:$B$65536
618618
// Sheet!$A$1:$IV$2
619619
if (str_contains($range, '!')) {
620-
$explodes = Worksheet::extractSheetTitle($range, true);
621-
if ($docSheet = $xls->spreadsheet->getSheetByName($explodes[0])) {
620+
$explodes = Worksheet::extractSheetTitle($range, true, true);
621+
$docSheet = $xls->spreadsheet->getSheetByName($explodes[0]);
622+
if ($docSheet) {
622623
$extractedRange = $explodes[1];
623624
$extractedRange = str_replace('$', '', $extractedRange);
624625

@@ -646,11 +647,9 @@ protected function loadSpreadsheetFromFile2(string $filename, Xls $xls): Spreads
646647
/** @var non-empty-string $formula */
647648
$formula = $definedName['formula'];
648649
if (str_contains($formula, '!')) {
649-
$explodes = Worksheet::extractSheetTitle($formula, true);
650-
if (
651-
($docSheet = $xls->spreadsheet->getSheetByName($explodes[0]))
652-
|| ($docSheet = $xls->spreadsheet->getSheetByName(trim($explodes[0], "'")))
653-
) {
650+
$explodes = Worksheet::extractSheetTitle($formula, true, true);
651+
$docSheet = $xls->spreadsheet->getSheetByName($explodes[0]);
652+
if ($docSheet) {
654653
$extractedRange = $explodes[1];
655654

656655
$localOnly = ($definedName['scope'] === 0) ? false : true;

0 commit comments

Comments
 (0)