@@ -107,6 +107,13 @@ class Xlsx extends BaseWriter
107
107
*/
108
108
private $ drawingHashTable ;
109
109
110
+ /**
111
+ * Private handle for zip stream.
112
+ *
113
+ * @var ZipStream
114
+ */
115
+ private $ zip ;
116
+
110
117
/**
111
118
* Create a new Xlsx Writer.
112
119
*/
@@ -173,6 +180,7 @@ public function save($pFilename): void
173
180
{
174
181
if ($ this ->spreadSheet !== null ) {
175
182
// garbage collect
183
+ $ this ->pathNames = [];
176
184
$ this ->spreadSheet ->garbageCollect ();
177
185
178
186
$ this ->openFileHandle ($ pFilename );
@@ -203,73 +211,73 @@ public function save($pFilename): void
203
211
$ options ->setEnableZip64 (false );
204
212
$ options ->setOutputStream ($ this ->fileHandle );
205
213
206
- $ zip = new ZipStream (null , $ options );
214
+ $ this -> zip = new ZipStream (null , $ options );
207
215
208
216
// Add [Content_Types].xml to ZIP file
209
- $ zip -> addFile ('[Content_Types].xml ' , $ this ->getWriterPart ('ContentTypes ' )->writeContentTypes ($ this ->spreadSheet , $ this ->includeCharts ));
217
+ $ this -> addZipFile ('[Content_Types].xml ' , $ this ->getWriterPart ('ContentTypes ' )->writeContentTypes ($ this ->spreadSheet , $ this ->includeCharts ));
210
218
211
219
//if hasMacros, add the vbaProject.bin file, Certificate file(if exists)
212
220
if ($ this ->spreadSheet ->hasMacros ()) {
213
221
$ macrosCode = $ this ->spreadSheet ->getMacrosCode ();
214
222
if ($ macrosCode !== null ) {
215
223
// we have the code ?
216
- $ zip -> addFile ('xl/vbaProject.bin ' , $ macrosCode ); //allways in 'xl', allways named vbaProject.bin
224
+ $ this -> addZipFile ('xl/vbaProject.bin ' , $ macrosCode ); //allways in 'xl', allways named vbaProject.bin
217
225
if ($ this ->spreadSheet ->hasMacrosCertificate ()) {
218
226
//signed macros ?
219
227
// Yes : add the certificate file and the related rels file
220
- $ zip -> addFile ('xl/vbaProjectSignature.bin ' , $ this ->spreadSheet ->getMacrosCertificate ());
221
- $ zip -> addFile ('xl/_rels/vbaProject.bin.rels ' , $ this ->getWriterPart ('RelsVBA ' )->writeVBARelationships ($ this ->spreadSheet ));
228
+ $ this -> addZipFile ('xl/vbaProjectSignature.bin ' , $ this ->spreadSheet ->getMacrosCertificate ());
229
+ $ this -> addZipFile ('xl/_rels/vbaProject.bin.rels ' , $ this ->getWriterPart ('RelsVBA ' )->writeVBARelationships ($ this ->spreadSheet ));
222
230
}
223
231
}
224
232
}
225
233
//a custom UI in this workbook ? add it ("base" xml and additional objects (pictures) and rels)
226
234
if ($ this ->spreadSheet ->hasRibbon ()) {
227
235
$ tmpRibbonTarget = $ this ->spreadSheet ->getRibbonXMLData ('target ' );
228
- $ zip -> addFile ($ tmpRibbonTarget , $ this ->spreadSheet ->getRibbonXMLData ('data ' ));
236
+ $ this -> addZipFile ($ tmpRibbonTarget , $ this ->spreadSheet ->getRibbonXMLData ('data ' ));
229
237
if ($ this ->spreadSheet ->hasRibbonBinObjects ()) {
230
238
$ tmpRootPath = dirname ($ tmpRibbonTarget ) . '/ ' ;
231
239
$ ribbonBinObjects = $ this ->spreadSheet ->getRibbonBinObjects ('data ' ); //the files to write
232
240
foreach ($ ribbonBinObjects as $ aPath => $ aContent ) {
233
- $ zip -> addFile ($ tmpRootPath . $ aPath , $ aContent );
241
+ $ this -> addZipFile ($ tmpRootPath . $ aPath , $ aContent );
234
242
}
235
243
//the rels for files
236
- $ zip -> addFile ($ tmpRootPath . '_rels/ ' . basename ($ tmpRibbonTarget ) . '.rels ' , $ this ->getWriterPart ('RelsRibbonObjects ' )->writeRibbonRelationships ($ this ->spreadSheet ));
244
+ $ this -> addZipFile ($ tmpRootPath . '_rels/ ' . basename ($ tmpRibbonTarget ) . '.rels ' , $ this ->getWriterPart ('RelsRibbonObjects ' )->writeRibbonRelationships ($ this ->spreadSheet ));
237
245
}
238
246
}
239
247
240
248
// Add relationships to ZIP file
241
- $ zip -> addFile ('_rels/.rels ' , $ this ->getWriterPart ('Rels ' )->writeRelationships ($ this ->spreadSheet ));
242
- $ zip -> addFile ('xl/_rels/workbook.xml.rels ' , $ this ->getWriterPart ('Rels ' )->writeWorkbookRelationships ($ this ->spreadSheet ));
249
+ $ this -> addZipFile ('_rels/.rels ' , $ this ->getWriterPart ('Rels ' )->writeRelationships ($ this ->spreadSheet ));
250
+ $ this -> addZipFile ('xl/_rels/workbook.xml.rels ' , $ this ->getWriterPart ('Rels ' )->writeWorkbookRelationships ($ this ->spreadSheet ));
243
251
244
252
// Add document properties to ZIP file
245
- $ zip -> addFile ('docProps/app.xml ' , $ this ->getWriterPart ('DocProps ' )->writeDocPropsApp ($ this ->spreadSheet ));
246
- $ zip -> addFile ('docProps/core.xml ' , $ this ->getWriterPart ('DocProps ' )->writeDocPropsCore ($ this ->spreadSheet ));
253
+ $ this -> addZipFile ('docProps/app.xml ' , $ this ->getWriterPart ('DocProps ' )->writeDocPropsApp ($ this ->spreadSheet ));
254
+ $ this -> addZipFile ('docProps/core.xml ' , $ this ->getWriterPart ('DocProps ' )->writeDocPropsCore ($ this ->spreadSheet ));
247
255
$ customPropertiesPart = $ this ->getWriterPart ('DocProps ' )->writeDocPropsCustom ($ this ->spreadSheet );
248
256
if ($ customPropertiesPart !== null ) {
249
- $ zip -> addFile ('docProps/custom.xml ' , $ customPropertiesPart );
257
+ $ this -> addZipFile ('docProps/custom.xml ' , $ customPropertiesPart );
250
258
}
251
259
252
260
// Add theme to ZIP file
253
- $ zip -> addFile ('xl/theme/theme1.xml ' , $ this ->getWriterPart ('Theme ' )->writeTheme ($ this ->spreadSheet ));
261
+ $ this -> addZipFile ('xl/theme/theme1.xml ' , $ this ->getWriterPart ('Theme ' )->writeTheme ($ this ->spreadSheet ));
254
262
255
263
// Add string table to ZIP file
256
- $ zip -> addFile ('xl/sharedStrings.xml ' , $ this ->getWriterPart ('StringTable ' )->writeStringTable ($ this ->stringTable ));
264
+ $ this -> addZipFile ('xl/sharedStrings.xml ' , $ this ->getWriterPart ('StringTable ' )->writeStringTable ($ this ->stringTable ));
257
265
258
266
// Add styles to ZIP file
259
- $ zip -> addFile ('xl/styles.xml ' , $ this ->getWriterPart ('Style ' )->writeStyles ($ this ->spreadSheet ));
267
+ $ this -> addZipFile ('xl/styles.xml ' , $ this ->getWriterPart ('Style ' )->writeStyles ($ this ->spreadSheet ));
260
268
261
269
// Add workbook to ZIP file
262
- $ zip -> addFile ('xl/workbook.xml ' , $ this ->getWriterPart ('Workbook ' )->writeWorkbook ($ this ->spreadSheet , $ this ->preCalculateFormulas ));
270
+ $ this -> addZipFile ('xl/workbook.xml ' , $ this ->getWriterPart ('Workbook ' )->writeWorkbook ($ this ->spreadSheet , $ this ->preCalculateFormulas ));
263
271
264
272
$ chartCount = 0 ;
265
273
// Add worksheets
266
274
for ($ i = 0 ; $ i < $ this ->spreadSheet ->getSheetCount (); ++$ i ) {
267
- $ zip -> addFile ('xl/worksheets/sheet ' . ($ i + 1 ) . '.xml ' , $ this ->getWriterPart ('Worksheet ' )->writeWorksheet ($ this ->spreadSheet ->getSheet ($ i ), $ this ->stringTable , $ this ->includeCharts ));
275
+ $ this -> addZipFile ('xl/worksheets/sheet ' . ($ i + 1 ) . '.xml ' , $ this ->getWriterPart ('Worksheet ' )->writeWorksheet ($ this ->spreadSheet ->getSheet ($ i ), $ this ->stringTable , $ this ->includeCharts ));
268
276
if ($ this ->includeCharts ) {
269
277
$ charts = $ this ->spreadSheet ->getSheet ($ i )->getChartCollection ();
270
278
if (count ($ charts ) > 0 ) {
271
279
foreach ($ charts as $ chart ) {
272
- $ zip -> addFile ('xl/charts/chart ' . ($ chartCount + 1 ) . '.xml ' , $ this ->getWriterPart ('Chart ' )->writeChart ($ chart , $ this ->preCalculateFormulas ));
280
+ $ this -> addZipFile ('xl/charts/chart ' . ($ chartCount + 1 ) . '.xml ' , $ this ->getWriterPart ('Chart ' )->writeChart ($ chart , $ this ->preCalculateFormulas ));
273
281
++$ chartCount ;
274
282
}
275
283
}
@@ -280,19 +288,19 @@ public function save($pFilename): void
280
288
// Add worksheet relationships (drawings, ...)
281
289
for ($ i = 0 ; $ i < $ this ->spreadSheet ->getSheetCount (); ++$ i ) {
282
290
// Add relationships
283
- $ zip -> addFile ('xl/worksheets/_rels/sheet ' . ($ i + 1 ) . '.xml.rels ' , $ this ->getWriterPart ('Rels ' )->writeWorksheetRelationships ($ this ->spreadSheet ->getSheet ($ i ), ($ i + 1 ), $ this ->includeCharts ));
291
+ $ this -> addZipFile ('xl/worksheets/_rels/sheet ' . ($ i + 1 ) . '.xml.rels ' , $ this ->getWriterPart ('Rels ' )->writeWorksheetRelationships ($ this ->spreadSheet ->getSheet ($ i ), ($ i + 1 ), $ this ->includeCharts ));
284
292
285
293
// Add unparsedLoadedData
286
294
$ sheetCodeName = $ this ->spreadSheet ->getSheet ($ i )->getCodeName ();
287
295
$ unparsedLoadedData = $ this ->spreadSheet ->getUnparsedLoadedData ();
288
296
if (isset ($ unparsedLoadedData ['sheets ' ][$ sheetCodeName ]['ctrlProps ' ])) {
289
297
foreach ($ unparsedLoadedData ['sheets ' ][$ sheetCodeName ]['ctrlProps ' ] as $ ctrlProp ) {
290
- $ zip -> addFile ($ ctrlProp ['filePath ' ], $ ctrlProp ['content ' ]);
298
+ $ this -> addZipFile ($ ctrlProp ['filePath ' ], $ ctrlProp ['content ' ]);
291
299
}
292
300
}
293
301
if (isset ($ unparsedLoadedData ['sheets ' ][$ sheetCodeName ]['printerSettings ' ])) {
294
302
foreach ($ unparsedLoadedData ['sheets ' ][$ sheetCodeName ]['printerSettings ' ] as $ ctrlProp ) {
295
- $ zip -> addFile ($ ctrlProp ['filePath ' ], $ ctrlProp ['content ' ]);
303
+ $ this -> addZipFile ($ ctrlProp ['filePath ' ], $ ctrlProp ['content ' ]);
296
304
}
297
305
}
298
306
@@ -305,13 +313,13 @@ public function save($pFilename): void
305
313
// Add drawing and image relationship parts
306
314
if (($ drawingCount > 0 ) || ($ chartCount > 0 )) {
307
315
// Drawing relationships
308
- $ zip -> addFile ('xl/drawings/_rels/drawing ' . ($ i + 1 ) . '.xml.rels ' , $ this ->getWriterPart ('Rels ' )->writeDrawingRelationships ($ this ->spreadSheet ->getSheet ($ i ), $ chartRef1 , $ this ->includeCharts ));
316
+ $ this -> addZipFile ('xl/drawings/_rels/drawing ' . ($ i + 1 ) . '.xml.rels ' , $ this ->getWriterPart ('Rels ' )->writeDrawingRelationships ($ this ->spreadSheet ->getSheet ($ i ), $ chartRef1 , $ this ->includeCharts ));
309
317
310
318
// Drawings
311
- $ zip -> addFile ('xl/drawings/drawing ' . ($ i + 1 ) . '.xml ' , $ this ->getWriterPart ('Drawing ' )->writeDrawings ($ this ->spreadSheet ->getSheet ($ i ), $ this ->includeCharts ));
319
+ $ this -> addZipFile ('xl/drawings/drawing ' . ($ i + 1 ) . '.xml ' , $ this ->getWriterPart ('Drawing ' )->writeDrawings ($ this ->spreadSheet ->getSheet ($ i ), $ this ->includeCharts ));
312
320
} elseif (isset ($ unparsedLoadedData ['sheets ' ][$ sheetCodeName ]['drawingAlternateContents ' ])) {
313
321
// Drawings
314
- $ zip -> addFile ('xl/drawings/drawing ' . ($ i + 1 ) . '.xml ' , $ this ->getWriterPart ('Drawing ' )->writeDrawings ($ this ->spreadSheet ->getSheet ($ i ), $ this ->includeCharts ));
322
+ $ this -> addZipFile ('xl/drawings/drawing ' . ($ i + 1 ) . '.xml ' , $ this ->getWriterPart ('Drawing ' )->writeDrawings ($ this ->spreadSheet ->getSheet ($ i ), $ this ->includeCharts ));
315
323
}
316
324
317
325
// Add unparsed drawings
@@ -320,38 +328,38 @@ public function save($pFilename): void
320
328
$ drawingFile = array_search ($ relId , $ unparsedLoadedData ['sheets ' ][$ sheetCodeName ]['drawingOriginalIds ' ]);
321
329
if ($ drawingFile !== false ) {
322
330
$ drawingFile = ltrim ($ drawingFile , '. ' );
323
- $ zip -> addFile ('xl ' . $ drawingFile , $ drawingXml );
331
+ $ this -> addZipFile ('xl ' . $ drawingFile , $ drawingXml );
324
332
}
325
333
}
326
334
}
327
335
328
336
// Add comment relationship parts
329
337
if (count ($ this ->spreadSheet ->getSheet ($ i )->getComments ()) > 0 ) {
330
338
// VML Comments
331
- $ zip -> addFile ('xl/drawings/vmlDrawing ' . ($ i + 1 ) . '.vml ' , $ this ->getWriterPart ('Comments ' )->writeVMLComments ($ this ->spreadSheet ->getSheet ($ i )));
339
+ $ this -> addZipFile ('xl/drawings/vmlDrawing ' . ($ i + 1 ) . '.vml ' , $ this ->getWriterPart ('Comments ' )->writeVMLComments ($ this ->spreadSheet ->getSheet ($ i )));
332
340
333
341
// Comments
334
- $ zip -> addFile ('xl/comments ' . ($ i + 1 ) . '.xml ' , $ this ->getWriterPart ('Comments ' )->writeComments ($ this ->spreadSheet ->getSheet ($ i )));
342
+ $ this -> addZipFile ('xl/comments ' . ($ i + 1 ) . '.xml ' , $ this ->getWriterPart ('Comments ' )->writeComments ($ this ->spreadSheet ->getSheet ($ i )));
335
343
}
336
344
337
345
// Add unparsed relationship parts
338
346
if (isset ($ unparsedLoadedData ['sheets ' ][$ sheetCodeName ]['vmlDrawings ' ])) {
339
347
foreach ($ unparsedLoadedData ['sheets ' ][$ sheetCodeName ]['vmlDrawings ' ] as $ vmlDrawing ) {
340
- $ zip -> addFile ($ vmlDrawing ['filePath ' ], $ vmlDrawing ['content ' ]);
348
+ $ this -> addZipFile ($ vmlDrawing ['filePath ' ], $ vmlDrawing ['content ' ]);
341
349
}
342
350
}
343
351
344
352
// Add header/footer relationship parts
345
353
if (count ($ this ->spreadSheet ->getSheet ($ i )->getHeaderFooter ()->getImages ()) > 0 ) {
346
354
// VML Drawings
347
- $ zip -> addFile ('xl/drawings/vmlDrawingHF ' . ($ i + 1 ) . '.vml ' , $ this ->getWriterPart ('Drawing ' )->writeVMLHeaderFooterImages ($ this ->spreadSheet ->getSheet ($ i )));
355
+ $ this -> addZipFile ('xl/drawings/vmlDrawingHF ' . ($ i + 1 ) . '.vml ' , $ this ->getWriterPart ('Drawing ' )->writeVMLHeaderFooterImages ($ this ->spreadSheet ->getSheet ($ i )));
348
356
349
357
// VML Drawing relationships
350
- $ zip -> addFile ('xl/drawings/_rels/vmlDrawingHF ' . ($ i + 1 ) . '.vml.rels ' , $ this ->getWriterPart ('Rels ' )->writeHeaderFooterDrawingRelationships ($ this ->spreadSheet ->getSheet ($ i )));
358
+ $ this -> addZipFile ('xl/drawings/_rels/vmlDrawingHF ' . ($ i + 1 ) . '.vml.rels ' , $ this ->getWriterPart ('Rels ' )->writeHeaderFooterDrawingRelationships ($ this ->spreadSheet ->getSheet ($ i )));
351
359
352
360
// Media
353
361
foreach ($ this ->spreadSheet ->getSheet ($ i )->getHeaderFooter ()->getImages () as $ image ) {
354
- $ zip -> addFile ('xl/media/ ' . $ image ->getIndexedFilename (), file_get_contents ($ image ->getPath ()));
362
+ $ this -> addZipFile ('xl/media/ ' . $ image ->getIndexedFilename (), file_get_contents ($ image ->getPath ()));
355
363
}
356
364
}
357
365
}
@@ -374,7 +382,7 @@ public function save($pFilename): void
374
382
$ imageContents = file_get_contents ($ imagePath );
375
383
}
376
384
377
- $ zip -> addFile ('xl/media/ ' . str_replace (' ' , '_ ' , $ this ->getDrawingHashTable ()->getByIndex ($ i )->getIndexedFilename ()), $ imageContents );
385
+ $ this -> addZipFile ('xl/media/ ' . str_replace (' ' , '_ ' , $ this ->getDrawingHashTable ()->getByIndex ($ i )->getIndexedFilename ()), $ imageContents );
378
386
} elseif ($ this ->getDrawingHashTable ()->getByIndex ($ i ) instanceof MemoryDrawing) {
379
387
ob_start ();
380
388
call_user_func (
@@ -384,7 +392,7 @@ public function save($pFilename): void
384
392
$ imageContents = ob_get_contents ();
385
393
ob_end_clean ();
386
394
387
- $ zip -> addFile ('xl/media/ ' . str_replace (' ' , '_ ' , $ this ->getDrawingHashTable ()->getByIndex ($ i )->getIndexedFilename ()), $ imageContents );
395
+ $ this -> addZipFile ('xl/media/ ' . str_replace (' ' , '_ ' , $ this ->getDrawingHashTable ()->getByIndex ($ i )->getIndexedFilename ()), $ imageContents );
388
396
}
389
397
}
390
398
@@ -393,7 +401,7 @@ public function save($pFilename): void
393
401
394
402
// Close file
395
403
try {
396
- $ zip ->finish ();
404
+ $ this -> zip ->finish ();
397
405
} catch (OverflowException $ e ) {
398
406
throw new WriterException ('Could not close resource. ' );
399
407
}
@@ -535,4 +543,14 @@ public function setOffice2003Compatibility($pValue)
535
543
536
544
return $ this ;
537
545
}
546
+
547
+ private $ pathNames = [];
548
+
549
+ private function addZipFile (string $ path , string $ content ): void
550
+ {
551
+ if (!in_array ($ path , $ this ->pathNames )) {
552
+ $ this ->pathNames [] = $ path ;
553
+ $ this ->zip ->addFile ($ path , $ content );
554
+ }
555
+ }
538
556
}
0 commit comments