ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Xlsx.php
Go to the documentation of this file.
1<?php
2
4
31use ZipArchive;
35
36class Xlsx extends BaseWriter
37{
43 private $office2003compatibility = false;
44
50 private $spreadSheet;
51
57 private $stringTable = [];
58
65
72
79
86
93
100
107
113 private $zip;
114
119
124
129
134
139
144
149
154
159
164
169
174
179
183 public function __construct(Spreadsheet $spreadsheet)
184 {
185 // Assign PhpSpreadsheet
186 $this->setSpreadsheet($spreadsheet);
187
188 $this->writerPartChart = new Chart($this);
189 $this->writerPartComments = new Comments($this);
190 $this->writerPartContentTypes = new ContentTypes($this);
191 $this->writerPartDocProps = new DocProps($this);
192 $this->writerPartDrawing = new Drawing($this);
193 $this->writerPartRels = new Rels($this);
194 $this->writerPartRelsRibbon = new RelsRibbon($this);
195 $this->writerPartRelsVBA = new RelsVBA($this);
196 $this->writerPartStringTable = new StringTable($this);
197 $this->writerPartStyle = new Style($this);
198 $this->writerPartTheme = new Theme($this);
199 $this->writerPartWorkbook = new Workbook($this);
200 $this->writerPartWorksheet = new Worksheet($this);
201
202 // Set HashTable variables
203 // @phpstan-ignore-next-line
204 $this->bordersHashTable = new HashTable();
205 // @phpstan-ignore-next-line
206 $this->drawingHashTable = new HashTable();
207 // @phpstan-ignore-next-line
208 $this->fillHashTable = new HashTable();
209 // @phpstan-ignore-next-line
210 $this->fontHashTable = new HashTable();
211 // @phpstan-ignore-next-line
212 $this->numFmtHashTable = new HashTable();
213 // @phpstan-ignore-next-line
214 $this->styleHashTable = new HashTable();
215 // @phpstan-ignore-next-line
216 $this->stylesConditionalHashTable = new HashTable();
217 }
218
219 public function getWriterPartChart(): Chart
220 {
222 }
223
225 {
227 }
228
230 {
232 }
233
235 {
237 }
238
239 public function getWriterPartDrawing(): Drawing
240 {
242 }
243
244 public function getWriterPartRels(): Rels
245 {
247 }
248
250 {
252 }
253
254 public function getWriterPartRelsVBA(): RelsVBA
255 {
257 }
258
260 {
262 }
263
264 public function getWriterPartStyle(): Style
265 {
267 }
268
269 public function getWriterPartTheme(): Theme
270 {
272 }
273
275 {
277 }
278
280 {
282 }
283
289 public function save($pFilename): void
290 {
291 // garbage collect
292 $this->pathNames = [];
293 $this->spreadSheet->garbageCollect();
294
295 $saveDebugLog = Calculation::getInstance($this->spreadSheet)->getDebugLog()->getWriteDebugLog();
296 Calculation::getInstance($this->spreadSheet)->getDebugLog()->setWriteDebugLog(false);
297 $saveDateReturnType = Functions::getReturnDateType();
299
300 // Create string lookup table
301 $this->stringTable = [];
302 for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) {
303 $this->stringTable = $this->getWriterPartStringTable()->createStringTable($this->spreadSheet->getSheet($i), $this->stringTable);
304 }
305
306 // Create styles dictionaries
307 $this->styleHashTable->addFromSource($this->getWriterPartStyle()->allStyles($this->spreadSheet));
308 $this->stylesConditionalHashTable->addFromSource($this->getWriterPartStyle()->allConditionalStyles($this->spreadSheet));
309 $this->fillHashTable->addFromSource($this->getWriterPartStyle()->allFills($this->spreadSheet));
310 $this->fontHashTable->addFromSource($this->getWriterPartStyle()->allFonts($this->spreadSheet));
311 $this->bordersHashTable->addFromSource($this->getWriterPartStyle()->allBorders($this->spreadSheet));
312 $this->numFmtHashTable->addFromSource($this->getWriterPartStyle()->allNumberFormats($this->spreadSheet));
313
314 // Create drawing dictionary
315 $this->drawingHashTable->addFromSource($this->getWriterPartDrawing()->allDrawings($this->spreadSheet));
316
317 $zipContent = [];
318 // Add [Content_Types].xml to ZIP file
319 $zipContent['[Content_Types].xml'] = $this->getWriterPartContentTypes()->writeContentTypes($this->spreadSheet, $this->includeCharts);
320
321 //if hasMacros, add the vbaProject.bin file, Certificate file(if exists)
322 if ($this->spreadSheet->hasMacros()) {
323 $macrosCode = $this->spreadSheet->getMacrosCode();
324 if ($macrosCode !== null) {
325 // we have the code ?
326 $zipContent['xl/vbaProject.bin'] = $macrosCode; //allways in 'xl', allways named vbaProject.bin
327 if ($this->spreadSheet->hasMacrosCertificate()) {
328 //signed macros ?
329 // Yes : add the certificate file and the related rels file
330 $zipContent['xl/vbaProjectSignature.bin'] = $this->spreadSheet->getMacrosCertificate();
331 $zipContent['xl/_rels/vbaProject.bin.rels'] = $this->getWriterPartRelsVBA()->writeVBARelationships($this->spreadSheet);
332 }
333 }
334 }
335 //a custom UI in this workbook ? add it ("base" xml and additional objects (pictures) and rels)
336 if ($this->spreadSheet->hasRibbon()) {
337 $tmpRibbonTarget = $this->spreadSheet->getRibbonXMLData('target');
338 $zipContent[$tmpRibbonTarget] = $this->spreadSheet->getRibbonXMLData('data');
339 if ($this->spreadSheet->hasRibbonBinObjects()) {
340 $tmpRootPath = dirname($tmpRibbonTarget) . '/';
341 $ribbonBinObjects = $this->spreadSheet->getRibbonBinObjects('data'); //the files to write
342 foreach ($ribbonBinObjects as $aPath => $aContent) {
343 $zipContent[$tmpRootPath . $aPath] = $aContent;
344 }
345 //the rels for files
346 $zipContent[$tmpRootPath . '_rels/' . basename($tmpRibbonTarget) . '.rels'] = $this->getWriterPartRelsRibbon()->writeRibbonRelationships($this->spreadSheet);
347 }
348 }
349
350 // Add relationships to ZIP file
351 $zipContent['_rels/.rels'] = $this->getWriterPartRels()->writeRelationships($this->spreadSheet);
352 $zipContent['xl/_rels/workbook.xml.rels'] = $this->getWriterPartRels()->writeWorkbookRelationships($this->spreadSheet);
353
354 // Add document properties to ZIP file
355 $zipContent['docProps/app.xml'] = $this->getWriterPartDocProps()->writeDocPropsApp($this->spreadSheet);
356 $zipContent['docProps/core.xml'] = $this->getWriterPartDocProps()->writeDocPropsCore($this->spreadSheet);
357 $customPropertiesPart = $this->getWriterPartDocProps()->writeDocPropsCustom($this->spreadSheet);
358 if ($customPropertiesPart !== null) {
359 $zipContent['docProps/custom.xml'] = $customPropertiesPart;
360 }
361
362 // Add theme to ZIP file
363 $zipContent['xl/theme/theme1.xml'] = $this->getWriterPartTheme()->writeTheme($this->spreadSheet);
364
365 // Add string table to ZIP file
366 $zipContent['xl/sharedStrings.xml'] = $this->getWriterPartStringTable()->writeStringTable($this->stringTable);
367
368 // Add styles to ZIP file
369 $zipContent['xl/styles.xml'] = $this->getWriterPartStyle()->writeStyles($this->spreadSheet);
370
371 // Add workbook to ZIP file
372 $zipContent['xl/workbook.xml'] = $this->getWriterPartWorkbook()->writeWorkbook($this->spreadSheet, $this->preCalculateFormulas);
373
374 $chartCount = 0;
375 // Add worksheets
376 for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) {
377 $zipContent['xl/worksheets/sheet' . ($i + 1) . '.xml'] = $this->getWriterPartWorksheet()->writeWorksheet($this->spreadSheet->getSheet($i), $this->stringTable, $this->includeCharts);
378 if ($this->includeCharts) {
379 $charts = $this->spreadSheet->getSheet($i)->getChartCollection();
380 if (count($charts) > 0) {
381 foreach ($charts as $chart) {
382 $zipContent['xl/charts/chart' . ($chartCount + 1) . '.xml'] = $this->getWriterPartChart()->writeChart($chart, $this->preCalculateFormulas);
383 ++$chartCount;
384 }
385 }
386 }
387 }
388
389 $chartRef1 = 0;
390 // Add worksheet relationships (drawings, ...)
391 for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) {
392 // Add relationships
393 $zipContent['xl/worksheets/_rels/sheet' . ($i + 1) . '.xml.rels'] = $this->getWriterPartRels()->writeWorksheetRelationships($this->spreadSheet->getSheet($i), ($i + 1), $this->includeCharts);
394
395 // Add unparsedLoadedData
396 $sheetCodeName = $this->spreadSheet->getSheet($i)->getCodeName();
397 $unparsedLoadedData = $this->spreadSheet->getUnparsedLoadedData();
398 if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['ctrlProps'])) {
399 foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['ctrlProps'] as $ctrlProp) {
400 $zipContent[$ctrlProp['filePath']] = $ctrlProp['content'];
401 }
402 }
403 if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['printerSettings'])) {
404 foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['printerSettings'] as $ctrlProp) {
405 $zipContent[$ctrlProp['filePath']] = $ctrlProp['content'];
406 }
407 }
408
409 $drawings = $this->spreadSheet->getSheet($i)->getDrawingCollection();
410 $drawingCount = count($drawings);
411 if ($this->includeCharts) {
412 $chartCount = $this->spreadSheet->getSheet($i)->getChartCount();
413 }
414
415 // Add drawing and image relationship parts
416 if (($drawingCount > 0) || ($chartCount > 0)) {
417 // Drawing relationships
418 $zipContent['xl/drawings/_rels/drawing' . ($i + 1) . '.xml.rels'] = $this->getWriterPartRels()->writeDrawingRelationships($this->spreadSheet->getSheet($i), $chartRef1, $this->includeCharts);
419
420 // Drawings
421 $zipContent['xl/drawings/drawing' . ($i + 1) . '.xml'] = $this->getWriterPartDrawing()->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts);
422 } elseif (isset($unparsedLoadedData['sheets'][$sheetCodeName]['drawingAlternateContents'])) {
423 // Drawings
424 $zipContent['xl/drawings/drawing' . ($i + 1) . '.xml'] = $this->getWriterPartDrawing()->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts);
425 }
426
427 // Add unparsed drawings
428 if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['Drawings'])) {
429 foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['Drawings'] as $relId => $drawingXml) {
430 $drawingFile = array_search($relId, $unparsedLoadedData['sheets'][$sheetCodeName]['drawingOriginalIds']);
431 if ($drawingFile !== false) {
432 $drawingFile = ltrim($drawingFile, '.');
433 $zipContent['xl' . $drawingFile] = $drawingXml;
434 }
435 }
436 }
437
438 // Add comment relationship parts
439 if (count($this->spreadSheet->getSheet($i)->getComments()) > 0) {
440 // VML Comments
441 $zipContent['xl/drawings/vmlDrawing' . ($i + 1) . '.vml'] = $this->getWriterPartComments()->writeVMLComments($this->spreadSheet->getSheet($i));
442
443 // Comments
444 $zipContent['xl/comments' . ($i + 1) . '.xml'] = $this->getWriterPartComments()->writeComments($this->spreadSheet->getSheet($i));
445 }
446
447 // Add unparsed relationship parts
448 if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'])) {
449 foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'] as $vmlDrawing) {
450 $zipContent[$vmlDrawing['filePath']] = $vmlDrawing['content'];
451 }
452 }
453
454 // Add header/footer relationship parts
455 if (count($this->spreadSheet->getSheet($i)->getHeaderFooter()->getImages()) > 0) {
456 // VML Drawings
457 $zipContent['xl/drawings/vmlDrawingHF' . ($i + 1) . '.vml'] = $this->getWriterPartDrawing()->writeVMLHeaderFooterImages($this->spreadSheet->getSheet($i));
458
459 // VML Drawing relationships
460 $zipContent['xl/drawings/_rels/vmlDrawingHF' . ($i + 1) . '.vml.rels'] = $this->getWriterPartRels()->writeHeaderFooterDrawingRelationships($this->spreadSheet->getSheet($i));
461
462 // Media
463 foreach ($this->spreadSheet->getSheet($i)->getHeaderFooter()->getImages() as $image) {
464 $zipContent['xl/media/' . $image->getIndexedFilename()] = file_get_contents($image->getPath());
465 }
466 }
467 }
468
469 // Add media
470 for ($i = 0; $i < $this->getDrawingHashTable()->count(); ++$i) {
471 if ($this->getDrawingHashTable()->getByIndex($i) instanceof WorksheetDrawing) {
472 $imageContents = null;
473 $imagePath = $this->getDrawingHashTable()->getByIndex($i)->getPath();
474 if (strpos($imagePath, 'zip://') !== false) {
475 $imagePath = substr($imagePath, 6);
476 $imagePathSplitted = explode('#', $imagePath);
477
478 $imageZip = new ZipArchive();
479 $imageZip->open($imagePathSplitted[0]);
480 $imageContents = $imageZip->getFromName($imagePathSplitted[1]);
481 $imageZip->close();
482 unset($imageZip);
483 } else {
484 $imageContents = file_get_contents($imagePath);
485 }
486
487 $zipContent['xl/media/' . str_replace(' ', '_', $this->getDrawingHashTable()->getByIndex($i)->getIndexedFilename())] = $imageContents;
488 } elseif ($this->getDrawingHashTable()->getByIndex($i) instanceof MemoryDrawing) {
489 ob_start();
490 call_user_func(
491 $this->getDrawingHashTable()->getByIndex($i)->getRenderingFunction(),
492 $this->getDrawingHashTable()->getByIndex($i)->getImageResource()
493 );
494 $imageContents = ob_get_contents();
495 ob_end_clean();
496
497 $zipContent['xl/media/' . str_replace(' ', '_', $this->getDrawingHashTable()->getByIndex($i)->getIndexedFilename())] = $imageContents;
498 }
499 }
500
501 Functions::setReturnDateType($saveDateReturnType);
502 Calculation::getInstance($this->spreadSheet)->getDebugLog()->setWriteDebugLog($saveDebugLog);
503
504 $this->openFileHandle($pFilename);
505
506 $options = new Archive();
507 $options->setEnableZip64(false);
508 $options->setOutputStream($this->fileHandle);
509
510 $this->zip = new ZipStream(null, $options);
511
512 $this->addZipFiles($zipContent);
513
514 // Close file
515 try {
516 $this->zip->finish();
517 } catch (OverflowException $e) {
518 throw new WriterException('Could not close resource.');
519 }
520
521 $this->maybeCloseFileHandle();
522 }
523
529 public function getSpreadsheet()
530 {
531 return $this->spreadSheet;
532 }
533
541 public function setSpreadsheet(Spreadsheet $spreadsheet)
542 {
543 $this->spreadSheet = $spreadsheet;
544
545 return $this;
546 }
547
553 public function getStringTable()
554 {
555 return $this->stringTable;
556 }
557
563 public function getStyleHashTable()
564 {
566 }
567
574 {
576 }
577
583 public function getFillHashTable()
584 {
586 }
587
593 public function getFontHashTable()
594 {
596 }
597
603 public function getBordersHashTable()
604 {
606 }
607
613 public function getNumFmtHashTable()
614 {
616 }
617
623 public function getDrawingHashTable()
624 {
626 }
627
634 {
636 }
637
645 public function setOffice2003Compatibility($pValue)
646 {
647 $this->office2003compatibility = $pValue;
648
649 return $this;
650 }
651
652 private $pathNames = [];
653
654 private function addZipFile(string $path, string $content): void
655 {
656 if (!in_array($path, $this->pathNames)) {
657 $this->pathNames[] = $path;
658 $this->zip->addFile($path, $content);
659 }
660 }
661
662 private function addZipFiles(array $zipContent): void
663 {
664 foreach ($zipContent as $path => $content) {
665 $this->addZipFile($path, $content);
666 }
667 }
668}
$path
Definition: aliased.php:25
An exception for terminatinating execution or to throw for unit testing.
static getInstance(?Spreadsheet $spreadsheet=null)
Get an instance of this class.
static setReturnDateType($returnDateType)
Set the Return Date Format used by functions that return a date/time (Excel, PHP Serialized Numeric o...
Definition: Functions.php:109
static getReturnDateType()
Return the current Return Date Format for functions that return a date/time (Excel,...
Definition: Functions.php:133
@template T of IComparable
Definition: HashTable.php:9
openFileHandle($filename)
Open file handle.
Definition: BaseWriter.php:102
maybeCloseFileHandle()
Close file handle only if we opened it ourselves.
Definition: BaseWriter.php:123
setOffice2003Compatibility($pValue)
Set Office2003 compatibility.
Definition: Xlsx.php:645
getFontHashTable()
Get \PhpOffice\PhpSpreadsheet\Style\Font HashTable.
Definition: Xlsx.php:593
getStylesConditionalHashTable()
Get Conditional HashTable.
Definition: Xlsx.php:573
getFillHashTable()
Get Fill HashTable.
Definition: Xlsx.php:583
getNumFmtHashTable()
Get NumberFormat HashTable.
Definition: Xlsx.php:613
getSpreadsheet()
Get Spreadsheet object.
Definition: Xlsx.php:529
getOffice2003Compatibility()
Get Office2003 compatibility.
Definition: Xlsx.php:633
setSpreadsheet(Spreadsheet $spreadsheet)
Set Spreadsheet object.
Definition: Xlsx.php:541
getStringTable()
Get string table.
Definition: Xlsx.php:553
getDrawingHashTable()
Get \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\BaseDrawing HashTable.
Definition: Xlsx.php:623
addZipFiles(array $zipContent)
Definition: Xlsx.php:662
save($pFilename)
Save PhpSpreadsheet to file.
Definition: Xlsx.php:289
__construct(Spreadsheet $spreadsheet)
Create a new Xlsx Writer.
Definition: Xlsx.php:183
getBordersHashTable()
Get Borders HashTable.
Definition: Xlsx.php:603
addZipFile(string $path, string $content)
Definition: Xlsx.php:654
getStyleHashTable()
Get Style HashTable.
Definition: Xlsx.php:563
This Exception gets invoked if a counter value exceeds storage size.
$i
Definition: disco.tpl.php:19
Class Version \Option.
Definition: Bigint.php:4