Skip to content

Commit d0c49cd

Browse files
authored
Merge branch 'master' into condxlsborder
2 parents 7ce0184 + 8e87f55 commit d0c49cd

File tree

12 files changed

+160
-9
lines changed

12 files changed

+160
-9
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
99

1010
### Added
1111

12-
- Nothing
12+
- Xlsx Reader Optionally Ignore Rows With No Cells. [Issue #3982](https://github.com/PHPOffice/PhpSpreadsheet/issues/3982) [PR #4035](https://github.com/PHPOffice/PhpSpreadsheet/pull/4035)
1313

1414
### Changed
1515

@@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
2929
- POWER Null/Bool Args. [PR #4031](https://github.com/PHPOffice/PhpSpreadsheet/pull/4031)
3030
- Do Not Output Alignment and Protection for Conditional Format. [Issue #4025](https://github.com/PHPOffice/PhpSpreadsheet/issues/4025) [PR #4027](https://github.com/PHPOffice/PhpSpreadsheet/pull/4027)
3131
- Xls Conditional Format Improvements. [PR #4030](https://github.com/PHPOffice/PhpSpreadsheet/pull/4030) [PR #4033](https://github.com/PHPOffice/PhpSpreadsheet/pull/4033)
32+
- Csv Reader allow use of html mimetype. [Issue #4036](https://github.com/PHPOffice/PhpSpreadsheet/issues/4036) [PR #4049](https://github.com/PHPOffice/PhpSpreadsheet/pull/4040)
3233

3334
## 2024-05-11 - 2.1.0
3435

samples/Financial2/DISC.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
require __DIR__ . '/../Header.php';
77

8-
$helper->log('Returns the the Discount Rate for a security.');
8+
$helper->log('Returns the Discount Rate for a security.');
99

1010
// Create new PhpSpreadsheet object
1111
$spreadsheet = new Spreadsheet();

src/PhpSpreadsheet/Reader/BaseReader.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ abstract class BaseReader implements IReader
3939
*/
4040
protected ?array $loadSheetsOnly = null;
4141

42+
/**
43+
* Ignore rows with no cells?
44+
* Identifies whether the Reader should ignore rows with no cells.
45+
* Currently implemented only for Xlsx.
46+
*/
47+
protected bool $ignoreRowsWithNoCells = false;
48+
4249
/**
4350
* IReadFilter instance.
4451
*/
@@ -78,6 +85,18 @@ public function setReadEmptyCells(bool $readEmptyCells): self
7885
return $this;
7986
}
8087

88+
public function getIgnoreRowsWithNoCells(): bool
89+
{
90+
return $this->ignoreRowsWithNoCells;
91+
}
92+
93+
public function setIgnoreRowsWithNoCells(bool $ignoreRowsWithNoCells): self
94+
{
95+
$this->ignoreRowsWithNoCells = $ignoreRowsWithNoCells;
96+
97+
return $this;
98+
}
99+
81100
public function getIncludeCharts(): bool
82101
{
83102
return $this->includeCharts;
@@ -150,6 +169,9 @@ protected function processFlags(int $flags): void
150169
if (((bool) ($flags & self::SKIP_EMPTY_CELLS) || (bool) ($flags & self::IGNORE_EMPTY_CELLS)) === true) {
151170
$this->setReadEmptyCells(false);
152171
}
172+
if (((bool) ($flags & self::IGNORE_ROWS_WITH_NO_CELLS)) === true) {
173+
$this->setIgnoreRowsWithNoCells(true);
174+
}
153175
}
154176

155177
protected function loadSpreadsheetFromFile(string $filename): Spreadsheet

src/PhpSpreadsheet/Reader/Csv.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,7 @@ public function canRead(string $filename): bool
566566
'text/csv',
567567
'text/plain',
568568
'inode/x-empty',
569+
'text/html',
569570
];
570571

571572
return in_array($type, $supportedTypes, true);

src/PhpSpreadsheet/Reader/IReader.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ interface IReader
1313
public const SKIP_EMPTY_CELLS = 4;
1414
public const IGNORE_EMPTY_CELLS = 4;
1515

16+
public const IGNORE_ROWS_WITH_NO_CELLS = 8;
17+
1618
public function __construct();
1719

1820
/**

src/PhpSpreadsheet/Reader/Xlsx.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -796,10 +796,10 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
796796
}
797797

798798
$sheetViewOptions = new SheetViewOptions($docSheet, $xmlSheetNS);
799-
$sheetViewOptions->load($this->getReadDataOnly(), $this->styleReader);
799+
$sheetViewOptions->load($this->readDataOnly, $this->styleReader);
800800

801801
(new ColumnAndRowAttributes($docSheet, $xmlSheetNS))
802-
->load($this->getReadFilter(), $this->getReadDataOnly());
802+
->load($this->getReadFilter(), $this->readDataOnly, $this->ignoreRowsWithNoCells);
803803
}
804804

805805
$holdSelectedCells = $docSheet->getSelectedCells();

src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ private function setRowAttributes(int $rowNumber, array $rowAttributes): void
7272
}
7373
}
7474

75-
public function load(?IReadFilter $readFilter = null, bool $readDataOnly = false): void
75+
public function load(?IReadFilter $readFilter = null, bool $readDataOnly = false, bool $ignoreRowsWithNoCells = false): void
7676
{
7777
if ($this->worksheetXml === null) {
7878
return;
@@ -85,7 +85,7 @@ public function load(?IReadFilter $readFilter = null, bool $readDataOnly = false
8585
}
8686

8787
if ($this->worksheetXml->sheetData && $this->worksheetXml->sheetData->row) {
88-
$rowsAttributes = $this->readRowAttributes($this->worksheetXml->sheetData->row, $readDataOnly);
88+
$rowsAttributes = $this->readRowAttributes($this->worksheetXml->sheetData->row, $readDataOnly, $ignoreRowsWithNoCells);
8989
}
9090

9191
if ($readFilter !== null && $readFilter::class === DefaultReadFilter::class) {
@@ -189,13 +189,13 @@ private function isFilteredRow(IReadFilter $readFilter, int $rowCoordinate, arra
189189
return false;
190190
}
191191

192-
private function readRowAttributes(SimpleXMLElement $worksheetRow, bool $readDataOnly): array
192+
private function readRowAttributes(SimpleXMLElement $worksheetRow, bool $readDataOnly, bool $ignoreRowsWithNoCells): array
193193
{
194194
$rowAttributes = [];
195195

196196
foreach ($worksheetRow as $rowx) {
197197
$row = $rowx->attributes();
198-
if ($row !== null) {
198+
if ($row !== null && (!$ignoreRowsWithNoCells || isset($rowx->c))) {
199199
if (isset($row['ht']) && !$readDataOnly) {
200200
$rowAttributes[(int) $row['r']]['rowHeight'] = (float) $row['ht'];
201201
}

src/PhpSpreadsheet/Writer/ZipStream3.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace PhpOffice\PhpSpreadsheet\Writer;
44

5-
use ZipStream\Option\Archive;
65
use ZipStream\ZipStream;
76

87
class ZipStream3

tests/PhpSpreadsheetTests/IOFactoryTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ public static function providerIdentify(): array
103103
//['samples/templates/Excel2003XMLTest.xml', 'Xml', Reader\Xml::class],
104104
['samples/templates/46readHtml.html', 'Html', Reader\Html::class],
105105
['tests/data/Reader/CSV/encoding.utf8bom.csv', 'Csv', Reader\Csv::class],
106+
['tests/data/Reader/HTML/charset.UTF-16.lebom.html', 'Html', Reader\Html::class],
107+
['tests/data/Reader/HTML/charset.UTF-8.bom.html', 'Html', Reader\Html::class],
106108
];
107109
}
108110

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Reader\Csv;
6+
7+
use PhpOffice\PhpSpreadsheet\IOFactory;
8+
use PhpOffice\PhpSpreadsheet\Reader\Csv as CsvReader;
9+
use PhpOffice\PhpSpreadsheet\Shared\File;
10+
use PHPUnit\Framework\TestCase;
11+
12+
class NotHtmlTest extends TestCase
13+
{
14+
private string $tempFile = '';
15+
16+
protected function tearDown(): void
17+
{
18+
if ($this->tempFile !== '') {
19+
unlink($this->tempFile);
20+
$this->tempFile = '';
21+
}
22+
}
23+
24+
public function testHtmlCantRead(): void
25+
{
26+
// This test has a file which IOFactory will identify as Csv.
27+
// So file can be read using either Csv Reader or IOFactory.
28+
$this->tempFile = $filename = File::temporaryFilename();
29+
$cells = [
30+
['1', '<a href="http://example.com">example</a>', '3'],
31+
['4', '5', '6'],
32+
];
33+
$handle = fopen($filename, 'wb');
34+
self::assertNotFalse($handle);
35+
foreach ($cells as $row) {
36+
fwrite($handle, "{$row[0]},{$row[1]},{$row[2]}\n");
37+
}
38+
fclose($handle);
39+
// Php8.3- identify file as text/html.
40+
// Php8.4+ identify file as text/csv, and this type of change
41+
// has been known to be retrofitted to prior versions.
42+
$mime = mime_content_type($filename);
43+
if ($mime !== 'text/csv') {
44+
self::assertSame('text/html', $mime);
45+
}
46+
self::assertSame('Csv', IOFactory::identify($filename));
47+
$reader = new CsvReader();
48+
$spreadsheet = $reader->load($filename);
49+
$sheet = $spreadsheet->getActiveSheet();
50+
self::assertSame($cells, $sheet->toArray());
51+
$spreadsheet->disconnectWorksheets();
52+
}
53+
54+
public function testHtmlCanRead(): void
55+
{
56+
// This test has a file which IOFactory will identify as Html.
57+
// So file has to be read using Csv Reader, not IOFactory.
58+
$this->tempFile = $filename = File::temporaryFilename();
59+
$cells = [
60+
['<a href="http://example.com">example</a>', '<div>hello', '3'],
61+
['4', '5', '</div>'],
62+
];
63+
$handle = fopen($filename, 'wb');
64+
self::assertNotFalse($handle);
65+
foreach ($cells as $row) {
66+
fwrite($handle, "{$row[0]},{$row[1]},{$row[2]}\n");
67+
}
68+
fclose($handle);
69+
// Php8.3- identify file as text/html.
70+
// Php8.4+ identify file as text/csv, and this type of change
71+
// has been known to be retrofitted to prior versions.
72+
$mime = mime_content_type($filename);
73+
if ($mime !== 'text/csv') {
74+
self::assertSame('text/html', $mime);
75+
}
76+
self::assertSame('Html', IOFactory::identify($filename));
77+
$reader = new CsvReader();
78+
$spreadsheet = $reader->load($filename);
79+
$sheet = $spreadsheet->getActiveSheet();
80+
self::assertSame($cells, $sheet->toArray());
81+
$spreadsheet->disconnectWorksheets();
82+
}
83+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
6+
7+
use PhpOffice\PhpSpreadsheet\IOFactory;
8+
use PhpOffice\PhpSpreadsheet\Reader\IReader;
9+
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
10+
11+
class Issue3982Test extends \PHPUnit\Framework\TestCase
12+
{
13+
private static string $testbook = 'tests/data/Reader/XLSX/issue.3982.xlsx';
14+
15+
public function testLoadAllRows(): void
16+
{
17+
$spreadsheet = IOFactory::load(self::$testbook);
18+
$sheet = $spreadsheet->getActiveSheet();
19+
$data = $sheet->toArray(null, true, false, true);
20+
self::assertCount(1048576, $data);
21+
$spreadsheet->disconnectWorksheets();
22+
}
23+
24+
public function testIgnoreCellsWithNoRows(): void
25+
{
26+
$spreadsheet = IOFactory::load(self::$testbook, IReader::IGNORE_ROWS_WITH_NO_CELLS);
27+
$sheet = $spreadsheet->getActiveSheet();
28+
$data = $sheet->toArray(null, true, false, true);
29+
self::assertSame([1, 2, 3, 4, 5, 6], array_keys($data));
30+
$spreadsheet->disconnectWorksheets();
31+
}
32+
33+
public function testDefaultSetting(): void
34+
{
35+
$reader = new XlsxReader();
36+
self::assertFalse($reader->getIgnoreRowsWithNoCells());
37+
self::assertFalse($reader->getReadDataOnly());
38+
self::assertFalse($reader->getIncludeCharts());
39+
self::assertTrue($reader->getReadEmptyCells());
40+
}
41+
}
20.5 KB
Binary file not shown.

0 commit comments

Comments
 (0)