Skip to content

Commit

Permalink
Modify XLSX RW to keep decimal for floats with a zero decimal part
Browse files Browse the repository at this point in the history
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.

Closes #1262
  • Loading branch information
rtek authored and PowerKiKi committed Nov 30, 2019
1 parent 9552172 commit cf30c2a
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).

- FLOOR() function accept negative number and negative significance [#1245](https://github.com/PHPOffice/PhpSpreadsheet/pull/1245)
- Correct column style even when using rowspan [#1249](https://github.com/PHPOffice/PhpSpreadsheet/pull/1249)
- XLSX reader/writer keep decimal for floats with a zero decimal part [#1262](https://github.com/PHPOffice/PhpSpreadsheet/pull/1262)

## [1.10.0] - 2019-11-18

Expand Down
9 changes: 0 additions & 9 deletions src/PhpSpreadsheet/Reader/Xlsx.php
Original file line number Diff line number Diff line change
Expand Up @@ -729,15 +729,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();
Expand Down
7 changes: 7 additions & 0 deletions src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand Down
54 changes: 54 additions & 0 deletions tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx;

use PhpOffice\PhpSpreadsheet\Reader\Xlsx as Reader;
use PhpOffice\PhpSpreadsheet\Settings;
use PhpOffice\PhpSpreadsheet\Shared\File;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as Writer;
use PHPUnit\Framework\TestCase;

class FloatsRetainedTest extends TestCase
{
/**
* @dataProvider providerIntyFloatsRetainedByWriter
*
* @param float|int $value
*/
public function testIntyFloatsRetainedByWriter($value)
{
$outputFilename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test');
Settings::setLibXmlLoaderOptions(null);
$sheet = new Spreadsheet();
$sheet->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],
];
}
}

0 comments on commit cf30c2a

Please sign in to comment.