Skip to content

Commit a921d24

Browse files
authored
Merge branch 'master' into pr1449
2 parents 1f5c308 + 37bb153 commit a921d24

File tree

14 files changed

+275
-36
lines changed

14 files changed

+275
-36
lines changed

CHANGELOG.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,32 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com)
66
and this project adheres to [Semantic Versioning](https://semver.org).
77

8-
## 2024-09-29 - 3.0.0
8+
## TBD - 3.4.0
9+
10+
### Added
11+
12+
- Nothing yet.
13+
14+
### Changed
15+
16+
- Nothing yet.
17+
18+
### Deprecated
19+
20+
- IREADER::SKIP_EMPTY_CELLS - use its alias IGNORE_EMPTY_CELLS instead.
21+
22+
### Moved
23+
24+
- Nothing yet.
25+
26+
### Fixed
27+
28+
- Xls Writer Condtional Rules Applied to Whole Rows or Columns. [Issue #3185](https://github.com/PHPOffice/PhpSpreadsheet/issues/3185) [PR #4152](https://github.com/PHPOffice/PhpSpreadsheet/pull/4152)
29+
- Xlsx Writer Duplicate ContentTypes Entry for Background Image. [Issue #4179](https://github.com/PHPOffice/PhpSpreadsheet/issues/4179) [PR #4180](https://github.com/PHPOffice/PhpSpreadsheet/pull/4180)
30+
- Check strictNullComparison outside of loops. [PR #3347](https://github.com/PHPOffice/PhpSpreadsheet/pull/3347)
31+
- SUMIFS Does Not Require xlfn. [Issue #4182](https://github.com/PHPOffice/PhpSpreadsheet/issues/4182) [PR #4186](https://github.com/PHPOffice/PhpSpreadsheet/pull/4186)
32+
33+
## 2024-09-29 - 3.3.0 (no 3.0.\*, 3.1.\*, 3.2.\*)
934

1035
### Dynamic Arrays
1136

composer.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/topics/reading-and-writing-to-file.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,19 +1113,19 @@ Flags that are available that can be passed to the Reader in this way include:
11131113

11141114
- $reader::LOAD_WITH_CHARTS
11151115
- $reader::READ_DATA_ONLY
1116-
- $reader::IGNORE_EMPTY_CELLS
1117-
- $reader::SKIP_EMPTY_CELLS (synonym for IGNORE_EMPTY_CELLS)
1118-
1119-
| Readers | LOAD_WITH_CHARTS | READ_DATA_ONLY | IGNORE_EMPTY_CELLS |
1120-
|----------|------------------|----------------|--------------------|
1121-
| Xlsx | YES | YES | YES |
1122-
| Xls | NO | YES | YES |
1123-
| Xml | NO | NO | NO |
1124-
| Ods | NO | YES | NO |
1125-
| Gnumeric | NO | YES | NO |
1126-
| Html | N/A | N/A | N/A |
1127-
| Slk | N/A | NO | NO |
1128-
| Csv | N/A | NO | NO |
1116+
- $reader::IGNORE_EMPTY_CELLS
1117+
- $reader::IGNORE_ROWS_WITH_NO_CELLS
1118+
1119+
| Readers | LOAD_WITH_CHARTS | READ_DATA_ONLY | IGNORE_EMPTY_CELLS | IGNORE_ROWS_WITH_NO_CELLS |
1120+
|----------|------------------|----------------|--------------------|---------------------------|
1121+
| Xlsx | YES | YES | YES | YES |
1122+
| Xls | NO | YES | YES | NO |
1123+
| Xml | NO | NO | NO | NO |
1124+
| Ods | NO | YES | NO | NO |
1125+
| Gnumeric | NO | YES | NO | NO |
1126+
| Html | N/A | N/A | N/A | N/A |
1127+
| Slk | N/A | NO | NO | NO |
1128+
| Csv | N/A | NO | NO | NO |
11291129

11301130
Likewise, when saving a file using a Writer, loaded charts will not be saved unless you explicitly tell the Writer to include them:
11311131

@@ -1162,5 +1162,5 @@ Two or more flags can be passed together using PHP's `|` operator.
11621162

11631163
```php
11641164
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReaderForFile("myExampleFile.xlsx");
1165-
$reader->load("spreadsheetWithCharts.xlsx", $reader::READ_DATA_ONLY | $reader::SKIP_EMPTY_CELLS);
1165+
$reader->load("spreadsheetWithCharts.xlsx", $reader::READ_DATA_ONLY | $reader::IGNORE_EMPTY_CELLS);
11661166
```

src/PhpSpreadsheet/Reader/BaseReader.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ abstract class BaseReader implements IReader
1919

2020
/**
2121
* Read empty cells?
22-
* Identifies whether the Reader should read data values for cells all cells, or should ignore cells containing
22+
* Identifies whether the Reader should read data values for all cells, or should ignore cells containing
2323
* null value or empty string.
2424
*/
2525
protected bool $readEmptyCells = true;
@@ -166,7 +166,7 @@ protected function processFlags(int $flags): void
166166
if (((bool) ($flags & self::READ_DATA_ONLY)) === true) {
167167
$this->setReadDataOnly(true);
168168
}
169-
if (((bool) ($flags & self::SKIP_EMPTY_CELLS) || (bool) ($flags & self::IGNORE_EMPTY_CELLS)) === true) {
169+
if (((bool) ($flags & self::IGNORE_EMPTY_CELLS)) === true) {
170170
$this->setReadEmptyCells(false);
171171
}
172172
if (((bool) ($flags & self::IGNORE_ROWS_WITH_NO_CELLS)) === true) {

src/PhpSpreadsheet/Reader/IReader.php

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,36 @@
66

77
interface IReader
88
{
9+
/**
10+
* Flag used to load the charts.
11+
*
12+
* This flag is supported only for some formats.
13+
*/
914
public const LOAD_WITH_CHARTS = 1;
1015

16+
/**
17+
* Flag used to read data only, not style or structure information.
18+
*/
1119
public const READ_DATA_ONLY = 2;
1220

13-
public const SKIP_EMPTY_CELLS = 4;
21+
/**
22+
* @deprecated 3.4.0 use IGNORE_EMPTY_CELLS instead.
23+
*/
24+
public const SKIP_EMPTY_CELLS = self::IGNORE_EMPTY_CELLS;
25+
26+
/**
27+
* Flag used to ignore empty cells when reading.
28+
*
29+
* The ignored cells will not be instantiated.
30+
*/
1431
public const IGNORE_EMPTY_CELLS = 4;
1532

33+
/**
34+
* Flag used to ignore rows without cells.
35+
*
36+
* This flag is supported only for some formats.
37+
* This can heavily improve performance for some files.
38+
*/
1639
public const IGNORE_ROWS_WITH_NO_CELLS = 8;
1740

1841
public function __construct();
@@ -119,7 +142,7 @@ public function setReadFilter(IReadFilter $readFilter): self;
119142
* @param int $flags Flags that can change the behaviour of the Writer:
120143
* self::LOAD_WITH_CHARTS Load any charts that are defined (if the Reader supports Charts)
121144
* self::READ_DATA_ONLY Read only data, not style or structure information, from the file
122-
* self::SKIP_EMPTY_CELLS Don't read empty cells (cells that contain a null value,
145+
* self::IGNORE_EMPTY_CELLS Don't read empty cells (cells that contain a null value,
123146
* empty string, or a string containing only whitespace characters)
124147
*/
125148
public function load(string $filename, int $flags = 0): Spreadsheet;

src/PhpSpreadsheet/Worksheet/Worksheet.php

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2784,23 +2784,30 @@ public function fromArray(array $source, mixed $nullValue = null, string $startC
27842784
[$startColumn, $startRow] = Coordinate::coordinateFromString($startCell);
27852785

27862786
// Loop through $source
2787-
foreach ($source as $rowData) {
2788-
$currentColumn = $startColumn;
2789-
foreach ($rowData as $cellValue) {
2790-
if ($strictNullComparison) {
2787+
if ($strictNullComparison) {
2788+
foreach ($source as $rowData) {
2789+
$currentColumn = $startColumn;
2790+
foreach ($rowData as $cellValue) {
27912791
if ($cellValue !== $nullValue) {
27922792
// Set cell value
27932793
$this->getCell($currentColumn . $startRow)->setValue($cellValue);
27942794
}
2795-
} else {
2795+
++$currentColumn;
2796+
}
2797+
++$startRow;
2798+
}
2799+
} else {
2800+
foreach ($source as $rowData) {
2801+
$currentColumn = $startColumn;
2802+
foreach ($rowData as $cellValue) {
27962803
if ($cellValue != $nullValue) {
27972804
// Set cell value
27982805
$this->getCell($currentColumn . $startRow)->setValue($cellValue);
27992806
}
2807+
++$currentColumn;
28002808
}
2801-
++$currentColumn;
2809+
++$startRow;
28022810
}
2803-
++$startRow;
28042811
}
28052812

28062813
return $this;

src/PhpSpreadsheet/Writer/Xls/ConditionalHelper.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ public function processCondition(mixed $condition, string $cellRange): void
3030
$this->condition = $condition;
3131
$this->cellRange = $cellRange;
3232

33-
if (is_int($condition) || is_float($condition)) {
34-
$this->size = ($condition <= 65535 ? 3 : 0x0000);
33+
if (is_int($condition) && $condition >= 0 && $condition <= 65535) {
34+
$this->size = 3;
3535
$this->tokens = pack('Cv', 0x1E, $condition);
3636
} else {
3737
try {

src/PhpSpreadsheet/Writer/Xls/Worksheet.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,31 @@ public function close(): void
489489
$this->storeEof();
490490
}
491491

492+
public const MAX_XLS_COLUMN = 256;
493+
public const MAX_XLS_COLUMN_STRING = 'IV';
494+
public const MAX_XLS_ROW = 65536;
495+
496+
private static function limitRange(string $exploded): string
497+
{
498+
$retVal = '';
499+
$ranges = Coordinate::getRangeBoundaries($exploded);
500+
$firstCol = Coordinate::columnIndexFromString($ranges[0][0]);
501+
$firstRow = (int) $ranges[0][1];
502+
if ($firstCol <= self::MAX_XLS_COLUMN && $firstRow <= self::MAX_XLS_ROW) {
503+
$retVal = $exploded;
504+
if (str_contains($exploded, ':')) {
505+
$lastCol = Coordinate::columnIndexFromString($ranges[1][0]);
506+
$ranges[1][1] = min(self::MAX_XLS_ROW, (int) $ranges[1][1]);
507+
if ($lastCol > self::MAX_XLS_COLUMN) {
508+
$ranges[1][0] = self::MAX_XLS_COLUMN_STRING;
509+
}
510+
$retVal = "{$ranges[0][0]}{$ranges[0][1]}:{$ranges[1][0]}{$ranges[1][1]}";
511+
}
512+
}
513+
514+
return $retVal;
515+
}
516+
492517
private function writeConditionalFormatting(): void
493518
{
494519
$conditionalFormulaHelper = new ConditionalHelper($this->parser);
@@ -497,7 +522,10 @@ private function writeConditionalFormatting(): void
497522
foreach ($this->phpSheet->getConditionalStylesCollection() as $key => $value) {
498523
$keyExplode = explode(',', Coordinate::resolveUnionAndIntersection($key));
499524
foreach ($keyExplode as $exploded) {
500-
$arrConditionalStyles[$exploded] = $value;
525+
$range = self::limitRange($exploded);
526+
if ($range !== '') {
527+
$arrConditionalStyles[$range] = $value;
528+
}
501529
}
502530
}
503531
if (!empty($arrConditionalStyles)) {

src/PhpSpreadsheet/Writer/Xlsx/ContentTypes.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ public function writeContentTypes(Spreadsheet $spreadsheet, bool $includeCharts
196196
$bgImage = $spreadsheet->getSheet($i)->getBackgroundImage();
197197
$mimeType = $spreadsheet->getSheet($i)->getBackgroundMime();
198198
$extension = $spreadsheet->getSheet($i)->getBackgroundExtension();
199-
if ($bgImage !== '' && !isset($aMediaContentTypes[$mimeType])) {
199+
if ($bgImage !== '' && !isset($aMediaContentTypes[$extension])) {
200200
$this->writeDefaultContentType($objWriter, $extension, $mimeType);
201201
}
202202
}

src/PhpSpreadsheet/Writer/Xlsx/FunctionPrefix.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@ class FunctionPrefix
130130
. '|ifs'
131131
. '|maxifs'
132132
. '|minifs'
133-
. '|sumifs'
134133
. '|textjoin'
135134
// functions added with Excel 365
136135
. '|anchorarray'

0 commit comments

Comments
 (0)