From bfb694a73e95d58b05527aec6758667a9c085d7a Mon Sep 17 00:00:00 2001 From: Robin van der Vliet Date: Mon, 10 Nov 2025 21:31:05 +0100 Subject: [PATCH 01/13] Implement missing `INFO` function --- docs/references/function-list-by-category.md | 2 +- .../function-list-by-name-compact.md | 2 +- docs/references/function-list-by-name.md | 2 +- .../Calculation/FunctionArray.php | 3 +- .../Calculation/Information/Info.php | 30 +++++++++++++++++++ 5 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Information/Info.php diff --git a/docs/references/function-list-by-category.md b/docs/references/function-list-by-category.md index 22c5222ad1..c8aa192e28 100644 --- a/docs/references/function-list-by-category.md +++ b/docs/references/function-list-by-category.md @@ -189,7 +189,7 @@ Excel Function | PhpSpreadsheet Function -------------------------|-------------------------------------- CELL | **Not yet Implemented** ERROR.TYPE | \PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError::type -INFO | **Not yet Implemented** +INFO | \PhpOffice\PhpSpreadsheet\Calculation\Information\Info::getInfo ISBLANK | \PhpOffice\PhpSpreadsheet\Calculation\Information\Value::isBlank ISERR | \PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue::isErr ISERROR | \PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue::isError diff --git a/docs/references/function-list-by-name-compact.md b/docs/references/function-list-by-name-compact.md index 4df84d2935..e137d63486 100644 --- a/docs/references/function-list-by-name-compact.md +++ b/docs/references/function-list-by-name-compact.md @@ -299,7 +299,7 @@ IMSUM | ENGINEERING | Engineering\ComplexOperations IMTAN | ENGINEERING | Engineering\ComplexFunctions::IMTAN INDEX | LOOKUP_AND_REFERENCE | LookupRef\Matrix::index INDIRECT | LOOKUP_AND_REFERENCE | LookupRef\Indirect::INDIRECT -INFO | INFORMATION | **Not yet Implemented** +INFO | INFORMATION | Information\Info::getInfo INT | MATH_AND_TRIG | MathTrig\IntClass::evaluate INTERCEPT | STATISTICAL | Statistical\Trends::INTERCEPT INTRATE | FINANCIAL | Financial\Securities\Rates::interest diff --git a/docs/references/function-list-by-name.md b/docs/references/function-list-by-name.md index 35594a7109..1f6683b337 100644 --- a/docs/references/function-list-by-name.md +++ b/docs/references/function-list-by-name.md @@ -295,7 +295,7 @@ IMSUM | CATEGORY_ENGINEERING | \PhpOffice\PhpSpread IMTAN | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering\ComplexFunctions::IMTAN INDEX | CATEGORY_LOOKUP_AND_REFERENCE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef\Matrix::index INDIRECT | CATEGORY_LOOKUP_AND_REFERENCE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef\Indirect::INDIRECT -INFO | CATEGORY_INFORMATION | **Not yet Implemented** +INFO | CATEGORY_INFORMATION | \PhpOffice\PhpSpreadsheet\Calculation\Information\Info::getInfo INT | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig\IntClass::evaluate INTERCEPT | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical\Trends::INTERCEPT INTRATE | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet\Calculation\Financial\Securities\Rates::interest diff --git a/src/PhpSpreadsheet/Calculation/FunctionArray.php b/src/PhpSpreadsheet/Calculation/FunctionArray.php index 68c2ecd1cd..74e778fda2 100644 --- a/src/PhpSpreadsheet/Calculation/FunctionArray.php +++ b/src/PhpSpreadsheet/Calculation/FunctionArray.php @@ -1284,8 +1284,9 @@ class FunctionArray extends CalculationBase ], 'INFO' => [ 'category' => Category::CATEGORY_INFORMATION, - 'functionCall' => [Functions::class, 'DUMMY'], + 'functionCall' => [Information\Info::class, 'getInfo'], 'argumentCount' => '1', + 'passCellReference' => true, ], 'INT' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, diff --git a/src/PhpSpreadsheet/Calculation/Information/Info.php b/src/PhpSpreadsheet/Calculation/Information/Info.php new file mode 100644 index 0000000000..8ce8e34951 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Information/Info.php @@ -0,0 +1,30 @@ + $cell?->getWorksheetOrNull()?->getParent()?->getSheetCount() ?? 1, + 'osversion' => 'PHP ' . phpversion(), + 'recalc' => 'Automatic', + 'system' => 'PHP', + default => ExcelError::VALUE(), + }; + } +} From e9ec166018a19ee1cda13a7c4bf6102c322d4583 Mon Sep 17 00:00:00 2001 From: Robin van der Vliet Date: Mon, 10 Nov 2025 21:50:15 +0100 Subject: [PATCH 02/13] Add tests --- .../Functions/Information/InfoTest.php | 26 +++++++++++++ tests/data/Calculation/Information/INFO.php | 38 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php create mode 100644 tests/data/Calculation/Information/INFO.php diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php new file mode 100644 index 0000000000..0cff7c2869 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php @@ -0,0 +1,26 @@ +mightHaveException($expectedResult); + $sheet = $this->getSheet(); + $sheet->getCell('A1')->setValue($typeText); + $sheet->getCell('B1')->setValue('=INFO(A1)'); + $result = $sheet->getCell('B1')->getCalculatedValue(); + self::assertSame($expectedResult, $result); + } + + public static function providerINFO(): array + { + return require 'tests/data/Calculation/Information/INFO.php'; + } +} diff --git a/tests/data/Calculation/Information/INFO.php b/tests/data/Calculation/Information/INFO.php new file mode 100644 index 0000000000..4cd71daae1 --- /dev/null +++ b/tests/data/Calculation/Information/INFO.php @@ -0,0 +1,38 @@ + Date: Mon, 10 Nov 2025 21:54:17 +0100 Subject: [PATCH 03/13] Fix issues --- .../Calculation/Information/Info.php | 14 +++++++------- tests/data/Calculation/Information/INFO.php | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Information/Info.php b/src/PhpSpreadsheet/Calculation/Information/Info.php index 8ce8e34951..ffcbd55301 100644 --- a/src/PhpSpreadsheet/Calculation/Information/Info.php +++ b/src/PhpSpreadsheet/Calculation/Information/Info.php @@ -15,16 +15,16 @@ class Info * @param mixed $typeText String specifying the type of information to be returned * @param ?Cell $cell Cell from which spreadsheet information is retrieved * - * @return string The requested information about the current operating environment + * @return string|int The requested information about the current operating environment */ - public static function getInfo(mixed $typeText = '', ?Cell $cell = null): string + public static function getInfo(mixed $typeText = '', ?Cell $cell = null): string|int { return match (is_string($typeText) ? strtolower($typeText) : $typeText) { - 'numfile' => $cell?->getWorksheetOrNull()?->getParent()?->getSheetCount() ?? 1, - 'osversion' => 'PHP ' . phpversion(), - 'recalc' => 'Automatic', - 'system' => 'PHP', - default => ExcelError::VALUE(), + 'numfile' => $cell?->getWorksheetOrNull()?->getParent()?->getSheetCount() ?? 1, + 'osversion' => 'PHP ' . PHP_VERSION, + 'recalc' => 'Automatic', + 'system' => 'PHP', + default => ExcelError::VALUE(), }; } } diff --git a/tests/data/Calculation/Information/INFO.php b/tests/data/Calculation/Information/INFO.php index 4cd71daae1..4967999d96 100644 --- a/tests/data/Calculation/Information/INFO.php +++ b/tests/data/Calculation/Information/INFO.php @@ -9,7 +9,7 @@ ], [ 'osversion', - 'PHP ' . phpversion(), + 'PHP ' . PHP_VERSION, ], [ 'recalc', From 4fd2f4d55144671224634efcafc01db5a25122c3 Mon Sep 17 00:00:00 2001 From: Robin van der Vliet Date: Mon, 10 Nov 2025 22:00:38 +0100 Subject: [PATCH 04/13] Fix issues --- .../Calculation/Information/Info.php | 4 ++-- tests/data/Calculation/Information/INFO.php | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Information/Info.php b/src/PhpSpreadsheet/Calculation/Information/Info.php index ffcbd55301..ee12bf2913 100644 --- a/src/PhpSpreadsheet/Calculation/Information/Info.php +++ b/src/PhpSpreadsheet/Calculation/Information/Info.php @@ -15,9 +15,9 @@ class Info * @param mixed $typeText String specifying the type of information to be returned * @param ?Cell $cell Cell from which spreadsheet information is retrieved * - * @return string|int The requested information about the current operating environment + * @return int|string The requested information about the current operating environment */ - public static function getInfo(mixed $typeText = '', ?Cell $cell = null): string|int + public static function getInfo(mixed $typeText = '', ?Cell $cell = null): int|string { return match (is_string($typeText) ? strtolower($typeText) : $typeText) { 'numfile' => $cell?->getWorksheetOrNull()?->getParent()?->getSheetCount() ?? 1, diff --git a/tests/data/Calculation/Information/INFO.php b/tests/data/Calculation/Information/INFO.php index 4967999d96..48012eec1f 100644 --- a/tests/data/Calculation/Information/INFO.php +++ b/tests/data/Calculation/Information/INFO.php @@ -4,32 +4,32 @@ return [ [ - 'numfile', 1, + 'numfile', ], [ - 'osversion', 'PHP ' . PHP_VERSION, + 'osversion', ], [ - 'recalc', 'Automatic', + 'recalc', ], [ + 'Automatic', 'RECALC', - 'AUTOMATIC', ], [ - 'system', 'PHP', + 'system', ], [ - 1, '#VALUE!', + 1, ], [ - 'A', '#VALUE!', + 'A', ], [ '#VALUE!', From e18bf2a2efbf9bef7f294663b9fbe634e7682ab4 Mon Sep 17 00:00:00 2001 From: Robin van der Vliet Date: Mon, 10 Nov 2025 22:45:43 +0100 Subject: [PATCH 05/13] Fix tests --- .../Functions/Information/InfoTest.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php index 0cff7c2869..dbd826d98f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php @@ -4,19 +4,19 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Information; -use PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig\AllSetupTeardown; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; +use PHPUnit\Framework\TestCase; -class InfoTest extends AllSetupTeardown +class InfoTest extends TestCase { #[\PHPUnit\Framework\Attributes\DataProvider('providerINFO')] public function testINFO(mixed $expectedResult, string $typeText): void { - $this->mightHaveException($expectedResult); - $sheet = $this->getSheet(); - $sheet->getCell('A1')->setValue($typeText); - $sheet->getCell('B1')->setValue('=INFO(A1)'); - $result = $sheet->getCell('B1')->getCalculatedValue(); - self::assertSame($expectedResult, $result); + $calculation = Calculation::getInstance(); + + $formula = "=INFO($typeText)"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEquals($expectedResult, $result); } public static function providerINFO(): array From e929a94ef6c1f67182aadddecd480338b298b0ae Mon Sep 17 00:00:00 2001 From: Robin van der Vliet Date: Tue, 11 Nov 2025 23:17:46 +0100 Subject: [PATCH 06/13] Fix tests --- .../Calculation/Functions/Information/InfoTest.php | 10 ++++++---- tests/data/Calculation/Information/INFO.php | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php index dbd826d98f..0cacb17dc9 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php @@ -4,7 +4,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Information; -use PhpOffice\PhpSpreadsheet\Calculation\Calculation; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class InfoTest extends TestCase @@ -12,10 +12,12 @@ class InfoTest extends TestCase #[\PHPUnit\Framework\Attributes\DataProvider('providerINFO')] public function testINFO(mixed $expectedResult, string $typeText): void { - $calculation = Calculation::getInstance(); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + + $sheet->getCell('A1')->setValue('=INFO("' . $typeText . '")'); + $result = $sheet->getCell('A1')->getCalculatedValue(); - $formula = "=INFO($typeText)"; - $result = $calculation->_calculateFormulaValue($formula); self::assertEquals($expectedResult, $result); } diff --git a/tests/data/Calculation/Information/INFO.php b/tests/data/Calculation/Information/INFO.php index 48012eec1f..36e3eb5822 100644 --- a/tests/data/Calculation/Information/INFO.php +++ b/tests/data/Calculation/Information/INFO.php @@ -25,7 +25,7 @@ ], [ '#VALUE!', - 1, + '1', ], [ '#VALUE!', From ec9d343e8a80092ed07b661f8dd8428bb5886532 Mon Sep 17 00:00:00 2001 From: Robin van der Vliet Date: Tue, 11 Nov 2025 23:29:19 +0100 Subject: [PATCH 07/13] Remove test for unimplemented function, because it is implemented now --- .../TypeAttributePreservationTest.php | 80 ------------------- 1 file changed, 80 deletions(-) diff --git a/tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php b/tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php index ea6397f94f..ec9ca90086 100644 --- a/tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php +++ b/tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php @@ -94,84 +94,4 @@ public function testFormulaeNoPrecalc(string $format, array $values): void $spreadsheet->disconnectWorksheets(); $reloadedSpreadsheet->disconnectWorksheets(); } - - public function testUnimplementedFunctionXlsx(): void - { - $file = 'tests/data/Reader/XLSX/issue.3658.xlsx'; - $reader = new ReaderXlsx(); - $spreadsheet = $reader->load($file); - $sheet = $spreadsheet->getActiveSheet(); - $unimplemented = '=INFO("SYSTEM")'; - self::assertSame(124, $sheet->getCell('A2')->getOldCalculatedValue()); - self::assertSame('00123', $sheet->getCell('A3')->getOldCalculatedValue()); - self::assertSame($unimplemented, $sheet->getCell('A4')->getValue()); - self::assertSame('pcdos', $sheet->getCell('A4')->getCalculatedValue(), 'use oldCalculatedValue from read for unimplemented function'); - $sheet->getCell('D10')->setValue($unimplemented); - self::assertNull($sheet->getCell('D10')->getCalculatedValue(), 'return null for unimplemented function when old value unassigned'); - $spreadsheet->disconnectWorksheets(); - } - - public function testUnimplementedFunctionXls(): void - { - $file = 'tests/data/Reader/XLS/issue.3658.xls'; - $reader = new ReaderXls(); - $spreadsheet = $reader->load($file); - $sheet = $spreadsheet->getActiveSheet(); - $unimplemented = '=INFO("SYSTEM")'; - self::assertSame(124, $sheet->getCell('A2')->getOldCalculatedValue()); - self::assertSame('00123', $sheet->getCell('A3')->getOldCalculatedValue()); - self::assertSame($unimplemented, $sheet->getCell('A4')->getValue()); - self::assertSame('pcdos', $sheet->getCell('A4')->getCalculatedValue(), 'use oldCalculatedValue from read for unimplemented function'); - $sheet->getCell('D10')->setValue($unimplemented); - self::assertNull($sheet->getCell('D10')->getCalculatedValue(), 'return null for unimplemented function when old value unassigned'); - $spreadsheet->disconnectWorksheets(); - } - - public function testUnimplementedFunctionXml(): void - { - $file = 'tests/data/Reader/Xml/issue.3658.xml'; - $reader = new ReaderXml(); - $spreadsheet = $reader->load($file); - $sheet = $spreadsheet->getActiveSheet(); - $unimplemented = '=INFO("SYSTEM")'; - self::assertSame(124, $sheet->getCell('A2')->getOldCalculatedValue()); - self::assertSame('00123', $sheet->getCell('A3')->getOldCalculatedValue()); - self::assertSame($unimplemented, $sheet->getCell('A4')->getValue()); - self::assertSame('pcdos', $sheet->getCell('A4')->getCalculatedValue(), 'use oldCalculatedValue from read for unimplemented function'); - $sheet->getCell('D10')->setValue($unimplemented); - self::assertNull($sheet->getCell('D10')->getCalculatedValue(), 'return null for unimplemented function when old value unassigned'); - $spreadsheet->disconnectWorksheets(); - } - - public function testUnimplementedFunctionOds(): void - { - $file = 'tests/data/Reader/Ods/issue.3658.ods'; - $reader = new ReaderOds(); - $spreadsheet = $reader->load($file); - $sheet = $spreadsheet->getActiveSheet(); - $unimplemented = '=INFO("SYSTEM")'; - self::assertSame(124, $sheet->getCell('A2')->getOldCalculatedValue()); - self::assertSame('00123', $sheet->getCell('A3')->getOldCalculatedValue()); - self::assertSame($unimplemented, $sheet->getCell('A4')->getValue()); - self::assertSame('WNT', $sheet->getCell('A4')->getCalculatedValue(), 'use oldCalculatedValue from read for unimplemented function'); - $sheet->getCell('D10')->setValue($unimplemented); - self::assertNull($sheet->getCell('D10')->getCalculatedValue(), 'return null for unimplemented function when old value unassigned'); - $spreadsheet->disconnectWorksheets(); - } - - public function testUnimplementedFunctionSlk(): void - { - $file = 'tests/data/Reader/Slk/issue.3658.slk'; - $reader = new ReaderSlk(); - $spreadsheet = $reader->load($file); - $sheet = $spreadsheet->getActiveSheet(); - $unimplemented = '=INFO("SYSTEM")'; - self::assertSame(124, $sheet->getCell('A2')->getOldCalculatedValue()); - self::assertSame('00123', $sheet->getCell('A3')->getOldCalculatedValue()); - self::assertSame($unimplemented, $sheet->getCell('A4')->getValue()); - self::assertSame('pcdos', $sheet->getCell('A4')->getCalculatedValue(), 'use oldCalculatedValue from read for unimplemented function'); - $sheet->getCell('D10')->setValue($unimplemented); - self::assertNull($sheet->getCell('D10')->getCalculatedValue(), 'return null for unimplemented function when old value unassigned'); - $spreadsheet->disconnectWorksheets(); - } } From 99d24e2b6b816e6d868c2e9a5331cafe02f48a92 Mon Sep 17 00:00:00 2001 From: Robin van der Vliet Date: Tue, 11 Nov 2025 23:35:01 +0100 Subject: [PATCH 08/13] Remove unused imports --- .../Functional/TypeAttributePreservationTest.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php b/tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php index ec9ca90086..197d03045f 100644 --- a/tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php +++ b/tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php @@ -4,11 +4,6 @@ namespace PhpOffice\PhpSpreadsheetTests\Functional; -use PhpOffice\PhpSpreadsheet\Reader\Ods as ReaderOds; -use PhpOffice\PhpSpreadsheet\Reader\Slk as ReaderSlk; -use PhpOffice\PhpSpreadsheet\Reader\Xls as ReaderXls; -use PhpOffice\PhpSpreadsheet\Reader\Xlsx as ReaderXlsx; -use PhpOffice\PhpSpreadsheet\Reader\Xml as ReaderXml; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Writer\Xlsx as WriterXlsx; use PHPUnit\Framework\Attributes\DataProvider; From 92eacbeef674f43dadef54a81e84da3ce7c84ac7 Mon Sep 17 00:00:00 2001 From: Robin van der Vliet Date: Tue, 11 Nov 2025 23:44:44 +0100 Subject: [PATCH 09/13] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6508250927..877e335d7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). Thia is a - Unexpected Exception in Php DateTime. [Issue #4696](https://github.com/PHPOffice/PhpSpreadsheet/issues/4696) [Issue #917](https://github.com/PHPOffice/PhpSpreadsheet/issues/917) [PR #4697](https://github.com/PHPOffice/PhpSpreadsheet/pull/4697) - Add missing Dutch translation to translation file. [PR #4707](https://github.com/PHPOffice/PhpSpreadsheet/pull/4707) - Fix lots of typos throughout codebase. [PR #4705](https://github.com/PHPOffice/PhpSpreadsheet/pull/4705) +- Implement missing `INFO` function. [PR #4709](https://github.com/PHPOffice/PhpSpreadsheet/pull/4709) ## 2025-10-25 - 5.2.0 From 536c63e100c7e96f1afa40c7474a4fc8d0bee3ae Mon Sep 17 00:00:00 2001 From: Robin van der Vliet Date: Wed, 12 Nov 2025 18:15:11 +0100 Subject: [PATCH 10/13] =?UTF-8?q?Implement=20`=C3=ACnfoSupported`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Calculation/Information/Info.php | 7 ++ .../TypeAttributePreservationTest.php | 96 +++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/src/PhpSpreadsheet/Calculation/Information/Info.php b/src/PhpSpreadsheet/Calculation/Information/Info.php index ee12bf2913..fd4fb17c69 100644 --- a/src/PhpSpreadsheet/Calculation/Information/Info.php +++ b/src/PhpSpreadsheet/Calculation/Information/Info.php @@ -2,10 +2,13 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Information; +use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Cell\Cell; class Info { + public static bool $infoSupported = true; + /** * INFO. * @@ -19,6 +22,10 @@ class Info */ public static function getInfo(mixed $typeText = '', ?Cell $cell = null): int|string { + if (!self::$infoSupported) { + return Functions::DUMMY(); + } + return match (is_string($typeText) ? strtolower($typeText) : $typeText) { 'numfile' => $cell?->getWorksheetOrNull()?->getParent()?->getSheetCount() ?? 1, 'osversion' => 'PHP ' . PHP_VERSION, diff --git a/tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php b/tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php index 197d03045f..0c4a99a608 100644 --- a/tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php +++ b/tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php @@ -4,12 +4,28 @@ namespace PhpOffice\PhpSpreadsheetTests\Functional; +use PhpOffice\PhpSpreadsheet\Calculation\Information\Info; +use PhpOffice\PhpSpreadsheet\Reader\Ods as ReaderOds; +use PhpOffice\PhpSpreadsheet\Reader\Slk as ReaderSlk; +use PhpOffice\PhpSpreadsheet\Reader\Xls as ReaderXls; +use PhpOffice\PhpSpreadsheet\Reader\Xlsx as ReaderXlsx; +use PhpOffice\PhpSpreadsheet\Reader\Xml as ReaderXml; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Writer\Xlsx as WriterXlsx; use PHPUnit\Framework\Attributes\DataProvider; class TypeAttributePreservationTest extends AbstractFunctional { + protected function setUp(): void + { + Info::$infoSupported = false; + } + + protected function tearDown(): void + { + Info::$infoSupported = true; + } + public static function providerFormulae(): array { $formats = ['Xlsx']; @@ -89,4 +105,84 @@ public function testFormulaeNoPrecalc(string $format, array $values): void $spreadsheet->disconnectWorksheets(); $reloadedSpreadsheet->disconnectWorksheets(); } + + public function testUnimplementedFunctionXlsx(): void + { + $file = 'tests/data/Reader/XLSX/issue.3658.xlsx'; + $reader = new ReaderXlsx(); + $spreadsheet = $reader->load($file); + $sheet = $spreadsheet->getActiveSheet(); + $unimplemented = '=INFO("SYSTEM")'; + self::assertSame(124, $sheet->getCell('A2')->getOldCalculatedValue()); + self::assertSame('00123', $sheet->getCell('A3')->getOldCalculatedValue()); + self::assertSame($unimplemented, $sheet->getCell('A4')->getValue()); + self::assertSame('pcdos', $sheet->getCell('A4')->getCalculatedValue(), 'use oldCalculatedValue from read for unimplemented function'); + $sheet->getCell('D10')->setValue($unimplemented); + self::assertNull($sheet->getCell('D10')->getCalculatedValue(), 'return null for unimplemented function when old value unassigned'); + $spreadsheet->disconnectWorksheets(); + } + + public function testUnimplementedFunctionXls(): void + { + $file = 'tests/data/Reader/XLS/issue.3658.xls'; + $reader = new ReaderXls(); + $spreadsheet = $reader->load($file); + $sheet = $spreadsheet->getActiveSheet(); + $unimplemented = '=INFO("SYSTEM")'; + self::assertSame(124, $sheet->getCell('A2')->getOldCalculatedValue()); + self::assertSame('00123', $sheet->getCell('A3')->getOldCalculatedValue()); + self::assertSame($unimplemented, $sheet->getCell('A4')->getValue()); + self::assertSame('pcdos', $sheet->getCell('A4')->getCalculatedValue(), 'use oldCalculatedValue from read for unimplemented function'); + $sheet->getCell('D10')->setValue($unimplemented); + self::assertNull($sheet->getCell('D10')->getCalculatedValue(), 'return null for unimplemented function when old value unassigned'); + $spreadsheet->disconnectWorksheets(); + } + + public function testUnimplementedFunctionXml(): void + { + $file = 'tests/data/Reader/Xml/issue.3658.xml'; + $reader = new ReaderXml(); + $spreadsheet = $reader->load($file); + $sheet = $spreadsheet->getActiveSheet(); + $unimplemented = '=INFO("SYSTEM")'; + self::assertSame(124, $sheet->getCell('A2')->getOldCalculatedValue()); + self::assertSame('00123', $sheet->getCell('A3')->getOldCalculatedValue()); + self::assertSame($unimplemented, $sheet->getCell('A4')->getValue()); + self::assertSame('pcdos', $sheet->getCell('A4')->getCalculatedValue(), 'use oldCalculatedValue from read for unimplemented function'); + $sheet->getCell('D10')->setValue($unimplemented); + self::assertNull($sheet->getCell('D10')->getCalculatedValue(), 'return null for unimplemented function when old value unassigned'); + $spreadsheet->disconnectWorksheets(); + } + + public function testUnimplementedFunctionOds(): void + { + $file = 'tests/data/Reader/Ods/issue.3658.ods'; + $reader = new ReaderOds(); + $spreadsheet = $reader->load($file); + $sheet = $spreadsheet->getActiveSheet(); + $unimplemented = '=INFO("SYSTEM")'; + self::assertSame(124, $sheet->getCell('A2')->getOldCalculatedValue()); + self::assertSame('00123', $sheet->getCell('A3')->getOldCalculatedValue()); + self::assertSame($unimplemented, $sheet->getCell('A4')->getValue()); + self::assertSame('WNT', $sheet->getCell('A4')->getCalculatedValue(), 'use oldCalculatedValue from read for unimplemented function'); + $sheet->getCell('D10')->setValue($unimplemented); + self::assertNull($sheet->getCell('D10')->getCalculatedValue(), 'return null for unimplemented function when old value unassigned'); + $spreadsheet->disconnectWorksheets(); + } + + public function testUnimplementedFunctionSlk(): void + { + $file = 'tests/data/Reader/Slk/issue.3658.slk'; + $reader = new ReaderSlk(); + $spreadsheet = $reader->load($file); + $sheet = $spreadsheet->getActiveSheet(); + $unimplemented = '=INFO("SYSTEM")'; + self::assertSame(124, $sheet->getCell('A2')->getOldCalculatedValue()); + self::assertSame('00123', $sheet->getCell('A3')->getOldCalculatedValue()); + self::assertSame($unimplemented, $sheet->getCell('A4')->getValue()); + self::assertSame('pcdos', $sheet->getCell('A4')->getCalculatedValue(), 'use oldCalculatedValue from read for unimplemented function'); + $sheet->getCell('D10')->setValue($unimplemented); + self::assertNull($sheet->getCell('D10')->getCalculatedValue(), 'return null for unimplemented function when old value unassigned'); + $spreadsheet->disconnectWorksheets(); + } } From 07d68b3bc8fa81484e0000eb8f64fafb54c1ce25 Mon Sep 17 00:00:00 2001 From: Robin van der Vliet Date: Thu, 13 Nov 2025 19:03:21 +0100 Subject: [PATCH 11/13] Add support for remaining types --- .../Calculation/Information/Info.php | 7 ++++++ tests/data/Calculation/Information/INFO.php | 24 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/PhpSpreadsheet/Calculation/Information/Info.php b/src/PhpSpreadsheet/Calculation/Information/Info.php index fd4fb17c69..61138fe1ea 100644 --- a/src/PhpSpreadsheet/Calculation/Information/Info.php +++ b/src/PhpSpreadsheet/Calculation/Information/Info.php @@ -7,6 +7,9 @@ class Info { + /** + * @internal + */ public static bool $infoSupported = true; /** @@ -27,10 +30,14 @@ public static function getInfo(mixed $typeText = '', ?Cell $cell = null): int|st } return match (is_string($typeText) ? strtolower($typeText) : $typeText) { + 'directory' => '/', 'numfile' => $cell?->getWorksheetOrNull()?->getParent()?->getSheetCount() ?? 1, + 'origin' => '$A:$A$1', 'osversion' => 'PHP ' . PHP_VERSION, 'recalc' => 'Automatic', + 'release' => PHP_VERSION, 'system' => 'PHP', + 'memavail', 'memused', 'totmem' => ExcelError::NA(), default => ExcelError::VALUE(), }; } diff --git a/tests/data/Calculation/Information/INFO.php b/tests/data/Calculation/Information/INFO.php index 36e3eb5822..9b46d7e313 100644 --- a/tests/data/Calculation/Information/INFO.php +++ b/tests/data/Calculation/Information/INFO.php @@ -3,10 +3,18 @@ declare(strict_types=1); return [ + [ + '/', + 'directory', + ], [ 1, 'numfile', ], + [ + '$A:$A$1', + 'origin', + ], [ 'PHP ' . PHP_VERSION, 'osversion', @@ -19,10 +27,26 @@ 'Automatic', 'RECALC', ], + [ + PHP_VERSION, + 'release', + ], [ 'PHP', 'system', ], + [ + '#N/A', + 'memavail', + ], + [ + '#N/A', + 'memused', + ], + [ + '#N/A', + 'totmem', + ], [ '#VALUE!', '1', From 70802fafe6bd598a69aca3b7f5a9ac5697e69a51 Mon Sep 17 00:00:00 2001 From: Robin van der Vliet Date: Thu, 13 Nov 2025 20:43:41 +0100 Subject: [PATCH 12/13] Add another test --- .../Calculation/Functions/Information/InfoTest.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php index 0cacb17dc9..d114e62e0d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php @@ -25,4 +25,17 @@ public static function providerINFO(): array { return require 'tests/data/Calculation/Information/INFO.php'; } + + public function testINFONumfileWithThreeSheets(): void + { + $spreadsheet = new Spreadsheet(); + $spreadsheet->createSheet(); + $spreadsheet->createSheet(); + $sheet = $spreadsheet->getActiveSheet(); + + $sheet->getCell('A1')->setValue('=INFO("numfile")'); + $result = $sheet->getCell('A1')->getCalculatedValue(); + + self::assertEquals(3, $result); + } } From 55098edf99635b25098e7ec1cf9e43f97cdda5b4 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Thu, 13 Nov 2025 21:07:19 -0800 Subject: [PATCH 13/13] Minor Touchup --- .../Calculation/Functions/Information/InfoTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php index d114e62e0d..966cedc9fc 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/InfoTest.php @@ -18,7 +18,8 @@ public function testINFO(mixed $expectedResult, string $typeText): void $sheet->getCell('A1')->setValue('=INFO("' . $typeText . '")'); $result = $sheet->getCell('A1')->getCalculatedValue(); - self::assertEquals($expectedResult, $result); + self::assertSame($expectedResult, $result); + $spreadsheet->disconnectWorksheets(); } public static function providerINFO(): array @@ -36,6 +37,7 @@ public function testINFONumfileWithThreeSheets(): void $sheet->getCell('A1')->setValue('=INFO("numfile")'); $result = $sheet->getCell('A1')->getCalculatedValue(); - self::assertEquals(3, $result); + self::assertSame(3, $result); + $spreadsheet->disconnectWorksheets(); } }