Skip to content

Commit 8d387c1

Browse files
committed
Reading Xlsx With No or Empty Styles
This is an exact replacement for PR PHPOffice#2247 by @arraintxo. That PR has reached a state in Github where it cannot be merged, and I am not sure how to fix it, other than by re-submitting it as this PR. See issue PHPOffice#2246. A spreadsheet lacking styles.xml is throwing an exception on Read. Additionally, after fixing that problem, attempting to save the object that has been read throws an exception. This is also true for a spreadsheet with an empty styles.xml.
1 parent 3c5750b commit 8d387c1

File tree

4 files changed

+80
-10
lines changed

4 files changed

+80
-10
lines changed

src/PhpSpreadsheet/Reader/Xlsx.php

+16-6
Original file line numberDiff line numberDiff line change
@@ -395,10 +395,8 @@ public function load(string $pFilename, int $flags = 0): Spreadsheet
395395
// Initialisations
396396
$excel = new Spreadsheet();
397397
$excel->removeSheetByIndex(0);
398-
if (!$this->readDataOnly) {
399-
$excel->removeCellStyleXfByIndex(0); // remove the default style
400-
$excel->removeCellXfByIndex(0); // remove the default style
401-
}
398+
$addingFirstCellStyleXf = true;
399+
$addingFirstCellXf = true;
402400
$unparsedLoadedData = [];
403401

404402
$this->zip = $zip = new ZipArchive();
@@ -534,8 +532,12 @@ public function load(string $pFilename, int $flags = 0): Spreadsheet
534532
. "$xmlNamespaceBase/styles"
535533
. "']";
536534
$xpath = self::getArrayItem(self::xpathNoFalse($relsWorkbook, $relType));
537-
// I think Nonamespace is okay because I'm using xpath.
538-
$xmlStyles = $this->loadZipNonamespace("$dir/$xpath[Target]", $mainNS);
535+
if ($xpath === null) {
536+
$xmlStyles = self::testSimpleXml(null);
537+
} else {
538+
// I think Nonamespace is okay because I'm using xpath.
539+
$xmlStyles = $this->loadZipNonamespace("$dir/$xpath[Target]", $mainNS);
540+
}
539541
$xmlStyles->registerXPathNamespace('smm', Namespaces::MAIN);
540542
$fills = self::xpathNoFalse($xmlStyles, 'smm:fills/smm:fill');
541543
$fonts = self::xpathNoFalse($xmlStyles, 'smm:fonts/smm:font');
@@ -593,6 +595,10 @@ public function load(string $pFilename, int $flags = 0): Spreadsheet
593595
// add style to cellXf collection
594596
$objStyle = new Style();
595597
self::readStyle($objStyle, $style);
598+
if ($addingFirstCellXf) {
599+
$excel->removeCellXfByIndex(0); // remove the default style
600+
$addingFirstCellXf = false;
601+
}
596602
$excel->addCellXf($objStyle);
597603
}
598604

@@ -624,6 +630,10 @@ public function load(string $pFilename, int $flags = 0): Spreadsheet
624630
// add style to cellStyleXf collection
625631
$objStyle = new Style();
626632
self::readStyle($objStyle, $cellStyle);
633+
if ($addingFirstCellStyleXf) {
634+
$excel->removeCellStyleXfByIndex(0); // remove the default style
635+
$addingFirstCellStyleXf = false;
636+
}
627637
$excel->addCellStyleXf($objStyle);
628638
}
629639
}

tests/PhpSpreadsheetTests/Reader/Xlsx/XlsxTest.php

+64-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
66
use PhpOffice\PhpSpreadsheet\Cell\DataValidation;
7-
use PhpOffice\PhpSpreadsheet\Document\Properties;
7+
use PhpOffice\PhpSpreadsheet\IOFactory;
88
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
99
use PhpOffice\PhpSpreadsheet\Shared\File;
1010
use PhpOffice\PhpSpreadsheet\Style\Conditional;
@@ -37,6 +37,7 @@ public function testLoadXlsxRowColumnAttributes(): void
3737
}
3838

3939
self::assertFalse($worksheet->getColumnDimension('E')->getVisible());
40+
$spreadsheet->disconnectWorksheets();
4041
}
4142

4243
public function testLoadXlsxWithStyles(): void
@@ -61,6 +62,54 @@ public function testLoadXlsxWithStyles(): void
6162
);
6263
}
6364
}
65+
$spreadsheet->disconnectWorksheets();
66+
}
67+
68+
/**
69+
* Test load Xlsx file without styles.xml.
70+
*/
71+
public function testLoadXlsxWithoutStyles(): void
72+
{
73+
$filename = 'tests/data/Reader/XLSX/issue.2246a.xlsx';
74+
$reader = new Xlsx();
75+
$spreadsheet = $reader->load($filename);
76+
77+
$tempFilename = File::temporaryFilename();
78+
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
79+
$writer->save($tempFilename);
80+
81+
$reader = new Xlsx();
82+
$reloadedSpreadsheet = $reader->load($tempFilename);
83+
unlink($tempFilename);
84+
85+
$reloadedWorksheet = $reloadedSpreadsheet->getActiveSheet();
86+
87+
self::assertEquals('TipoDato', $reloadedWorksheet->getCell('A1')->getValue());
88+
$spreadsheet->disconnectWorksheets();
89+
$reloadedSpreadsheet->disconnectWorksheets();
90+
}
91+
92+
/**
93+
* Test load Xlsx file with empty styles.xml.
94+
*/
95+
public function testLoadXlsxWithEmptyStyles(): void
96+
{
97+
$filename = 'tests/data/Reader/XLSX/issue.2246b.xlsx';
98+
$reader = new Xlsx();
99+
$spreadsheet = $reader->load($filename);
100+
101+
$tempFilename = File::temporaryFilename();
102+
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
103+
$writer->save($tempFilename);
104+
105+
$reader = new Xlsx();
106+
$reloadedSpreadsheet = $reader->load($tempFilename);
107+
unlink($tempFilename);
108+
109+
$reloadedWorksheet = $reloadedSpreadsheet->getActiveSheet();
110+
self::assertEquals('TipoDato', $reloadedWorksheet->getCell('A1')->getValue());
111+
$spreadsheet->disconnectWorksheets();
112+
$reloadedSpreadsheet->disconnectWorksheets();
64113
}
65114

66115
public function testLoadXlsxAutofilter(): void
@@ -78,6 +127,7 @@ public function testLoadXlsxAutofilter(): void
78127
AutoFilter\Column::AUTOFILTER_FILTERTYPE_FILTER,
79128
$autofilter->getColumn('A')->getFilterType()
80129
);
130+
$spreadsheet->disconnectWorksheets();
81131
}
82132

83133
public function testLoadXlsxPageSetup(): void
@@ -97,6 +147,7 @@ public function testLoadXlsxPageSetup(): void
97147

98148
self::assertEquals(PageSetup::PAPERSIZE_A4, $worksheet->getPageSetup()->getPaperSize());
99149
self::assertEquals(['A10', 'A20', 'A30', 'A40', 'A50'], array_keys($worksheet->getBreaks()));
150+
$spreadsheet->disconnectWorksheets();
100151
}
101152

102153
public function testLoadXlsxConditionalFormatting(): void
@@ -116,6 +167,7 @@ public function testLoadXlsxConditionalFormatting(): void
116167
self::assertEquals(Conditional::OPERATOR_BETWEEN, $conditionalRule->getOperatorType());
117168
self::assertEquals(['200', '400'], $conditionalRule->getConditions());
118169
self::assertInstanceOf(Style::class, $conditionalRule->getStyle());
170+
$spreadsheet->disconnectWorksheets();
119171
}
120172

121173
public function testLoadXlsxDataValidation(): void
@@ -127,6 +179,7 @@ public function testLoadXlsxDataValidation(): void
127179
$worksheet = $spreadsheet->getActiveSheet();
128180

129181
self::assertTrue($worksheet->getCell('B3')->hasDataValidation());
182+
$spreadsheet->disconnectWorksheets();
130183
}
131184

132185
/*
@@ -152,6 +205,7 @@ public function testLoadXlsxDataValidationOfAnotherSheet(): void
152205
self::assertTrue($validationCell->hasDataValidation());
153206
self::assertSame(DataValidation::TYPE_LIST, $validationCell->getDataValidation()->getType());
154207
self::assertSame('Feuil2!$A$3:$A$5', $validationCell->getDataValidation()->getFormula1());
208+
$spreadsheet->disconnectWorksheets();
155209
}
156210

157211
/**
@@ -163,7 +217,8 @@ public function testLoadXlsxWithoutCellReference(): void
163217
{
164218
$filename = 'tests/data/Reader/XLSX/without_cell_reference.xlsx';
165219
$reader = new Xlsx();
166-
$reader->load($filename);
220+
$spreadsheet = $reader->load($filename);
221+
$spreadsheet->disconnectWorksheets();
167222
}
168223

169224
/**
@@ -174,12 +229,14 @@ public function testLoadWithReadFilter(): void
174229
$filename = 'tests/data/Reader/XLSX/without_cell_reference.xlsx';
175230
$reader = new Xlsx();
176231
$reader->setReadFilter(new OddColumnReadFilter());
177-
$data = $reader->load($filename)->getActiveSheet()->toArray();
232+
$spreadsheet = $reader->load($filename);
233+
$data = $spreadsheet->getActiveSheet()->toArray();
178234
$ref = [1.0, null, 3.0, null, 5.0, null, 7.0, null, 9.0, null];
179235

180236
for ($i = 0; $i < 10; ++$i) {
181237
self::assertEquals($ref, \array_slice($data[$i], 0, 10, true));
182238
}
239+
$spreadsheet->disconnectWorksheets();
183240
}
184241

185242
/**
@@ -191,7 +248,8 @@ public function testLoadXlsxWithDoubleAttrDrawing(): void
191248
{
192249
$filename = 'tests/data/Reader/XLSX/double_attr_drawing.xlsx';
193250
$reader = new Xlsx();
194-
$reader->load($filename);
251+
$spreadsheet = $reader->load($filename);
252+
$spreadsheet->disconnectWorksheets();
195253
}
196254

197255
/**
@@ -206,10 +264,12 @@ public function testLoadSaveWithEmptyDrawings(): void
206264
$resultFilename = File::temporaryFilename();
207265
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($excel);
208266
$writer->save($resultFilename);
267+
$excel->disconnectWorksheets();
209268
$excel = $reader->load($resultFilename);
210269
unlink($resultFilename);
211270
// Fake assert. The only thing we need is to ensure the file is loaded without exception
212271
self::assertNotNull($excel);
272+
$excel->disconnectWorksheets();
213273
}
214274

215275
/**
14.8 KB
Binary file not shown.
18.5 KB
Binary file not shown.

0 commit comments

Comments
 (0)