From be18bd0d307de5e671cecd70cb0320ff9d568b50 Mon Sep 17 00:00:00 2001 From: rtek Date: Mon, 25 Nov 2019 11:00:15 -0500 Subject: [PATCH] Modify XLSX RW to keep decimal for floats with a zero decimal part Prior to 1.10, all numeric values where read as floats. In 1.10 numeric values are read using 0 + x, which relies on PHP type juggling rules. As a result, float(0.0) is written as string('0'), then read back as int(0). This fix causes the writer to retain the the decimal for float values such that a reader can differentiate floats from ints. --- src/PhpSpreadsheet/Reader/Xlsx.php | 9 ---- src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php | 7 +++ .../Writer/Xlsx/FloatsRetainedTest.php | 54 +++++++++++++++++++ 3 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index 4c10750524..428961dd15 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -727,15 +727,6 @@ public function load($pFilename) // read empty cells or the cells are not empty if ($this->readEmptyCells || ($value !== null && $value !== '')) { - // Check for numeric values - if (is_numeric($value) && $cellDataType != 's') { - if ($value == (int) $value) { - $value = (int) $value; - } elseif ($value == (float) $value) { - $value = (float) $value; - } - } - // Rich text? if ($value instanceof RichText && $this->readDataOnly) { $value = $value->getPlainText(); diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php index c8e7062da0..f460c0f12c 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php @@ -1135,6 +1135,13 @@ private function writeCell(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet break; case 'n': // Numeric + //force a decimal to be written if the type is float + if (is_float($cellValue)) { + $cellValue = (string) $cellValue; + if (strpos($cellValue, '.') === false) { + $cellValue = $cellValue . '.0'; + } + } // force point as decimal separator in case current locale uses comma $objWriter->writeElement('v', str_replace(',', '.', $cellValue)); diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php new file mode 100644 index 0000000000..521cc47f0a --- /dev/null +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php @@ -0,0 +1,54 @@ +getActiveSheet()->getCell('A1')->setValue($value); + + $writer = new Writer($sheet); + $writer->save($outputFilename); + + $reader = new Reader(); + $sheet = $reader->load($outputFilename); + + $this->assertSame($value, $sheet->getActiveSheet()->getCell('A1')->getValue()); + } + + public function providerIntyFloatsRetainedByWriter() + { + return [ + [-1.0], + [-1], + [0.0], + [0], + [1.0], + [1], + [1e-3], + [1.3e-10], + [1e10], + [3.00000000000000000001], + [99999999999999999], + [99999999999999999.0], + [999999999999999999999999999999999999999999], + [999999999999999999999999999999999999999999.0], + ]; + } +}