Failed Conditions
Pull Request — master (#3962)
by Owen
11:35
created

Xlsx::determineUseDynamicArrays()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
ccs 0
cts 0
cp 0
cc 3
nc 3
nop 0
crap 12
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Writer;
4
5
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
6
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
7
use PhpOffice\PhpSpreadsheet\HashTable;
8
use PhpOffice\PhpSpreadsheet\Spreadsheet;
9
use PhpOffice\PhpSpreadsheet\Style\Borders;
10
use PhpOffice\PhpSpreadsheet\Style\Conditional;
11
use PhpOffice\PhpSpreadsheet\Style\Fill;
12
use PhpOffice\PhpSpreadsheet\Style\Font;
13
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
14
use PhpOffice\PhpSpreadsheet\Worksheet\BaseDrawing;
15
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing as WorksheetDrawing;
16
use PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing;
17
use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;
18
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\Chart;
19
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\Comments;
20
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\ContentTypes;
21
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\DocProps;
22
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\Drawing;
23
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\Rels;
24
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\RelsRibbon;
25
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\RelsVBA;
26
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\StringTable;
27
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\Style;
28
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\Table;
29
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\Theme;
30
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\Workbook;
31
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\Worksheet;
32
use ZipArchive;
33
use ZipStream\Exception\OverflowException;
34
use ZipStream\ZipStream;
35
36
class Xlsx extends BaseWriter
37
{
38
    /**
39
     * Office2003 compatibility.
40
     */
41
    private bool $office2003compatibility = false;
42
43
    /**
44
     * Private Spreadsheet.
45
     */
46
    private Spreadsheet $spreadSheet;
47
48
    /**
49
     * Private string table.
50
     *
51
     * @var string[]
52
     */
53
    private array $stringTable = [];
54
55
    /**
56
     * Private unique Conditional HashTable.
57
     *
58
     * @var HashTable<Conditional>
59
     */
60
    private HashTable $stylesConditionalHashTable;
61
62
    /**
63
     * Private unique Style HashTable.
64
     *
65
     * @var HashTable<\PhpOffice\PhpSpreadsheet\Style\Style>
66
     */
67
    private HashTable $styleHashTable;
68
69
    /**
70
     * Private unique Fill HashTable.
71
     *
72
     * @var HashTable<Fill>
73
     */
74
    private HashTable $fillHashTable;
75
76
    /**
77
     * Private unique \PhpOffice\PhpSpreadsheet\Style\Font HashTable.
78
     *
79
     * @var HashTable<Font>
80
     */
81
    private HashTable $fontHashTable;
82
83
    /**
84
     * Private unique Borders HashTable.
85
     *
86
     * @var HashTable<Borders>
87
     */
88
    private HashTable $bordersHashTable;
89
90
    /**
91
     * Private unique NumberFormat HashTable.
92
     *
93
     * @var HashTable<NumberFormat>
94
     */
95
    private HashTable $numFmtHashTable;
96
97
    /**
98
     * Private unique \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\BaseDrawing HashTable.
99
     *
100
     * @var HashTable<BaseDrawing>
101
     */
102
    private HashTable $drawingHashTable;
103
104
    /**
105
     * Private handle for zip stream.
106
     */
107
    private ZipStream $zip;
108
109
    private Chart $writerPartChart;
110
111
    private Comments $writerPartComments;
112
113
    private ContentTypes $writerPartContentTypes;
114
115
    private DocProps $writerPartDocProps;
116
117
    private Drawing $writerPartDrawing;
118
119
    private Rels $writerPartRels;
120
121
    private RelsRibbon $writerPartRelsRibbon;
122
123
    private RelsVBA $writerPartRelsVBA;
124
125
    private StringTable $writerPartStringTable;
126
127
    private Style $writerPartStyle;
128
129
    private Theme $writerPartTheme;
130
131
    private Table $writerPartTable;
132
133
    private Workbook $writerPartWorkbook;
134
135
    private Worksheet $writerPartWorksheet;
136
137
    private bool $explicitStyle0 = false;
138
139
    private bool $useCSEArrays = false;
140
141
    private bool $useDynamicArray = false;
142 388
143
    /**
144
     * Create a new Xlsx Writer.
145 388
     */
146
    public function __construct(Spreadsheet $spreadsheet)
147 388
    {
148 388
        // Assign PhpSpreadsheet
149 388
        $this->setSpreadsheet($spreadsheet);
150 388
151 388
        $this->writerPartChart = new Chart($this);
152 388
        $this->writerPartComments = new Comments($this);
153 388
        $this->writerPartContentTypes = new ContentTypes($this);
154 388
        $this->writerPartDocProps = new DocProps($this);
155 388
        $this->writerPartDrawing = new Drawing($this);
156 388
        $this->writerPartRels = new Rels($this);
157 388
        $this->writerPartRelsRibbon = new RelsRibbon($this);
158 388
        $this->writerPartRelsVBA = new RelsVBA($this);
159 388
        $this->writerPartStringTable = new StringTable($this);
160 388
        $this->writerPartStyle = new Style($this);
161
        $this->writerPartTheme = new Theme($this);
162
        $this->writerPartTable = new Table($this);
163 388
        $this->writerPartWorkbook = new Workbook($this);
164 388
        $this->writerPartWorksheet = new Worksheet($this);
165 388
166 388
        // Set HashTable variables
167 388
        $this->bordersHashTable = new HashTable();
168 388
        $this->drawingHashTable = new HashTable();
169 388
        $this->fillHashTable = new HashTable();
170
        $this->fontHashTable = new HashTable();
171
        $this->numFmtHashTable = new HashTable();
172 73
        $this->styleHashTable = new HashTable();
173
        $this->stylesConditionalHashTable = new HashTable();
174 73
        $this->determineUseDynamicArrays();
175
    }
176
177 20
    public function getWriterPartChart(): Chart
178
    {
179 20
        return $this->writerPartChart;
180
    }
181
182 334
    public function getWriterPartComments(): Comments
183
    {
184 334
        return $this->writerPartComments;
185
    }
186
187 334
    public function getWriterPartContentTypes(): ContentTypes
188
    {
189 334
        return $this->writerPartContentTypes;
190
    }
191
192 334
    public function getWriterPartDocProps(): DocProps
193
    {
194 334
        return $this->writerPartDocProps;
195
    }
196
197 334
    public function getWriterPartDrawing(): Drawing
198
    {
199 334
        return $this->writerPartDrawing;
200
    }
201
202
    public function getWriterPartRels(): Rels
203
    {
204
        return $this->writerPartRels;
205
    }
206
207 2
    public function getWriterPartRelsRibbon(): RelsRibbon
208
    {
209 2
        return $this->writerPartRelsRibbon;
210
    }
211
212 386
    public function getWriterPartRelsVBA(): RelsVBA
213
    {
214 386
        return $this->writerPartRelsVBA;
215
    }
216
217 335
    public function getWriterPartStringTable(): StringTable
218
    {
219 335
        return $this->writerPartStringTable;
220
    }
221
222 334
    public function getWriterPartStyle(): Style
223
    {
224 334
        return $this->writerPartStyle;
225
    }
226
227 7
    public function getWriterPartTheme(): Theme
228
    {
229 7
        return $this->writerPartTheme;
230
    }
231
232 334
    public function getWriterPartTable(): Table
233
    {
234 334
        return $this->writerPartTable;
235
    }
236
237 334
    public function getWriterPartWorkbook(): Workbook
238
    {
239 334
        return $this->writerPartWorkbook;
240
    }
241
242
    public function getWriterPartWorksheet(): Worksheet
243
    {
244
        return $this->writerPartWorksheet;
245
    }
246
247 334
    /**
248
     * Save PhpSpreadsheet to file.
249 334
     *
250
     * @param resource|string $filename
251
     */
252 334
    public function save($filename, int $flags = 0): void
253 334
    {
254
        $this->processFlags($flags);
255 334
        $this->determineUseDynamicArrays();
256 334
257 334
        // garbage collect
258 334
        $this->pathNames = [];
259
        $this->spreadSheet->garbageCollect();
260
261 334
        $saveDebugLog = Calculation::getInstance($this->spreadSheet)->getDebugLog()->getWriteDebugLog();
262 334
        Calculation::getInstance($this->spreadSheet)->getDebugLog()->setWriteDebugLog(false);
263 334
        $saveDateReturnType = Functions::getReturnDateType();
264
        Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
265
266
        // Create string lookup table
267 334
        $this->stringTable = [];
268 334
        for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) {
269 334
            $this->stringTable = $this->getWriterPartStringTable()->createStringTable($this->spreadSheet->getSheet($i), $this->stringTable);
270 334
        }
271 334
272 334
        // Create styles dictionaries
273
        $this->styleHashTable->addFromSource($this->getWriterPartStyle()->allStyles($this->spreadSheet));
274
        $this->stylesConditionalHashTable->addFromSource($this->getWriterPartStyle()->allConditionalStyles($this->spreadSheet));
275 334
        $this->fillHashTable->addFromSource($this->getWriterPartStyle()->allFills($this->spreadSheet));
276
        $this->fontHashTable->addFromSource($this->getWriterPartStyle()->allFonts($this->spreadSheet));
277 334
        $this->bordersHashTable->addFromSource($this->getWriterPartStyle()->allBorders($this->spreadSheet));
278
        $this->numFmtHashTable->addFromSource($this->getWriterPartStyle()->allNumberFormats($this->spreadSheet));
279 334
280
        // Create drawing dictionary
281
        $this->drawingHashTable->addFromSource($this->getWriterPartDrawing()->allDrawings($this->spreadSheet));
282 334
283 2
        $zipContent = [];
284 2
        // Add [Content_Types].xml to ZIP file
285
        $zipContent['[Content_Types].xml'] = $this->getWriterPartContentTypes()->writeContentTypes($this->spreadSheet, $this->includeCharts);
286 2
        $metadataData = (new Xlsx\Metadata($this))->writeMetadata();
287 2
        if ($metadataData !== '') {
288
            $zipContent['xl/metadata.xml'] = $metadataData;
289
        }
290 2
291 2
        //if hasMacros, add the vbaProject.bin file, Certificate file(if exists)
292
        if ($this->spreadSheet->hasMacros()) {
293
            $macrosCode = $this->spreadSheet->getMacrosCode();
294
            if ($macrosCode !== null) {
295
                // we have the code ?
296 334
                $zipContent['xl/vbaProject.bin'] = $macrosCode; //allways in 'xl', allways named vbaProject.bin
297 2
                if ($this->spreadSheet->hasMacrosCertificate()) {
298 2
                    //signed macros ?
299 2
                    // Yes : add the certificate file and the related rels file
300 2
                    $zipContent['xl/vbaProjectSignature.bin'] = $this->spreadSheet->getMacrosCertificate();
301
                    $zipContent['xl/_rels/vbaProject.bin.rels'] = $this->getWriterPartRelsVBA()->writeVBARelationships();
302
                }
303
            }
304
        }
305
        //a custom UI in this workbook ? add it ("base" xml and additional objects (pictures) and rels)
306
        if ($this->spreadSheet->hasRibbon()) {
307
            $tmpRibbonTarget = $this->spreadSheet->getRibbonXMLData('target');
308
            $tmpRibbonTarget = is_string($tmpRibbonTarget) ? $tmpRibbonTarget : '';
309
            $zipContent[$tmpRibbonTarget] = $this->spreadSheet->getRibbonXMLData('data');
310
            if ($this->spreadSheet->hasRibbonBinObjects()) {
311
                $tmpRootPath = dirname($tmpRibbonTarget) . '/';
312
                $ribbonBinObjects = $this->spreadSheet->getRibbonBinObjects('data'); //the files to write
313
                if (is_array($ribbonBinObjects)) {
314 334
                    foreach ($ribbonBinObjects as $aPath => $aContent) {
315 334
                        $zipContent[$tmpRootPath . $aPath] = $aContent;
316
                    }
317
                }
318 334
                //the rels for files
319 334
                $zipContent[$tmpRootPath . '_rels/' . basename($tmpRibbonTarget) . '.rels'] = $this->getWriterPartRelsRibbon()->writeRibbonRelationships($this->spreadSheet);
320 334
            }
321 334
        }
322 26
323
        // Add relationships to ZIP file
324
        $zipContent['_rels/.rels'] = $this->getWriterPartRels()->writeRelationships($this->spreadSheet);
325
        $zipContent['xl/_rels/workbook.xml.rels'] = $this->getWriterPartRels()->writeWorkbookRelationships($this->spreadSheet);
326 334
327
        // Add document properties to ZIP file
328
        $zipContent['docProps/app.xml'] = $this->getWriterPartDocProps()->writeDocPropsApp($this->spreadSheet);
329 334
        $zipContent['docProps/core.xml'] = $this->getWriterPartDocProps()->writeDocPropsCore($this->spreadSheet);
330
        $customPropertiesPart = $this->getWriterPartDocProps()->writeDocPropsCustom($this->spreadSheet);
331
        if ($customPropertiesPart !== null) {
332 334
            $zipContent['docProps/custom.xml'] = $customPropertiesPart;
333
        }
334
335 334
        // Add theme to ZIP file
336
        $zipContent['xl/theme/theme1.xml'] = $this->getWriterPartTheme()->writeTheme($this->spreadSheet);
337 334
338
        // Add string table to ZIP file
339 334
        $zipContent['xl/sharedStrings.xml'] = $this->getWriterPartStringTable()->writeStringTable($this->stringTable);
340 334
341 333
        // Add styles to ZIP file
342 75
        $zipContent['xl/styles.xml'] = $this->getWriterPartStyle()->writeStyles($this->spreadSheet);
343 75
344 73
        // Add workbook to ZIP file
345 73
        $zipContent['xl/workbook.xml'] = $this->getWriterPartWorkbook()->writeWorkbook($this->spreadSheet, $this->preCalculateFormulas);
346 73
347
        $chartCount = 0;
348
        // Add worksheets
349
        for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) {
350
            $zipContent['xl/worksheets/sheet' . ($i + 1) . '.xml'] = $this->getWriterPartWorksheet()->writeWorksheet($this->spreadSheet->getSheet($i), $this->stringTable, $this->includeCharts);
351
            if ($this->includeCharts) {
352 333
                $charts = $this->spreadSheet->getSheet($i)->getChartCollection();
353 333
                if (count($charts) > 0) {
354
                    foreach ($charts as $chart) {
355 333
                        $zipContent['xl/charts/chart' . ($chartCount + 1) . '.xml'] = $this->getWriterPartChart()->writeChart($chart, $this->preCalculateFormulas);
356
                        ++$chartCount;
357 333
                    }
358
                }
359
            }
360 333
        }
361 333
362 333
        $chartRef1 = 0;
363 3
        $tableRef1 = 1;
364 3
        // Add worksheet relationships (drawings, ...)
365
        for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) {
366
            // Add relationships
367 333
            $zipContent['xl/worksheets/_rels/sheet' . ($i + 1) . '.xml.rels'] = $this->getWriterPartRels()->writeWorksheetRelationships($this->spreadSheet->getSheet($i), ($i + 1), $this->includeCharts, $tableRef1, $zipContent);
368 32
369 32
            // Add unparsedLoadedData
370
            $sheetCodeName = $this->spreadSheet->getSheet($i)->getCodeName();
371
            $unparsedLoadedData = $this->spreadSheet->getUnparsedLoadedData();
372
            if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['ctrlProps'])) {
373 333
                foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['ctrlProps'] as $ctrlProp) {
374 333
                    $zipContent[$ctrlProp['filePath']] = $ctrlProp['content'];
375 333
                }
376 75
            }
377
            if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['printerSettings'])) {
378
                foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['printerSettings'] as $ctrlProp) {
379
                    $zipContent[$ctrlProp['filePath']] = $ctrlProp['content'];
380 333
                }
381
            }
382 109
383
            $drawings = $this->spreadSheet->getSheet($i)->getDrawingCollection();
384
            $drawingCount = count($drawings);
385 109
            if ($this->includeCharts) {
386 239
                $chartCount = $this->spreadSheet->getSheet($i)->getChartCount();
387
            }
388 3
389
            // Add drawing and image relationship parts
390
            if (($drawingCount > 0) || ($chartCount > 0)) {
391
                // Drawing relationships
392 333
                $zipContent['xl/drawings/_rels/drawing' . ($i + 1) . '.xml.rels'] = $this->getWriterPartRels()->writeDrawingRelationships($this->spreadSheet->getSheet($i), $chartRef1, $this->includeCharts);
393 5
394 5
                // Drawings
395 5
                $zipContent['xl/drawings/drawing' . ($i + 1) . '.xml'] = $this->getWriterPartDrawing()->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts);
396
            } elseif (isset($unparsedLoadedData['sheets'][$sheetCodeName]['drawingAlternateContents'])) {
397
                // Drawings
398 5
                $zipContent['xl/drawings/drawing' . ($i + 1) . '.xml'] = $this->getWriterPartDrawing()->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts);
399
            }
400
401
            // Add unparsed drawings
402 333
            if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['Drawings']) && !isset($zipContent['xl/drawings/drawing' . ($i + 1) . '.xml'])) {
403 1
                foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['Drawings'] as $relId => $drawingXml) {
404
                    $drawingFile = array_search($relId, $unparsedLoadedData['sheets'][$sheetCodeName]['drawingOriginalIds']);
405
                    if ($drawingFile !== false) {
406
                        //$drawingFile = ltrim($drawingFile, '.');
407 333
                        //$zipContent['xl' . $drawingFile] = $drawingXml;
408 333
                        $zipContent['xl/drawings/drawing' . ($i + 1) . '.xml'] = $drawingXml;
409
                    }
410 22
                }
411
            }
412
            if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['drawingOriginalIds']) && !isset($zipContent['xl/drawings/drawing' . ($i + 1) . '.xml'])) {
413 22
                $zipContent['xl/drawings/drawing' . ($i + 1) . '.xml'] = '<xml></xml>';
414
            }
415
416
            // Add comment relationship parts
417 333
            $legacy = $unparsedLoadedData['sheets'][$this->spreadSheet->getSheet($i)->getCodeName()]['legacyDrawing'] ?? null;
418 20
            if (count($this->spreadSheet->getSheet($i)->getComments()) > 0 || $legacy !== null) {
419
                // VML Comments relationships
420
                $zipContent['xl/drawings/_rels/vmlDrawing' . ($i + 1) . '.vml.rels'] = $this->getWriterPartRels()->writeVMLDrawingRelationships($this->spreadSheet->getSheet($i));
421 20
422 20
                // VML Comments
423 3
                $zipContent['xl/drawings/vmlDrawing' . ($i + 1) . '.vml'] = $legacy ?? $this->getWriterPartComments()->writeVMLComments($this->spreadSheet->getSheet($i));
424 3
            }
425
426
            // Comments
427
            if (count($this->spreadSheet->getSheet($i)->getComments()) > 0) {
428
                $zipContent['xl/comments' . ($i + 1) . '.xml'] = $this->getWriterPartComments()->writeComments($this->spreadSheet->getSheet($i));
429
430 333
                // Media
431 5
                foreach ($this->spreadSheet->getSheet($i)->getComments() as $comment) {
432 5
                    if ($comment->hasBackgroundImage()) {
433 3
                        $image = $comment->getBackgroundImage();
434
                        $zipContent['xl/media/' . $image->getMediaFilename()] = $this->processDrawing($image);
435
                    }
436
                }
437
            }
438
439 333
            // Add unparsed relationship parts
440
            if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'])) {
441 3
                foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'] as $vmlDrawing) {
442
                    if (!isset($zipContent[$vmlDrawing['filePath']])) {
443
                        $zipContent[$vmlDrawing['filePath']] = $vmlDrawing['content'];
444 3
                    }
445
                }
446
            }
447 3
448 3
            // Add header/footer relationship parts
449
            if (count($this->spreadSheet->getSheet($i)->getHeaderFooter()->getImages()) > 0) {
450
                // VML Drawings
451
                $zipContent['xl/drawings/vmlDrawingHF' . ($i + 1) . '.vml'] = $this->getWriterPartDrawing()->writeVMLHeaderFooterImages($this->spreadSheet->getSheet($i));
452
453 333
                // VML Drawing relationships
454 333
                $zipContent['xl/drawings/_rels/vmlDrawingHF' . ($i + 1) . '.vml.rels'] = $this->getWriterPartRels()->writeHeaderFooterDrawingRelationships($this->spreadSheet->getSheet($i));
455 7
456
                // Media
457
                foreach ($this->spreadSheet->getSheet($i)->getHeaderFooter()->getImages() as $image) {
458
                    $zipContent['xl/media/' . $image->getIndexedFilename()] = file_get_contents($image->getPath());
459
                }
460 333
            }
461 47
462 36
            // Add Table parts
463 36
            $tables = $this->spreadSheet->getSheet($i)->getTableCollection();
464 36
            foreach ($tables as $table) {
465 23
                $zipContent['xl/tables/table' . $tableRef1 . '.xml'] = $this->getWriterPartTable()->writeTable($table, $tableRef1++);
466 23
            }
467
        }
468 23
469 23
        // Add media
470 23
        for ($i = 0; $i < $this->getDrawingHashTable()->count(); ++$i) {
471 23
            if ($this->getDrawingHashTable()->getByIndex($i) instanceof WorksheetDrawing) {
472 23
                $imageContents = null;
473
                $imagePath = $this->getDrawingHashTable()->getByIndex($i)->getPath();
1 ignored issue
show
Bug introduced by
The method getPath() does not exist on PhpOffice\PhpSpreadsheet\IComparable. It seems like you code against a sub-type of PhpOffice\PhpSpreadsheet\IComparable such as PhpOffice\PhpSpreadsheet\Worksheet\Drawing. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

473
                $imagePath = $this->getDrawingHashTable()->getByIndex($i)->/** @scrutinizer ignore-call */ getPath();
Loading history...
474 15
                if (str_contains($imagePath, 'zip://')) {
475
                    $imagePath = substr($imagePath, 6);
476
                    $imagePathSplitted = explode('#', $imagePath);
477 36
478 11
                    $imageZip = new ZipArchive();
479 11
                    $imageZip->open($imagePathSplitted[0]);
480
                    $imageContents = $imageZip->getFromName($imagePathSplitted[1]);
481 11
                    $imageZip->close();
482 11
                    unset($imageZip);
483 11
                } else {
484 11
                    $imageContents = file_get_contents($imagePath);
485 11
                }
486 11
487 11
                $zipContent['xl/media/' . $this->getDrawingHashTable()->getByIndex($i)->getIndexedFilename()] = $imageContents;
1 ignored issue
show
Bug introduced by
The method getIndexedFilename() does not exist on PhpOffice\PhpSpreadsheet\IComparable. It seems like you code against a sub-type of PhpOffice\PhpSpreadsheet\IComparable such as PhpOffice\PhpSpreadsheet\Worksheet\Drawing or PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

487
                $zipContent['xl/media/' . $this->getDrawingHashTable()->getByIndex($i)->/** @scrutinizer ignore-call */ getIndexedFilename()] = $imageContents;
Loading history...
488
            } elseif ($this->getDrawingHashTable()->getByIndex($i) instanceof MemoryDrawing) {
489 11
                ob_start();
490
                /** @var callable $callable */
491
                $callable = $this->getDrawingHashTable()->getByIndex($i)->getRenderingFunction();
1 ignored issue
show
Bug introduced by
The method getRenderingFunction() does not exist on PhpOffice\PhpSpreadsheet\IComparable. It seems like you code against a sub-type of PhpOffice\PhpSpreadsheet\IComparable such as PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

491
                $callable = $this->getDrawingHashTable()->getByIndex($i)->/** @scrutinizer ignore-call */ getRenderingFunction();
Loading history...
492
                call_user_func(
493 333
                    $callable,
494 333
                    $this->getDrawingHashTable()->getByIndex($i)->getImageResource()
1 ignored issue
show
Bug introduced by
The method getImageResource() does not exist on PhpOffice\PhpSpreadsheet\IComparable. It seems like you code against a sub-type of PhpOffice\PhpSpreadsheet\IComparable such as PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

494
                    $this->getDrawingHashTable()->getByIndex($i)->/** @scrutinizer ignore-call */ getImageResource()
Loading history...
495
                );
496 333
                $imageContents = ob_get_contents();
497
                ob_end_clean();
498 333
499
                $zipContent['xl/media/' . $this->getDrawingHashTable()->getByIndex($i)->getIndexedFilename()] = $imageContents;
500 333
            }
501
        }
502
503
        Functions::setReturnDateType($saveDateReturnType);
504 333
        Calculation::getInstance($this->spreadSheet)->getDebugLog()->setWriteDebugLog($saveDebugLog);
505
506
        $this->openFileHandle($filename);
507
508
        $this->zip = ZipStream0::newZipStream($this->fileHandle);
509 333
510
        $this->addZipFiles($zipContent);
511
512
        // Close file
513
        try {
514
            $this->zip->finish();
515 386
        } catch (OverflowException) {
516
            throw new WriterException('Could not close resource.');
517 386
        }
518
519
        $this->maybeCloseFileHandle();
520
    }
521
522
    /**
523
     * Get Spreadsheet object.
524
     */
525
    public function getSpreadsheet(): Spreadsheet
526
    {
527 388
        return $this->spreadSheet;
528
    }
529 388
530
    /**
531 388
     * Set Spreadsheet object.
532
     *
533
     * @param Spreadsheet $spreadsheet PhpSpreadsheet object
534
     *
535
     * @return $this
536
     */
537
    public function setSpreadsheet(Spreadsheet $spreadsheet): static
538
    {
539
        $this->spreadSheet = $spreadsheet;
540
541
        return $this;
542
    }
543
544
    /**
545
     * Get string table.
546
     *
547
     * @return string[]
548
     */
549
    public function getStringTable(): array
550
    {
551
        return $this->stringTable;
552
    }
553
554
    /**
555
     * Get Style HashTable.
556
     *
557
     * @return HashTable<\PhpOffice\PhpSpreadsheet\Style\Style>
558
     */
559 369
    public function getStyleHashTable(): HashTable
560
    {
561 369
        return $this->styleHashTable;
562
    }
563
564
    /**
565
     * Get Conditional HashTable.
566
     *
567
     * @return HashTable<Conditional>
568
     */
569 335
    public function getStylesConditionalHashTable(): HashTable
570
    {
571 335
        return $this->stylesConditionalHashTable;
572
    }
573
574
    /**
575
     * Get Fill HashTable.
576
     *
577
     * @return HashTable<Fill>
578
     */
579 335
    public function getFillHashTable(): HashTable
580
    {
581 335
        return $this->fillHashTable;
582
    }
583
584
    /**
585
     * Get \PhpOffice\PhpSpreadsheet\Style\Font HashTable.
586
     *
587
     * @return HashTable<Font>
588
     */
589 335
    public function getFontHashTable(): HashTable
590
    {
591 335
        return $this->fontHashTable;
592
    }
593
594
    /**
595
     * Get Borders HashTable.
596
     *
597
     * @return HashTable<Borders>
598
     */
599 335
    public function getBordersHashTable(): HashTable
600
    {
601 335
        return $this->bordersHashTable;
602
    }
603
604
    /**
605
     * Get NumberFormat HashTable.
606
     *
607
     * @return HashTable<NumberFormat>
608
     */
609 334
    public function getNumFmtHashTable(): HashTable
610
    {
611 334
        return $this->numFmtHashTable;
612
    }
613
614
    /**
615
     * Get \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\BaseDrawing HashTable.
616
     *
617 334
     * @return HashTable<BaseDrawing>
618
     */
619 334
    public function getDrawingHashTable(): HashTable
620
    {
621
        return $this->drawingHashTable;
622
    }
623
624
    /**
625
     * Get Office2003 compatibility.
626
     */
627
    public function getOffice2003Compatibility(): bool
628
    {
629
        return $this->office2003compatibility;
630
    }
631
632
    /**
633
     * Set Office2003 compatibility.
634
     *
635
     * @param bool $office2003compatibility Office2003 compatibility?
636
     *
637
     * @return $this
638 333
     */
639
    public function setOffice2003Compatibility(bool $office2003compatibility): static
640 333
    {
641 333
        $this->office2003compatibility = $office2003compatibility;
642 333
643
        return $this;
644
    }
645
646 333
    private array $pathNames = [];
647
648 333
    private function addZipFile(string $path, string $content): void
649 333
    {
650
        if (!in_array($path, $this->pathNames)) {
651
            $this->pathNames[] = $path;
652
            $this->zip->addFile($path, $content);
653 3
        }
654
    }
655 3
656 3
    private function addZipFiles(array $zipContent): void
657 3
    {
658
        foreach ($zipContent as $path => $content) {
659 3
            $this->addZipFile($path, $content);
660 3
        }
661 3
    }
662 2
663 2
    private function processDrawing(WorksheetDrawing $drawing): string|null|false
664 2
    {
665 2
        $data = null;
666 2
        $filename = $drawing->getPath();
667 2
        $imageData = getimagesize($filename);
668
669
        if (!empty($imageData)) {
670 2
            switch ($imageData[2]) {
671
                case 1: // GIF, not supported by BIFF8, we convert to PNG
672 3
                    $image = imagecreatefromgif($filename);
673 2
                    if ($image !== false) {
674
                        ob_start();
675 2
                        imagepng($image);
676
                        $data = ob_get_contents();
677 2
                        ob_end_clean();
678 1
                    }
679
680 1
                    break;
681
682 2
                case 2: // JPEG
683 2
                    $data = file_get_contents($filename);
684 2
685 2
                    break;
686 2
687 2
                case 3: // PNG
688 2
                    $data = file_get_contents($filename);
689
690
                    break;
691 2
692
                case 6: // Windows DIB (BMP), we convert to PNG
693
                    $image = imagecreatefrombmp($filename);
694
                    if ($image !== false) {
695 3
                        ob_start();
696
                        imagepng($image);
697
                        $data = ob_get_contents();
698 373
                        ob_end_clean();
699
                    }
700 373
701
                    break;
702
            }
703
        }
704
705
        return $data;
706
    }
707
708 1
    public function getExplicitStyle0(): bool
709
    {
710 1
        return $this->explicitStyle0;
711
    }
712 1
713
    /**
714
     * This may be useful if non-default Alignment is part of default style
715
     * and you think you might want to open the spreadsheet
716
     * with LibreOffice or Gnumeric.
717
     */
718
    public function setExplicitStyle0(bool $explicitStyle0): self
719
    {
720
        $this->explicitStyle0 = $explicitStyle0;
721
722
        return $this;
723
    }
724
725
    public function setUseCSEArrays(?bool $useCSEArrays): void
726
    {
727
        if ($useCSEArrays !== null) {
728
            $this->useCSEArrays = $useCSEArrays;
729
        }
730
        $this->determineUseDynamicArrays();
731
    }
732
733
    public function useDynamicArrays(): bool
734
    {
735
        return $this->useDynamicArray;
736
    }
737
738
    private function determineUseDynamicArrays(): void
739
    {
740
        $this->useDynamicArray = $this->preCalculateFormulas && Calculation::getInstance($this->spreadSheet)->getInstanceArrayReturnType() === Calculation::RETURN_ARRAY_AS_ARRAY && !$this->useCSEArrays;
741
    }
742
}
743