From e5697fbc4eabb17fe07d70218c4c90d9d9faf130 Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Tue, 4 Apr 2023 07:29:47 -0700
Subject: [PATCH] Xlsx Reader Formula with quotePrefix (#3497)
Fix #3495. This seems to be a bug in Excel, one which it manages to cover up but PhpSpreadsheet is affected. User enters a formula preceded by an apostrophe into a cell. Excel turns on `quotePrefix` style and stores the data as a string rather than a formula. User now enters a formula not preceded by an apostrophe into the same cell. Excel stores it is a formula but does not turn `quotePrefix` off. When the spreadsheet is saved, the cell's style specifies `quotePrefix`, but the cell's content indicates it's a formula. Till now, PhpSpreadsheet sees that quotePrefix is set, and therefore treats the cell's contents as a string rather than a formula. This PR will change that behavior so that quotePrefix is automatically turned off when Xlsx Reader sees that the cell indicates that it is a formula.
---
src/PhpSpreadsheet/Reader/Xlsx.php | 4 ++
.../Reader/Xlsx/Issue3464Test.php | 4 +-
.../Reader/Xlsx/Issue3495Test.php | 57 ++++++++++++++++++
tests/data/Reader/XLSX/issue.3495d.xlsx | Bin 0 -> 10916 bytes
4 files changed, 64 insertions(+), 1 deletion(-)
create mode 100644 tests/PhpSpreadsheetTests/Reader/Xlsx/Issue3495Test.php
create mode 100644 tests/data/Reader/XLSX/issue.3495d.xlsx
diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php
index 4f7fbaaae..3a76b05b5 100644
--- a/src/PhpSpreadsheet/Reader/Xlsx.php
+++ b/src/PhpSpreadsheet/Reader/Xlsx.php
@@ -945,6 +945,10 @@ class Xlsx extends BaseReader
// no style index means 0, it seems
$cell->setXfIndex(isset($styles[(int) ($cAttr['s'])]) ?
(int) ($cAttr['s']) : 0);
+ // issue 3495
+ if ($cell->getDataType() === DataType::TYPE_FORMULA) {
+ $cell->getStyle()->setQuotePrefix(false);
+ }
}
}
++$rowIndex;
diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue3464Test.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue3464Test.php
index f08af4863..90a34f3d5 100644
--- a/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue3464Test.php
+++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue3464Test.php
@@ -18,7 +18,8 @@ class Issue3464Test extends \PHPUnit\Framework\TestCase
$objReader = IOFactory::createReader($inputFileType);
$objReader->setReadEmptyCells(false);
- $sheet = $objReader->load(self::$testbook)->getActiveSheet();
+ $spreadsheet = $objReader->load(self::$testbook);
+ $sheet = $spreadsheet->getActiveSheet();
$rickText = $sheet->getCell([1, 1])->getValue();
self::assertInstanceOf(RichText::class, $rickText);
@@ -34,5 +35,6 @@ class Issue3464Test extends \PHPUnit\Framework\TestCase
$font = $elements[1]->getFont();
self::assertNotNull($font);
self::assertEquals('ff2600', $font->getColor()->getRGB());
+ $spreadsheet->disconnectWorksheets();
}
}
diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue3495Test.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue3495Test.php
new file mode 100644
index 000000000..b85d27e11
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue3495Test.php
@@ -0,0 +1,57 @@
+'
+ . ''
+ . '',
+ $data
+ );
+ }
+ $data = file_get_contents($file2);
+ if ($data === false) {
+ self::fail('Unable to read file');
+ } else {
+ // cells B1, C1, D1 all nominally use quotePrefix s="1"
+ self::assertStringContainsString('', $data);
+ self::assertStringContainsString('', $data);
+ self::assertStringContainsString('', $data);
+ }
+ }
+
+ public function testFormulaDespiteQuotePrefix(): void
+ {
+ $reader = new Xlsx();
+ $spreadsheet = $reader->load(self::$testbook);
+ $sheet = $spreadsheet->getActiveSheet();
+ self::assertSame('=2+3', $sheet->getCell('B1')->getValue());
+ self::assertSame('=1+2', $sheet->getCell('C1')->getValue());
+ self::assertSame('3', $sheet->getCell('D1')->getValue());
+ self::assertSame(5, $sheet->getCell('B1')->getCalculatedValue());
+ self::assertSame('=1+2', $sheet->getCell('C1')->getCalculatedValue());
+ self::assertSame('3', $sheet->getCell('D1')->getCalculatedValue());
+ $spreadsheet->disconnectWorksheets();
+ }
+}
diff --git a/tests/data/Reader/XLSX/issue.3495d.xlsx b/tests/data/Reader/XLSX/issue.3495d.xlsx
new file mode 100644
index 0000000000000000000000000000000000000000..ac5c2e7cb7df567f9feb7ec4e5757a2dea12eca6
GIT binary patch
literal 10916
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