Skip to content

Commit 20ac2f1

Browse files
authored
Merge pull request #4527 from oleibman/issue4522
Minor Breaking Change to DefaultValueBinder
2 parents ac4befd + 6b3cb42 commit 20ac2f1

File tree

2 files changed

+33
-12
lines changed

2 files changed

+33
-12
lines changed

src/PhpSpreadsheet/Cell/DefaultValueBinder.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PhpOffice\PhpSpreadsheet\Cell;
44

5+
use Composer\Pcre\Preg;
56
use DateTimeInterface;
67
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
78
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalculationException;
@@ -12,6 +13,9 @@
1213

1314
class DefaultValueBinder implements IValueBinder
1415
{
16+
// 123 456 789 012 345
17+
private const FIFTEEN_NINES = 999_999_999_999_999;
18+
1519
/**
1620
* Bind value to a cell.
1721
*
@@ -49,6 +53,9 @@ public static function dataTypeForValue(mixed $value): string
4953
if ($value === null) {
5054
return DataType::TYPE_NULL;
5155
}
56+
if (is_int($value) && abs($value) > self::FIFTEEN_NINES) {
57+
return DataType::TYPE_STRING;
58+
}
5259
if (is_float($value) || is_int($value)) {
5360
return DataType::TYPE_NUMERIC;
5461
}
@@ -89,13 +96,18 @@ public static function dataTypeForValue(mixed $value): string
8996

9097
return DataType::TYPE_FORMULA;
9198
}
92-
if (preg_match('/^[\+\-]?(\d+\.?\d*|\d*\.?\d+)([Ee][\-\+]?[0-2]?\d{1,3})?$/', $value)) {
99+
if (Preg::isMatch('/^[\+\-]?(\d+\.?\d*|\d*\.?\d+)([Ee][\-\+]?[0-2]?\d{1,3})?$/', $value)) {
93100
$tValue = ltrim($value, '+-');
94101
if (strlen($tValue) > 1 && $tValue[0] === '0' && $tValue[1] !== '.') {
95102
return DataType::TYPE_STRING;
96-
} elseif ((!str_contains($value, '.')) && ($value > PHP_INT_MAX)) {
97-
return DataType::TYPE_STRING;
98-
} elseif (!is_numeric($value)) {
103+
}
104+
if (!Preg::isMatch('/[eE.]/', $value)) {
105+
$aValue = abs((float) $value);
106+
if ($aValue > self::FIFTEEN_NINES) {
107+
return DataType::TYPE_STRING;
108+
}
109+
}
110+
if (!is_numeric($value)) {
99111
return DataType::TYPE_STRING;
100112
}
101113

tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,21 @@
88
use PhpOffice\PhpSpreadsheet\Shared\File;
99
use PhpOffice\PhpSpreadsheet\Spreadsheet;
1010
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as Writer;
11+
use PHPUnit\Framework\Attributes\DataProvider;
1112
use PHPUnit\Framework\TestCase;
1213

1314
class FloatsRetainedTest extends TestCase
1415
{
15-
#[\PHPUnit\Framework\Attributes\DataProvider('providerIntyFloatsRetainedByWriter')]
16-
public function testIntyFloatsRetainedByWriter(float|int $value): void
16+
#[DataProvider('providerIntyFloatsRetainedByWriter')]
17+
public function testIntyFloatsRetainedByWriter(float|int $value, mixed $expected = null): void
1718
{
19+
if ($expected === null) {
20+
$expected = $value;
21+
}
1822
$outputFilename = File::temporaryFilename();
1923
$spreadsheet = new Spreadsheet();
20-
$spreadsheet->getActiveSheet()->getCell('A1')->setValue($value);
24+
$spreadsheet->getActiveSheet()
25+
->getCell('A1')->setValue($value);
2126

2227
$writer = new Writer($spreadsheet);
2328
$writer->save($outputFilename);
@@ -27,7 +32,11 @@ public function testIntyFloatsRetainedByWriter(float|int $value): void
2732
$spreadsheet2 = $reader->load($outputFilename);
2833
unlink($outputFilename);
2934

30-
self::assertSame($value, $spreadsheet2->getActiveSheet()->getCell('A1')->getValue());
35+
self::assertSame(
36+
$expected,
37+
$spreadsheet2->getActiveSheet()
38+
->getCell('A1')->getValue()
39+
);
3140
$spreadsheet2->disconnectWorksheets();
3241
}
3342

@@ -44,10 +53,10 @@ public static function providerIntyFloatsRetainedByWriter(): array
4453
[1.3e-10],
4554
[1e10],
4655
[3.00000000000000000001],
47-
[99999999999999999],
48-
[99999999999999999.0],
49-
[999999999999999999999999999999999999999999],
50-
[999999999999999999999999999999999999999999.0],
56+
'int but too much precision for Excel' => [99_999_999_999_999_999, '99999999999999999'],
57+
[99_999_999_999_999_999.0],
58+
'int > PHP_INT_MAX so stored as float' => [999_999_999_999_999_999_999_999_999_999_999_999_999_999],
59+
[999_999_999_999_999_999_999_999_999_999_999_999_999_999.0],
5160
];
5261
}
5362
}

0 commit comments

Comments
 (0)