Completed
Push — develop ( 2922a1...cfa1fe )
by Adrien
24:40
created

Excel2007::castToFormula()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 24
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 15
nc 3
nop 7
dl 0
loc 24
rs 8.6845
c 1
b 0
f 0
ccs 0
cts 19
cp 0
crap 20
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Reader;
4
5
/**
6
 * Copyright (c) 2006 - 2016 PhpSpreadsheet
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21
 *
22
 * @category   PhpSpreadsheet
23
 * @copyright  Copyright (c) 2006 - 2016 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
24
 * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
25
 * @version    ##VERSION##, ##DATE##
26
 */
27
class Excel2007 extends BaseReader implements IReader
28
{
29
    /**
30
     * ReferenceHelper instance
31
     *
32
     * @var \PhpOffice\PhpSpreadsheet\ReferenceHelper
33
     */
34
    private $referenceHelper = null;
35
36
    /**
37
     * Excel2007\Theme instance
38
     *
39
     * @var Excel2007\Theme
40
     */
41
    private static $theme = null;
42
43
    /**
44
     * Create a new Excel2007 Reader instance
45
     */
46
    public function __construct()
47
    {
48
        $this->readFilter = new DefaultReadFilter();
49
        $this->referenceHelper = \PhpOffice\PhpSpreadsheet\ReferenceHelper::getInstance();
50
    }
51
52
    /**
53
     * Can the current IReader read the file?
54
     *
55
     * @param    string         $pFilename
56
     * @throws   Exception
57
     * @return   bool
58
     */
59
    public function canRead($pFilename)
60
    {
61
        // Check if file exists
62
        if (!file_exists($pFilename)) {
63
            throw new Exception('Could not open ' . $pFilename . ' for reading! File does not exist.');
64
        }
65
66
        $zipClass = \PhpOffice\PhpSpreadsheet\Settings::getZipClass();
67
68
        // Check if zip class exists
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
69
//        if (!class_exists($zipClass, false)) {
70
//            throw new Exception($zipClass . " library is not enabled");
71
//        }
72
73
        $xl = false;
74
        // Load file
75
        $zip = new $zipClass();
76
        if ($zip->open($pFilename) === true) {
77
            // check if it is an OOXML archive
78
            $rels = simplexml_load_string(
79
                $this->securityScan(
80
                    $this->getFromZipArchive($zip, '_rels/.rels')
81
                ),
82
                'SimpleXMLElement',
83
                \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
84
            );
85
            if ($rels !== false) {
86
                foreach ($rels->Relationship as $rel) {
87
                    switch ($rel['Type']) {
88
                        case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument':
89
                            if (basename($rel['Target']) == 'workbook.xml') {
90
                                $xl = true;
91
                            }
92
                            break;
93
                    }
94
                }
95
            }
96
            $zip->close();
97
        }
98
99
        return $xl;
100
    }
101
102
    /**
103
     * Reads names of the worksheets from a file, without parsing the whole file to a Spreadsheet object
104
     *
105
     * @param    string         $pFilename
106
     * @throws   Exception
107
     */
108
    public function listWorksheetNames($pFilename)
109
    {
110
        // Check if file exists
111
        if (!file_exists($pFilename)) {
112
            throw new Exception('Could not open ' . $pFilename . ' for reading! File does not exist.');
113
        }
114
115
        $worksheetNames = [];
116
117
        $zipClass = \PhpOffice\PhpSpreadsheet\Settings::getZipClass();
118
119
        $zip = new $zipClass();
120
        $zip->open($pFilename);
121
122
        //    The files we're looking at here are small enough that simpleXML is more efficient than XMLReader
123
        $rels = simplexml_load_string(
124
            $this->securityScan(
125
                $this->getFromZipArchive($zip, '_rels/.rels'),
126
                'SimpleXMLElement',
0 ignored issues
show
Unused Code introduced by
The call to Excel2007::securityScan() has too many arguments starting with 'SimpleXMLElement'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
127
                \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
128
            )
129
        ); //~ http://schemas.openxmlformats.org/package/2006/relationships");
130
        foreach ($rels->Relationship as $rel) {
131
            switch ($rel['Type']) {
132
                case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument':
133
                    $xmlWorkbook = simplexml_load_string(
134
                        $this->securityScan(
135
                            $this->getFromZipArchive($zip, "{$rel['Target']}"),
136
                            'SimpleXMLElement',
0 ignored issues
show
Unused Code introduced by
The call to Excel2007::securityScan() has too many arguments starting with 'SimpleXMLElement'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
137
                            \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
138
                        )
139
                    ); //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
140
141
                    if ($xmlWorkbook->sheets) {
142
                        foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
143
                            // Check if sheet should be skipped
144
                            $worksheetNames[] = (string) $eleSheet['name'];
145
                        }
146
                    }
147
            }
148
        }
149
150
        $zip->close();
151
152
        return $worksheetNames;
153
    }
154
155
    /**
156
     * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
157
     *
158
     * @param   string     $pFilename
159
     * @throws  Exception
160
     */
161
    public function listWorksheetInfo($pFilename)
162
    {
163
        // Check if file exists
164
        if (!file_exists($pFilename)) {
165
            throw new Exception('Could not open ' . $pFilename . ' for reading! File does not exist.');
166
        }
167
168
        $worksheetInfo = [];
169
170
        $zipClass = \PhpOffice\PhpSpreadsheet\Settings::getZipClass();
171
172
        $zip = new $zipClass();
173
        $zip->open($pFilename);
174
175
        $rels = simplexml_load_string(
176
            //~ http://schemas.openxmlformats.org/package/2006/relationships"
177
            $this->securityScan($this->getFromZipArchive($zip, '_rels/.rels')),
178
            'SimpleXMLElement',
179
            \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
180
        );
181
        foreach ($rels->Relationship as $rel) {
182
            if ($rel['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument') {
183
                $dir = dirname($rel['Target']);
184
                $relsWorkbook = simplexml_load_string(
185
                    //~ http://schemas.openxmlformats.org/package/2006/relationships"
186
                    $this->securityScan(
187
                        $this->getFromZipArchive($zip, "$dir/_rels/" . basename($rel['Target']) . '.rels')
188
                    ),
189
                    'SimpleXMLElement',
190
                    \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
191
                );
192
                $relsWorkbook->registerXPathNamespace('rel', 'http://schemas.openxmlformats.org/package/2006/relationships');
193
194
                $worksheets = [];
195
                foreach ($relsWorkbook->Relationship as $ele) {
196
                    if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet') {
197
                        $worksheets[(string) $ele['Id']] = $ele['Target'];
198
                    }
199
                }
200
201
                $xmlWorkbook = simplexml_load_string(
202
                    //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
203
                    $this->securityScan(
204
                        $this->getFromZipArchive($zip, "{$rel['Target']}")
205
                    ),
206
                    'SimpleXMLElement',
207
                    \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
208
                );
209
                if ($xmlWorkbook->sheets) {
210
                    $dir = dirname($rel['Target']);
211
                    foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
212
                        $tmpInfo = [
213
                            'worksheetName' => (string) $eleSheet['name'],
214
                            'lastColumnLetter' => 'A',
215
                            'lastColumnIndex' => 0,
216
                            'totalRows' => 0,
217
                            'totalColumns' => 0,
218
                        ];
219
220
                        $fileWorksheet = $worksheets[(string) self::getArrayItem($eleSheet->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id')];
221
222
                        $xml = new \XMLReader();
223
                        $res = $xml->xml(
0 ignored issues
show
Unused Code introduced by
$res is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
224
                            $this->securityScanFile(
225
                                'zip://' . \PhpOffice\PhpSpreadsheet\Shared\File::realpath($pFilename) . '#' . "$dir/$fileWorksheet"
226
                            ),
227
                            null,
228
                            \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
229
                        );
230
                        $xml->setParserProperty(2, true);
231
232
                        $currCells = 0;
233
                        while ($xml->read()) {
234
                            if ($xml->name == 'row' && $xml->nodeType == \XMLReader::ELEMENT) {
235
                                $row = $xml->getAttribute('r');
236
                                $tmpInfo['totalRows'] = $row;
237
                                $tmpInfo['totalColumns'] = max($tmpInfo['totalColumns'], $currCells);
238
                                $currCells = 0;
239
                            } elseif ($xml->name == 'c' && $xml->nodeType == \XMLReader::ELEMENT) {
240
                                ++$currCells;
241
                            }
242
                        }
243
                        $tmpInfo['totalColumns'] = max($tmpInfo['totalColumns'], $currCells);
244
                        $xml->close();
245
246
                        $tmpInfo['lastColumnIndex'] = $tmpInfo['totalColumns'] - 1;
247
                        $tmpInfo['lastColumnLetter'] = \PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
248
249
                        $worksheetInfo[] = $tmpInfo;
250
                    }
251
                }
252
            }
253
        }
254
255
        $zip->close();
256
257
        return $worksheetInfo;
258
    }
259
260
    private static function castToBoolean($c)
261
    {
262
        $value = isset($c->v) ? (string) $c->v : null;
263
        if ($value == '0') {
264
            return false;
265
        } elseif ($value == '1') {
266
            return true;
267
        } else {
268
            return (bool) $c->v;
269
        }
270
271
        return $value;
0 ignored issues
show
Unused Code introduced by
return $value; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
272
    }
273
274
    private static function castToError($c)
275
    {
276
        return isset($c->v) ? (string) $c->v : null;
277
    }
278
279
    private static function castToString($c)
280
    {
281
        return isset($c->v) ? (string) $c->v : null;
282
    }
283
284
    private function castToFormula($c, $r, &$cellDataType, &$value, &$calculatedValue, &$sharedFormulas, $castBaseType)
285
    {
286
        $cellDataType = 'f';
287
        $value = "={$c->f}";
288
        $calculatedValue = self::$castBaseType($c);
289
290
        // Shared formula?
291
        if (isset($c->f['t']) && strtolower((string) $c->f['t']) == 'shared') {
292
            $instance = (string) $c->f['si'];
293
294
            if (!isset($sharedFormulas[(string) $c->f['si']])) {
295
                $sharedFormulas[$instance] = ['master' => $r, 'formula' => $value];
296
            } else {
297
                $master = \PhpOffice\PhpSpreadsheet\Cell::coordinateFromString($sharedFormulas[$instance]['master']);
298
                $current = \PhpOffice\PhpSpreadsheet\Cell::coordinateFromString($r);
299
300
                $difference = [0, 0];
301
                $difference[0] = \PhpOffice\PhpSpreadsheet\Cell::columnIndexFromString($current[0]) - \PhpOffice\PhpSpreadsheet\Cell::columnIndexFromString($master[0]);
302
                $difference[1] = $current[1] - $master[1];
303
304
                $value = $this->referenceHelper->updateFormulaReferences($sharedFormulas[$instance]['formula'], 'A1', $difference[0], $difference[1]);
305
            }
306
        }
307
    }
308
309
    private function getFromZipArchive($archive, $fileName = '')
310
    {
311
        // Root-relative paths
312
        if (strpos($fileName, '//') !== false) {
313
            $fileName = substr($fileName, strpos($fileName, '//') + 1);
314
        }
315
        $fileName = \PhpOffice\PhpSpreadsheet\Shared\File::realpath($fileName);
316
317
        // Sadly, some 3rd party xlsx generators don't use consistent case for filenaming
318
        //    so we need to load case-insensitively from the zip file
319
320
        // Apache POI fixes
321
        $contents = $archive->getFromIndex(
322
            $archive->locateName($fileName, \ZipArchive::FL_NOCASE)
323
        );
324
        if ($contents === false) {
325
            $contents = $archive->getFromIndex(
326
                $archive->locateName(substr($fileName, 1), \ZipArchive::FL_NOCASE)
327
            );
328
        }
329
330
        return $contents;
331
    }
332
333
    /**
334
     * Loads Spreadsheet from file
335
     *
336
     * @param     string         $pFilename
337
     * @throws    Exception
338
     * @return    Spreadsheet
339
     */
340
    public function load($pFilename)
341
    {
342
        // Check if file exists
343
        if (!file_exists($pFilename)) {
344
            throw new Exception('Could not open ' . $pFilename . ' for reading! File does not exist.');
345
        }
346
347
        // Initialisations
348
        $excel = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
349
        $excel->removeSheetByIndex(0);
350
        if (!$this->readDataOnly) {
351
            $excel->removeCellStyleXfByIndex(0); // remove the default style
352
            $excel->removeCellXfByIndex(0); // remove the default style
353
        }
354
355
        $zipClass = \PhpOffice\PhpSpreadsheet\Settings::getZipClass();
356
357
        $zip = new $zipClass();
358
        $zip->open($pFilename);
359
360
        //    Read the theme first, because we need the colour scheme when reading the styles
361
        $wbRels = simplexml_load_string(
362
            //~ http://schemas.openxmlformats.org/package/2006/relationships"
363
            $this->securityScan($this->getFromZipArchive($zip, 'xl/_rels/workbook.xml.rels')),
364
            'SimpleXMLElement',
365
            \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
366
        );
367
        foreach ($wbRels->Relationship as $rel) {
368
            switch ($rel['Type']) {
369
                case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme':
370
                    $themeOrderArray = ['lt1', 'dk1', 'lt2', 'dk2'];
371
                    $themeOrderAdditional = count($themeOrderArray);
372
373
                    $xmlTheme = simplexml_load_string(
374
                        $this->securityScan($this->getFromZipArchive($zip, "xl/{$rel['Target']}")),
375
                        'SimpleXMLElement',
376
                        \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
377
                    );
378
                    if (is_object($xmlTheme)) {
379
                        $xmlThemeName = $xmlTheme->attributes();
380
                        $xmlTheme = $xmlTheme->children('http://schemas.openxmlformats.org/drawingml/2006/main');
381
                        $themeName = (string) $xmlThemeName['name'];
382
383
                        $colourScheme = $xmlTheme->themeElements->clrScheme->attributes();
384
                        $colourSchemeName = (string) $colourScheme['name'];
385
                        $colourScheme = $xmlTheme->themeElements->clrScheme->children('http://schemas.openxmlformats.org/drawingml/2006/main');
386
387
                        $themeColours = [];
388
                        foreach ($colourScheme as $k => $xmlColour) {
389
                            $themePos = array_search($k, $themeOrderArray);
390
                            if ($themePos === false) {
391
                                $themePos = $themeOrderAdditional++;
392
                            }
393
                            if (isset($xmlColour->sysClr)) {
394
                                $xmlColourData = $xmlColour->sysClr->attributes();
395
                                $themeColours[$themePos] = $xmlColourData['lastClr'];
396
                            } elseif (isset($xmlColour->srgbClr)) {
397
                                $xmlColourData = $xmlColour->srgbClr->attributes();
398
                                $themeColours[$themePos] = $xmlColourData['val'];
399
                            }
400
                        }
401
                        self::$theme = new Excel2007\Theme($themeName, $colourSchemeName, $themeColours);
402
                    }
403
                    break;
404
            }
405
        }
406
407
        $rels = simplexml_load_string(
408
            //~ http://schemas.openxmlformats.org/package/2006/relationships"
409
            $this->securityScan($this->getFromZipArchive($zip, '_rels/.rels')),
410
            'SimpleXMLElement',
411
            \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
412
        );
413
        foreach ($rels->Relationship as $rel) {
414
            switch ($rel['Type']) {
415
                case 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties':
416
                    $xmlCore = simplexml_load_string(
417
                        $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")),
418
                        'SimpleXMLElement',
419
                        \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
420
                    );
421
                    if (is_object($xmlCore)) {
422
                        $xmlCore->registerXPathNamespace('dc', 'http://purl.org/dc/elements/1.1/');
423
                        $xmlCore->registerXPathNamespace('dcterms', 'http://purl.org/dc/terms/');
424
                        $xmlCore->registerXPathNamespace('cp', 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties');
425
                        $docProps = $excel->getProperties();
426
                        $docProps->setCreator((string) self::getArrayItem($xmlCore->xpath('dc:creator')));
427
                        $docProps->setLastModifiedBy((string) self::getArrayItem($xmlCore->xpath('cp:lastModifiedBy')));
428
                        $docProps->setCreated(strtotime(self::getArrayItem($xmlCore->xpath('dcterms:created')))); //! respect xsi:type
0 ignored issues
show
Documentation introduced by
strtotime(self::getArray...th('dcterms:created'))) is of type integer, but the function expects a object<PhpOffice\PhpSpre...Document\datetime>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
429
                        $docProps->setModified(strtotime(self::getArrayItem($xmlCore->xpath('dcterms:modified')))); //! respect xsi:type
0 ignored issues
show
Documentation introduced by
strtotime(self::getArray...h('dcterms:modified'))) is of type integer, but the function expects a object<PhpOffice\PhpSpre...Document\datetime>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
430
                        $docProps->setTitle((string) self::getArrayItem($xmlCore->xpath('dc:title')));
431
                        $docProps->setDescription((string) self::getArrayItem($xmlCore->xpath('dc:description')));
432
                        $docProps->setSubject((string) self::getArrayItem($xmlCore->xpath('dc:subject')));
433
                        $docProps->setKeywords((string) self::getArrayItem($xmlCore->xpath('cp:keywords')));
434
                        $docProps->setCategory((string) self::getArrayItem($xmlCore->xpath('cp:category')));
435
                    }
436
                    break;
437
                case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties':
438
                    $xmlCore = simplexml_load_string(
439
                        $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")),
440
                        'SimpleXMLElement',
441
                        \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
442
                    );
443
                    if (is_object($xmlCore)) {
444
                        $docProps = $excel->getProperties();
445
                        if (isset($xmlCore->Company)) {
446
                            $docProps->setCompany((string) $xmlCore->Company);
447
                        }
448
                        if (isset($xmlCore->Manager)) {
449
                            $docProps->setManager((string) $xmlCore->Manager);
450
                        }
451
                    }
452
                    break;
453
                case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties':
454
                    $xmlCore = simplexml_load_string(
455
                        $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")),
456
                        'SimpleXMLElement',
457
                        \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
458
                    );
459
                    if (is_object($xmlCore)) {
460
                        $docProps = $excel->getProperties();
461
                        foreach ($xmlCore as $xmlProperty) {
462
                            $cellDataOfficeAttributes = $xmlProperty->attributes();
463
                            if (isset($cellDataOfficeAttributes['name'])) {
464
                                $propertyName = (string) $cellDataOfficeAttributes['name'];
465
                                $cellDataOfficeChildren = $xmlProperty->children('http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes');
466
                                $attributeType = $cellDataOfficeChildren->getName();
467
                                $attributeValue = (string) $cellDataOfficeChildren->{$attributeType};
468
                                $attributeValue = \PhpOffice\PhpSpreadsheet\Document\Properties::convertProperty($attributeValue, $attributeType);
469
                                $attributeType = \PhpOffice\PhpSpreadsheet\Document\Properties::convertPropertyType($attributeType);
470
                                $docProps->setCustomProperty($propertyName, $attributeValue, $attributeType);
471
                            }
472
                        }
473
                    }
474
                    break;
475
                //Ribbon
476
                case 'http://schemas.microsoft.com/office/2006/relationships/ui/extensibility':
477
                    $customUI = $rel['Target'];
478
                    if (!is_null($customUI)) {
479
                        $this->readRibbon($excel, $customUI, $zip);
480
                    }
481
                    break;
482
                case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument':
483
                    $dir = dirname($rel['Target']);
484
                    $relsWorkbook = simplexml_load_string(
485
                        //~ http://schemas.openxmlformats.org/package/2006/relationships"
486
                        $this->securityScan($this->getFromZipArchive($zip, "$dir/_rels/" . basename($rel['Target']) . '.rels')),
487
                        'SimpleXMLElement',
488
                        \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
489
                    );
490
                    $relsWorkbook->registerXPathNamespace('rel', 'http://schemas.openxmlformats.org/package/2006/relationships');
491
492
                    $sharedStrings = [];
493
                    $xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings']"));
494
                    $xmlStrings = simplexml_load_string(
495
                        //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
496
                        $this->securityScan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")),
497
                        'SimpleXMLElement',
498
                        \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
499
                    );
500
                    if (isset($xmlStrings) && isset($xmlStrings->si)) {
501
                        foreach ($xmlStrings->si as $val) {
502
                            if (isset($val->t)) {
503
                                $sharedStrings[] = \PhpOffice\PhpSpreadsheet\Shared\StringHelper::controlCharacterOOXML2PHP((string) $val->t);
504
                            } elseif (isset($val->r)) {
505
                                $sharedStrings[] = $this->parseRichText($val);
506
                            }
507
                        }
508
                    }
509
510
                    $worksheets = [];
511
                    $macros = $customUI = null;
0 ignored issues
show
Unused Code introduced by
$customUI is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
512
                    foreach ($relsWorkbook->Relationship as $ele) {
513
                        switch ($ele['Type']) {
514
                            case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet':
515
                                $worksheets[(string) $ele['Id']] = $ele['Target'];
516
                                break;
517
                            // a vbaProject ? (: some macros)
518
                            case 'http://schemas.microsoft.com/office/2006/relationships/vbaProject':
519
                                $macros = $ele['Target'];
520
                                break;
521
                        }
522
                    }
523
524
                    if (!is_null($macros)) {
525
                        $macrosCode = $this->getFromZipArchive($zip, 'xl/vbaProject.bin'); //vbaProject.bin always in 'xl' dir and always named vbaProject.bin
526
                        if ($macrosCode !== false) {
527
                            $excel->setMacrosCode($macrosCode);
528
                            $excel->setHasMacros(true);
529
                            //short-circuit : not reading vbaProject.bin.rel to get Signature =>allways vbaProjectSignature.bin in 'xl' dir
530
                            $Certificate = $this->getFromZipArchive($zip, 'xl/vbaProjectSignature.bin');
531
                            if ($Certificate !== false) {
532
                                $excel->setMacrosCertificate($Certificate);
533
                            }
534
                        }
535
                    }
536
                    $styles = [];
537
                    $cellStyles = [];
538
                    $xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles']"));
539
                    $xmlStyles = simplexml_load_string(
540
                        //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
541
                        $this->securityScan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")),
542
                        'SimpleXMLElement',
543
                        \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
544
                    );
545
                    $numFmts = null;
546
                    if ($xmlStyles && $xmlStyles->numFmts[0]) {
547
                        $numFmts = $xmlStyles->numFmts[0];
548
                    }
549
                    if (isset($numFmts) && ($numFmts !== null)) {
550
                        $numFmts->registerXPathNamespace('sml', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
551
                    }
552
                    if (!$this->readDataOnly && $xmlStyles) {
553
                        foreach ($xmlStyles->cellXfs->xf as $xf) {
554
                            $numFmt = \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_GENERAL;
555
556
                            if ($xf['numFmtId']) {
557
                                if (isset($numFmts)) {
558
                                    $tmpNumFmt = self::getArrayItem($numFmts->xpath("sml:numFmt[@numFmtId=$xf[numFmtId]]"));
559
560
                                    if (isset($tmpNumFmt['formatCode'])) {
561
                                        $numFmt = (string) $tmpNumFmt['formatCode'];
562
                                    }
563
                                }
564
565
                                // We shouldn't override any of the built-in MS Excel values (values below id 164)
566
                                //  But there's a lot of naughty homebrew xlsx writers that do use "reserved" id values that aren't actually used
567
                                //  So we make allowance for them rather than lose formatting masks
568
                                if ((int) $xf['numFmtId'] < 164 &&
569
                                    \PhpOffice\PhpSpreadsheet\Style\NumberFormat::builtInFormatCode((int) $xf['numFmtId']) !== '') {
570
                                    $numFmt = \PhpOffice\PhpSpreadsheet\Style\NumberFormat::builtInFormatCode((int) $xf['numFmtId']);
571
                                }
572
                            }
573
                            $quotePrefix = false;
574
                            if (isset($xf['quotePrefix'])) {
575
                                $quotePrefix = (boolean) $xf['quotePrefix'];
576
                            }
577
578
                            $style = (object) [
579
                                'numFmt' => $numFmt,
580
                                'font' => $xmlStyles->fonts->font[intval($xf['fontId'])],
581
                                'fill' => $xmlStyles->fills->fill[intval($xf['fillId'])],
582
                                'border' => $xmlStyles->borders->border[intval($xf['borderId'])],
583
                                'alignment' => $xf->alignment,
584
                                'protection' => $xf->protection,
585
                                'quotePrefix' => $quotePrefix,
586
                            ];
587
                            $styles[] = $style;
588
589
                            // add style to cellXf collection
590
                            $objStyle = new \PhpOffice\PhpSpreadsheet\Style();
591
                            self::readStyle($objStyle, $style);
592
                            $excel->addCellXf($objStyle);
593
                        }
594
595
                        foreach ($xmlStyles->cellStyleXfs->xf as $xf) {
596
                            $numFmt = \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_GENERAL;
597
                            if ($numFmts && $xf['numFmtId']) {
598
                                $tmpNumFmt = self::getArrayItem($numFmts->xpath("sml:numFmt[@numFmtId=$xf[numFmtId]]"));
599
                                if (isset($tmpNumFmt['formatCode'])) {
600
                                    $numFmt = (string) $tmpNumFmt['formatCode'];
601
                                } elseif ((int) $xf['numFmtId'] < 165) {
602
                                    $numFmt = \PhpOffice\PhpSpreadsheet\Style\NumberFormat::builtInFormatCode((int) $xf['numFmtId']);
603
                                }
604
                            }
605
606
                            $cellStyle = (object) [
607
                                'numFmt' => $numFmt,
608
                                'font' => $xmlStyles->fonts->font[intval($xf['fontId'])],
609
                                'fill' => $xmlStyles->fills->fill[intval($xf['fillId'])],
610
                                'border' => $xmlStyles->borders->border[intval($xf['borderId'])],
611
                                'alignment' => $xf->alignment,
612
                                'protection' => $xf->protection,
613
                                'quotePrefix' => $quotePrefix,
0 ignored issues
show
Bug introduced by
The variable $quotePrefix does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
614
                            ];
615
                            $cellStyles[] = $cellStyle;
616
617
                            // add style to cellStyleXf collection
618
                            $objStyle = new \PhpOffice\PhpSpreadsheet\Style();
619
                            self::readStyle($objStyle, $cellStyle);
620
                            $excel->addCellStyleXf($objStyle);
621
                        }
622
                    }
623
624
                    $dxfs = [];
625
                    if (!$this->readDataOnly && $xmlStyles) {
626
                        //    Conditional Styles
627
                        if ($xmlStyles->dxfs) {
628
                            foreach ($xmlStyles->dxfs->dxf as $dxf) {
629
                                $style = new \PhpOffice\PhpSpreadsheet\Style(false, true);
630
                                self::readStyle($style, $dxf);
631
                                $dxfs[] = $style;
632
                            }
633
                        }
634
                        //    Cell Styles
635
                        if ($xmlStyles->cellStyles) {
636
                            foreach ($xmlStyles->cellStyles->cellStyle as $cellStyle) {
637
                                if (intval($cellStyle['builtinId']) == 0) {
638
                                    if (isset($cellStyles[intval($cellStyle['xfId'])])) {
639
                                        // Set default style
640
                                        $style = new \PhpOffice\PhpSpreadsheet\Style();
641
                                        self::readStyle($style, $cellStyles[intval($cellStyle['xfId'])]);
642
643
                                        // normal style, currently not using it for anything
644
                                    }
645
                                }
646
                            }
647
                        }
648
                    }
649
650
                    $xmlWorkbook = simplexml_load_string(
651
                        //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
652
                        $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")),
653
                        'SimpleXMLElement',
654
                        \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
655
                    );
656
657
                    // Set base date
658
                    if ($xmlWorkbook->workbookPr) {
659
                        \PhpOffice\PhpSpreadsheet\Shared\Date::setExcelCalendar(\PhpOffice\PhpSpreadsheet\Shared\Date::CALENDAR_WINDOWS_1900);
660
                        if (isset($xmlWorkbook->workbookPr['date1904'])) {
661
                            if (self::boolean((string) $xmlWorkbook->workbookPr['date1904'])) {
662
                                \PhpOffice\PhpSpreadsheet\Shared\Date::setExcelCalendar(\PhpOffice\PhpSpreadsheet\Shared\Date::CALENDAR_MAC_1904);
663
                            }
664
                        }
665
                    }
666
667
                    $sheetId = 0; // keep track of new sheet id in final workbook
668
                    $oldSheetId = -1; // keep track of old sheet id in final workbook
669
                    $countSkippedSheets = 0; // keep track of number of skipped sheets
670
                    $mapSheetId = []; // mapping of sheet ids from old to new
671
672
                    $charts = $chartDetails = [];
673
674
                    if ($xmlWorkbook->sheets) {
675
                        foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
676
                            ++$oldSheetId;
677
678
                            // Check if sheet should be skipped
679
                            if (isset($this->loadSheetsOnly) && !in_array((string) $eleSheet['name'], $this->loadSheetsOnly)) {
680
                                ++$countSkippedSheets;
681
                                $mapSheetId[$oldSheetId] = null;
682
                                continue;
683
                            }
684
685
                            // Map old sheet id in original workbook to new sheet id.
686
                            // They will differ if loadSheetsOnly() is being used
687
                            $mapSheetId[$oldSheetId] = $oldSheetId - $countSkippedSheets;
688
689
                            // Load sheet
690
                            $docSheet = $excel->createSheet();
691
                            //    Use false for $updateFormulaCellReferences to prevent adjustment of worksheet
692
                            //        references in formula cells... during the load, all formulae should be correct,
693
                            //        and we're simply bringing the worksheet name in line with the formula, not the
694
                            //        reverse
695
                            $docSheet->setTitle((string) $eleSheet['name'], false);
696
                            $fileWorksheet = $worksheets[(string) self::getArrayItem($eleSheet->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id')];
697
                            $xmlSheet = simplexml_load_string(
698
                                //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
699
                                $this->securityScan($this->getFromZipArchive($zip, "$dir/$fileWorksheet")),
700
                                'SimpleXMLElement',
701
                                \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
702
                            );
703
704
                            $sharedFormulas = [];
705
706
                            if (isset($eleSheet['state']) && (string) $eleSheet['state'] != '') {
707
                                $docSheet->setSheetState((string) $eleSheet['state']);
708
                            }
709
710
                            if (isset($xmlSheet->sheetViews) && isset($xmlSheet->sheetViews->sheetView)) {
711 View Code Duplication
                                if (isset($xmlSheet->sheetViews->sheetView['zoomScale'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
712
                                    $docSheet->getSheetView()->setZoomScale(intval($xmlSheet->sheetViews->sheetView['zoomScale']));
713
                                }
714 View Code Duplication
                                if (isset($xmlSheet->sheetViews->sheetView['zoomScaleNormal'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
715
                                    $docSheet->getSheetView()->setZoomScaleNormal(intval($xmlSheet->sheetViews->sheetView['zoomScaleNormal']));
716
                                }
717
                                if (isset($xmlSheet->sheetViews->sheetView['view'])) {
718
                                    $docSheet->getSheetView()->setView((string) $xmlSheet->sheetViews->sheetView['view']);
719
                                }
720 View Code Duplication
                                if (isset($xmlSheet->sheetViews->sheetView['showGridLines'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
721
                                    $docSheet->setShowGridLines(self::boolean((string) $xmlSheet->sheetViews->sheetView['showGridLines']));
722
                                }
723 View Code Duplication
                                if (isset($xmlSheet->sheetViews->sheetView['showRowColHeaders'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
724
                                    $docSheet->setShowRowColHeaders(self::boolean((string) $xmlSheet->sheetViews->sheetView['showRowColHeaders']));
725
                                }
726 View Code Duplication
                                if (isset($xmlSheet->sheetViews->sheetView['rightToLeft'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
727
                                    $docSheet->setRightToLeft(self::boolean((string) $xmlSheet->sheetViews->sheetView['rightToLeft']));
728
                                }
729
                                if (isset($xmlSheet->sheetViews->sheetView->pane)) {
730
                                    if (isset($xmlSheet->sheetViews->sheetView->pane['topLeftCell'])) {
731
                                        $docSheet->freezePane((string) $xmlSheet->sheetViews->sheetView->pane['topLeftCell']);
732
                                    } else {
733
                                        $xSplit = 0;
734
                                        $ySplit = 0;
735
736 View Code Duplication
                                        if (isset($xmlSheet->sheetViews->sheetView->pane['xSplit'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
737
                                            $xSplit = 1 + intval($xmlSheet->sheetViews->sheetView->pane['xSplit']);
738
                                        }
739
740 View Code Duplication
                                        if (isset($xmlSheet->sheetViews->sheetView->pane['ySplit'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
741
                                            $ySplit = 1 + intval($xmlSheet->sheetViews->sheetView->pane['ySplit']);
742
                                        }
743
744
                                        $docSheet->freezePaneByColumnAndRow($xSplit, $ySplit);
745
                                    }
746
                                }
747
748
                                if (isset($xmlSheet->sheetViews->sheetView->selection)) {
749
                                    if (isset($xmlSheet->sheetViews->sheetView->selection['sqref'])) {
750
                                        $sqref = (string) $xmlSheet->sheetViews->sheetView->selection['sqref'];
751
                                        $sqref = explode(' ', $sqref);
752
                                        $sqref = $sqref[0];
753
                                        $docSheet->setSelectedCells($sqref);
754
                                    }
755
                                }
756
                            }
757
758
                            if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr->tabColor)) {
759
                                if (isset($xmlSheet->sheetPr->tabColor['rgb'])) {
760
                                    $docSheet->getTabColor()->setARGB((string) $xmlSheet->sheetPr->tabColor['rgb']);
761
                                }
762
                            }
763
                            if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr['codeName'])) {
764
                                $docSheet->setCodeName((string) $xmlSheet->sheetPr['codeName']);
765
                            }
766
                            if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr->outlinePr)) {
767 View Code Duplication
                                if (isset($xmlSheet->sheetPr->outlinePr['summaryRight']) &&
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
768
                                    !self::boolean((string) $xmlSheet->sheetPr->outlinePr['summaryRight'])) {
769
                                    $docSheet->setShowSummaryRight(false);
770
                                } else {
771
                                    $docSheet->setShowSummaryRight(true);
772
                                }
773
774 View Code Duplication
                                if (isset($xmlSheet->sheetPr->outlinePr['summaryBelow']) &&
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
775
                                    !self::boolean((string) $xmlSheet->sheetPr->outlinePr['summaryBelow'])) {
776
                                    $docSheet->setShowSummaryBelow(false);
777
                                } else {
778
                                    $docSheet->setShowSummaryBelow(true);
779
                                }
780
                            }
781
782
                            if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr->pageSetUpPr)) {
783
                                if (isset($xmlSheet->sheetPr->pageSetUpPr['fitToPage']) &&
784
                                    !self::boolean((string) $xmlSheet->sheetPr->pageSetUpPr['fitToPage'])) {
785
                                    $docSheet->getPageSetup()->setFitToPage(false);
786
                                } else {
787
                                    $docSheet->getPageSetup()->setFitToPage(true);
788
                                }
789
                            }
790
791
                            if (isset($xmlSheet->sheetFormatPr)) {
792
                                if (isset($xmlSheet->sheetFormatPr['customHeight']) &&
793
                                    self::boolean((string) $xmlSheet->sheetFormatPr['customHeight']) &&
794
                                    isset($xmlSheet->sheetFormatPr['defaultRowHeight'])) {
795
                                    $docSheet->getDefaultRowDimension()->setRowHeight((float) $xmlSheet->sheetFormatPr['defaultRowHeight']);
796
                                }
797
                                if (isset($xmlSheet->sheetFormatPr['defaultColWidth'])) {
798
                                    $docSheet->getDefaultColumnDimension()->setWidth((float) $xmlSheet->sheetFormatPr['defaultColWidth']);
799
                                }
800
                                if (isset($xmlSheet->sheetFormatPr['zeroHeight']) &&
801
                                    ((string) $xmlSheet->sheetFormatPr['zeroHeight'] == '1')) {
802
                                    $docSheet->getDefaultRowDimension()->setZeroHeight(true);
803
                                }
804
                            }
805
806
                            if (isset($xmlSheet->cols) && !$this->readDataOnly) {
807
                                foreach ($xmlSheet->cols->col as $col) {
808
                                    for ($i = intval($col['min']) - 1; $i < intval($col['max']); ++$i) {
809
                                        if ($col['style'] && !$this->readDataOnly) {
810
                                            $docSheet->getColumnDimension(\PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex($i))->setXfIndex(intval($col['style']));
811
                                        }
812
                                        if (self::boolean($col['hidden'])) {
813
                                            $docSheet->getColumnDimension(\PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex($i))->setVisible(false);
814
                                        }
815
                                        if (self::boolean($col['collapsed'])) {
816
                                            $docSheet->getColumnDimension(\PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex($i))->setCollapsed(true);
817
                                        }
818
                                        if ($col['outlineLevel'] > 0) {
819
                                            $docSheet->getColumnDimension(\PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex($i))->setOutlineLevel(intval($col['outlineLevel']));
820
                                        }
821
                                        $docSheet->getColumnDimension(\PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex($i))->setWidth(floatval($col['width']));
822
823
                                        if (intval($col['max']) == 16384) {
824
                                            break;
825
                                        }
826
                                    }
827
                                }
828
                            }
829
830
                            if (isset($xmlSheet->printOptions) && !$this->readDataOnly) {
831
                                if (self::boolean((string) $xmlSheet->printOptions['gridLinesSet'])) {
832
                                    $docSheet->setShowGridlines(true);
833
                                }
834
                                if (self::boolean((string) $xmlSheet->printOptions['gridLines'])) {
835
                                    $docSheet->setPrintGridlines(true);
836
                                }
837
                                if (self::boolean((string) $xmlSheet->printOptions['horizontalCentered'])) {
838
                                    $docSheet->getPageSetup()->setHorizontalCentered(true);
839
                                }
840
                                if (self::boolean((string) $xmlSheet->printOptions['verticalCentered'])) {
841
                                    $docSheet->getPageSetup()->setVerticalCentered(true);
842
                                }
843
                            }
844
845
                            if ($xmlSheet && $xmlSheet->sheetData && $xmlSheet->sheetData->row) {
846
                                foreach ($xmlSheet->sheetData->row as $row) {
847
                                    if ($row['ht'] && !$this->readDataOnly) {
848
                                        $docSheet->getRowDimension(intval($row['r']))->setRowHeight(floatval($row['ht']));
849
                                    }
850
                                    if (self::boolean($row['hidden']) && !$this->readDataOnly) {
851
                                        $docSheet->getRowDimension(intval($row['r']))->setVisible(false);
852
                                    }
853
                                    if (self::boolean($row['collapsed'])) {
854
                                        $docSheet->getRowDimension(intval($row['r']))->setCollapsed(true);
855
                                    }
856
                                    if ($row['outlineLevel'] > 0) {
857
                                        $docSheet->getRowDimension(intval($row['r']))->setOutlineLevel(intval($row['outlineLevel']));
858
                                    }
859 View Code Duplication
                                    if ($row['s'] && !$this->readDataOnly) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
860
                                        $docSheet->getRowDimension(intval($row['r']))->setXfIndex(intval($row['s']));
861
                                    }
862
863
                                    foreach ($row->c as $c) {
864
                                        $r = (string) $c['r'];
865
                                        $cellDataType = (string) $c['t'];
866
                                        $value = null;
867
                                        $calculatedValue = null;
868
869
                                        // Read cell?
870
                                        if ($this->getReadFilter() !== null) {
871
                                            $coordinates = \PhpOffice\PhpSpreadsheet\Cell::coordinateFromString($r);
872
873
                                            if (!$this->getReadFilter()->readCell($coordinates[0], $coordinates[1], $docSheet->getTitle())) {
874
                                                continue;
875
                                            }
876
                                        }
877
878
                                        // Read cell!
879
                                        switch ($cellDataType) {
880
                                            case 's':
881
                                                if ((string) $c->v != '') {
882
                                                    $value = $sharedStrings[intval($c->v)];
883
884
                                                    if ($value instanceof \PhpOffice\PhpSpreadsheet\RichText) {
885
                                                        $value = clone $value;
886
                                                    }
887
                                                } else {
888
                                                    $value = '';
889
                                                }
890
                                                break;
891
                                            case 'b':
892
                                                if (!isset($c->f)) {
893
                                                    $value = self::castToBoolean($c);
894
                                                } else {
895
                                                    // Formula
896
                                                    $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToBoolean');
897
                                                    if (isset($c->f['t'])) {
898
                                                        $att = [];
0 ignored issues
show
Unused Code introduced by
$att is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
899
                                                        $att = $c->f;
900
                                                        $docSheet->getCell($r)->setFormulaAttributes($att);
901
                                                    }
902
                                                }
903
                                                break;
904 View Code Duplication
                                            case 'inlineStr':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
905
                                                if (isset($c->f)) {
906
                                                    $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToError');
907
                                                } else {
908
                                                    $value = $this->parseRichText($c->is);
909
                                                }
910
                                                break;
911 View Code Duplication
                                            case 'e':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
912
                                                if (!isset($c->f)) {
913
                                                    $value = self::castToError($c);
914
                                                } else {
915
                                                    // Formula
916
                                                    $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToError');
917
                                                }
918
                                                break;
919
                                            default:
920
                                                if (!isset($c->f)) {
921
                                                    $value = self::castToString($c);
922
                                                } else {
923
                                                    // Formula
924
                                                    $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToString');
925
                                                }
926
                                                break;
927
                                        }
928
929
                                        // Check for numeric values
930
                                        if (is_numeric($value) && $cellDataType != 's') {
931
                                            if ($value == (int) $value) {
932
                                                $value = (int) $value;
933
                                            } elseif ($value == (float) $value) {
934
                                                $value = (float) $value;
935
                                            } elseif ($value == (double) $value) {
936
                                                $value = (double) $value;
937
                                            }
938
                                        }
939
940
                                        // Rich text?
941
                                        if ($value instanceof \PhpOffice\PhpSpreadsheet\RichText && $this->readDataOnly) {
942
                                            $value = $value->getPlainText();
943
                                        }
944
945
                                        $cell = $docSheet->getCell($r);
946
                                        // Assign value
947
                                        if ($cellDataType != '') {
948
                                            $cell->setValueExplicit($value, $cellDataType);
949
                                        } else {
950
                                            $cell->setValue($value);
951
                                        }
952
                                        if ($calculatedValue !== null) {
953
                                            $cell->setCalculatedValue($calculatedValue);
954
                                        }
955
956
                                        // Style information?
957 View Code Duplication
                                        if ($c['s'] && !$this->readDataOnly) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
958
                                            // no style index means 0, it seems
959
                                            $cell->setXfIndex(isset($styles[intval($c['s'])]) ?
960
                                                intval($c['s']) : 0);
961
                                        }
962
                                    }
963
                                }
964
                            }
965
966
                            $conditionals = [];
967
                            if (!$this->readDataOnly && $xmlSheet && $xmlSheet->conditionalFormatting) {
968
                                foreach ($xmlSheet->conditionalFormatting as $conditional) {
969
                                    foreach ($conditional->cfRule as $cfRule) {
970
                                        if (((string) $cfRule['type'] == \PhpOffice\PhpSpreadsheet\Style\Conditional::CONDITION_NONE || (string) $cfRule['type'] == \PhpOffice\PhpSpreadsheet\Style\Conditional::CONDITION_CELLIS || (string) $cfRule['type'] == \PhpOffice\PhpSpreadsheet\Style\Conditional::CONDITION_CONTAINSTEXT || (string) $cfRule['type'] == \PhpOffice\PhpSpreadsheet\Style\Conditional::CONDITION_EXPRESSION) && isset($dxfs[intval($cfRule['dxfId'])])) {
971
                                            $conditionals[(string) $conditional['sqref']][intval($cfRule['priority'])] = $cfRule;
972
                                        }
973
                                    }
974
                                }
975
976
                                foreach ($conditionals as $ref => $cfRules) {
977
                                    ksort($cfRules);
978
                                    $conditionalStyles = [];
979
                                    foreach ($cfRules as $cfRule) {
980
                                        $objConditional = new \PhpOffice\PhpSpreadsheet\Style\Conditional();
981
                                        $objConditional->setConditionType((string) $cfRule['type']);
982
                                        $objConditional->setOperatorType((string) $cfRule['operator']);
983
984
                                        if ((string) $cfRule['text'] != '') {
985
                                            $objConditional->setText((string) $cfRule['text']);
986
                                        }
987
988
                                        if (count($cfRule->formula) > 1) {
989
                                            foreach ($cfRule->formula as $formula) {
990
                                                $objConditional->addCondition((string) $formula);
991
                                            }
992
                                        } else {
993
                                            $objConditional->addCondition((string) $cfRule->formula);
994
                                        }
995
                                        $objConditional->setStyle(clone $dxfs[intval($cfRule['dxfId'])]);
996
                                        $conditionalStyles[] = $objConditional;
997
                                    }
998
999
                                    // Extract all cell references in $ref
1000
                                    $cellBlocks = explode(' ', str_replace('$', '', strtoupper($ref)));
1001
                                    foreach ($cellBlocks as $cellBlock) {
1002
                                        $docSheet->getStyle($cellBlock)->setConditionalStyles($conditionalStyles);
1003
                                    }
1004
                                }
1005
                            }
1006
1007
                            $aKeys = ['sheet', 'objects', 'scenarios', 'formatCells', 'formatColumns', 'formatRows', 'insertColumns', 'insertRows', 'insertHyperlinks', 'deleteColumns', 'deleteRows', 'selectLockedCells', 'sort', 'autoFilter', 'pivotTables', 'selectUnlockedCells'];
1008
                            if (!$this->readDataOnly && $xmlSheet && $xmlSheet->sheetProtection) {
1009
                                foreach ($aKeys as $key) {
1010
                                    $method = 'set' . ucfirst($key);
1011
                                    $docSheet->getProtection()->$method(self::boolean((string) $xmlSheet->sheetProtection[$key]));
1012
                                }
1013
                            }
1014
1015
                            if (!$this->readDataOnly && $xmlSheet && $xmlSheet->sheetProtection) {
1016
                                $docSheet->getProtection()->setPassword((string) $xmlSheet->sheetProtection['password'], true);
1017
                                if ($xmlSheet->protectedRanges->protectedRange) {
1018
                                    foreach ($xmlSheet->protectedRanges->protectedRange as $protectedRange) {
1019
                                        $docSheet->protectCells((string) $protectedRange['sqref'], (string) $protectedRange['password'], true);
1020
                                    }
1021
                                }
1022
                            }
1023
1024
                            if ($xmlSheet && $xmlSheet->autoFilter && !$this->readDataOnly) {
1025
                                $autoFilterRange = (string) $xmlSheet->autoFilter['ref'];
1026
                                if (strpos($autoFilterRange, ':') !== false) {
1027
                                    $autoFilter = $docSheet->getAutoFilter();
1028
                                    $autoFilter->setRange($autoFilterRange);
1029
1030
                                    foreach ($xmlSheet->autoFilter->filterColumn as $filterColumn) {
1031
                                        $column = $autoFilter->getColumnByOffset((integer) $filterColumn['colId']);
1032
                                        //    Check for standard filters
1033
                                        if ($filterColumn->filters) {
1034
                                            $column->setFilterType(\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column::AUTOFILTER_FILTERTYPE_FILTER);
1035
                                            $filters = $filterColumn->filters;
1036
                                            if ((isset($filters['blank'])) && ($filters['blank'] == 1)) {
1037
                                                //    Operator is undefined, but always treated as EQUAL
1038
                                                $column->createRule()->setRule(null, '')->setRuleType(\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_FILTER);
1039
                                            }
1040
                                            //    Standard filters are always an OR join, so no join rule needs to be set
1041
                                            //    Entries can be either filter elements
1042 View Code Duplication
                                            foreach ($filters->filter as $filterRule) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1043
                                                //    Operator is undefined, but always treated as EQUAL
1044
                                                $column->createRule()->setRule(null, (string) $filterRule['val'])->setRuleType(\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_FILTER);
1045
                                            }
1046
                                            //    Or Date Group elements
1047
                                            foreach ($filters->dateGroupItem as $dateGroupItem) {
1048
                                                $column->createRule()->setRule(
1049
                                                    //    Operator is undefined, but always treated as EQUAL
1050
                                                    null,
1051
                                                    [
1052
                                                        'year' => (string) $dateGroupItem['year'],
1053
                                                        'month' => (string) $dateGroupItem['month'],
1054
                                                        'day' => (string) $dateGroupItem['day'],
1055
                                                        'hour' => (string) $dateGroupItem['hour'],
1056
                                                        'minute' => (string) $dateGroupItem['minute'],
1057
                                                        'second' => (string) $dateGroupItem['second'],
1058
                                                    ],
1059
                                                    (string) $dateGroupItem['dateTimeGrouping']
1060
                                                )
1061
                                                ->setRuleType(\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP);
1062
                                            }
1063
                                        }
1064
                                        //    Check for custom filters
1065
                                        if ($filterColumn->customFilters) {
1066
                                            $column->setFilterType(\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column::AUTOFILTER_FILTERTYPE_CUSTOMFILTER);
1067
                                            $customFilters = $filterColumn->customFilters;
1068
                                            //    Custom filters can an AND or an OR join;
1069
                                            //        and there should only ever be one or two entries
1070
                                            if ((isset($customFilters['and'])) && ($customFilters['and'] == 1)) {
1071
                                                $column->setJoin(\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column::AUTOFILTER_COLUMN_JOIN_AND);
1072
                                            }
1073 View Code Duplication
                                            foreach ($customFilters->customFilter as $filterRule) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1074
                                                $column->createRule()->setRule(
1075
                                                    (string) $filterRule['operator'],
1076
                                                    (string) $filterRule['val']
1077
                                                )
1078
                                                ->setRuleType(\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER);
1079
                                            }
1080
                                        }
1081
                                        //    Check for dynamic filters
1082
                                        if ($filterColumn->dynamicFilter) {
1083
                                            $column->setFilterType(\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER);
1084
                                            //    We should only ever have one dynamic filter
1085
                                            foreach ($filterColumn->dynamicFilter as $filterRule) {
1086
                                                $column->createRule()->setRule(
1087
                                                    //    Operator is undefined, but always treated as EQUAL
1088
                                                    null,
1089
                                                    (string) $filterRule['val'],
1090
                                                    (string) $filterRule['type']
1091
                                                )
1092
                                                ->setRuleType(\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER);
1093
                                                if (isset($filterRule['val'])) {
1094
                                                    $column->setAttribute('val', (string) $filterRule['val']);
1095
                                                }
1096
                                                if (isset($filterRule['maxVal'])) {
1097
                                                    $column->setAttribute('maxVal', (string) $filterRule['maxVal']);
1098
                                                }
1099
                                            }
1100
                                        }
1101
                                        //    Check for dynamic filters
1102
                                        if ($filterColumn->top10) {
1103
                                            $column->setFilterType(\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column::AUTOFILTER_FILTERTYPE_TOPTENFILTER);
1104
                                            //    We should only ever have one top10 filter
1105
                                            foreach ($filterColumn->top10 as $filterRule) {
1106
                                                $column->createRule()->setRule(
1107
                                                    (((isset($filterRule['percent'])) && ($filterRule['percent'] == 1))
1108
                                                        ? \PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT
1109
                                                        : \PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE
1110
                                                    ),
1111
                                                    (string) $filterRule['val'],
1112
                                                    (((isset($filterRule['top'])) && ($filterRule['top'] == 1))
1113
                                                        ? \PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP
1114
                                                        : \PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM
1115
                                                    )
1116
                                                )
1117
                                                ->setRuleType(\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_TOPTENFILTER);
1118
                                            }
1119
                                        }
1120
                                    }
1121
                                }
1122
                            }
1123
1124
                            if ($xmlSheet && $xmlSheet->mergeCells && $xmlSheet->mergeCells->mergeCell && !$this->readDataOnly) {
1125
                                foreach ($xmlSheet->mergeCells->mergeCell as $mergeCell) {
1126
                                    $mergeRef = (string) $mergeCell['ref'];
1127
                                    if (strpos($mergeRef, ':') !== false) {
1128
                                        $docSheet->mergeCells((string) $mergeCell['ref']);
1129
                                    }
1130
                                }
1131
                            }
1132
1133
                            if ($xmlSheet && $xmlSheet->pageMargins && !$this->readDataOnly) {
1134
                                $docPageMargins = $docSheet->getPageMargins();
1135
                                $docPageMargins->setLeft(floatval($xmlSheet->pageMargins['left']));
1136
                                $docPageMargins->setRight(floatval($xmlSheet->pageMargins['right']));
1137
                                $docPageMargins->setTop(floatval($xmlSheet->pageMargins['top']));
1138
                                $docPageMargins->setBottom(floatval($xmlSheet->pageMargins['bottom']));
1139
                                $docPageMargins->setHeader(floatval($xmlSheet->pageMargins['header']));
1140
                                $docPageMargins->setFooter(floatval($xmlSheet->pageMargins['footer']));
1141
                            }
1142
1143
                            if ($xmlSheet && $xmlSheet->pageSetup && !$this->readDataOnly) {
1144
                                $docPageSetup = $docSheet->getPageSetup();
1145
1146
                                if (isset($xmlSheet->pageSetup['orientation'])) {
1147
                                    $docPageSetup->setOrientation((string) $xmlSheet->pageSetup['orientation']);
1148
                                }
1149
                                if (isset($xmlSheet->pageSetup['paperSize'])) {
1150
                                    $docPageSetup->setPaperSize(intval($xmlSheet->pageSetup['paperSize']));
1151
                                }
1152
                                if (isset($xmlSheet->pageSetup['scale'])) {
1153
                                    $docPageSetup->setScale(intval($xmlSheet->pageSetup['scale']), false);
1154
                                }
1155 View Code Duplication
                                if (isset($xmlSheet->pageSetup['fitToHeight']) && intval($xmlSheet->pageSetup['fitToHeight']) >= 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1156
                                    $docPageSetup->setFitToHeight(intval($xmlSheet->pageSetup['fitToHeight']), false);
1157
                                }
1158 View Code Duplication
                                if (isset($xmlSheet->pageSetup['fitToWidth']) && intval($xmlSheet->pageSetup['fitToWidth']) >= 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1159
                                    $docPageSetup->setFitToWidth(intval($xmlSheet->pageSetup['fitToWidth']), false);
1160
                                }
1161
                                if (isset($xmlSheet->pageSetup['firstPageNumber']) && isset($xmlSheet->pageSetup['useFirstPageNumber']) &&
1162
                                    self::boolean((string) $xmlSheet->pageSetup['useFirstPageNumber'])) {
1163
                                    $docPageSetup->setFirstPageNumber(intval($xmlSheet->pageSetup['firstPageNumber']));
1164
                                }
1165
                            }
1166
1167
                            if ($xmlSheet && $xmlSheet->headerFooter && !$this->readDataOnly) {
1168
                                $docHeaderFooter = $docSheet->getHeaderFooter();
1169
1170 View Code Duplication
                                if (isset($xmlSheet->headerFooter['differentOddEven']) &&
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1171
                                    self::boolean((string) $xmlSheet->headerFooter['differentOddEven'])) {
1172
                                    $docHeaderFooter->setDifferentOddEven(true);
1173
                                } else {
1174
                                    $docHeaderFooter->setDifferentOddEven(false);
1175
                                }
1176 View Code Duplication
                                if (isset($xmlSheet->headerFooter['differentFirst']) &&
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1177
                                    self::boolean((string) $xmlSheet->headerFooter['differentFirst'])) {
1178
                                    $docHeaderFooter->setDifferentFirst(true);
1179
                                } else {
1180
                                    $docHeaderFooter->setDifferentFirst(false);
1181
                                }
1182 View Code Duplication
                                if (isset($xmlSheet->headerFooter['scaleWithDoc']) &&
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1183
                                    !self::boolean((string) $xmlSheet->headerFooter['scaleWithDoc'])) {
1184
                                    $docHeaderFooter->setScaleWithDocument(false);
1185
                                } else {
1186
                                    $docHeaderFooter->setScaleWithDocument(true);
1187
                                }
1188 View Code Duplication
                                if (isset($xmlSheet->headerFooter['alignWithMargins']) &&
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1189
                                    !self::boolean((string) $xmlSheet->headerFooter['alignWithMargins'])) {
1190
                                    $docHeaderFooter->setAlignWithMargins(false);
1191
                                } else {
1192
                                    $docHeaderFooter->setAlignWithMargins(true);
1193
                                }
1194
1195
                                $docHeaderFooter->setOddHeader((string) $xmlSheet->headerFooter->oddHeader);
1196
                                $docHeaderFooter->setOddFooter((string) $xmlSheet->headerFooter->oddFooter);
1197
                                $docHeaderFooter->setEvenHeader((string) $xmlSheet->headerFooter->evenHeader);
1198
                                $docHeaderFooter->setEvenFooter((string) $xmlSheet->headerFooter->evenFooter);
1199
                                $docHeaderFooter->setFirstHeader((string) $xmlSheet->headerFooter->firstHeader);
1200
                                $docHeaderFooter->setFirstFooter((string) $xmlSheet->headerFooter->firstFooter);
1201
                            }
1202
1203
                            if ($xmlSheet && $xmlSheet->rowBreaks && $xmlSheet->rowBreaks->brk && !$this->readDataOnly) {
1204
                                foreach ($xmlSheet->rowBreaks->brk as $brk) {
1205
                                    if ($brk['man']) {
1206
                                        $docSheet->setBreak("A$brk[id]", \PhpOffice\PhpSpreadsheet\Worksheet::BREAK_ROW);
1207
                                    }
1208
                                }
1209
                            }
1210
                            if ($xmlSheet && $xmlSheet->colBreaks && $xmlSheet->colBreaks->brk && !$this->readDataOnly) {
1211
                                foreach ($xmlSheet->colBreaks->brk as $brk) {
1212
                                    if ($brk['man']) {
1213
                                        $docSheet->setBreak(\PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex((string) $brk['id']) . '1', \PhpOffice\PhpSpreadsheet\Worksheet::BREAK_COLUMN);
1214
                                    }
1215
                                }
1216
                            }
1217
1218
                            if ($xmlSheet && $xmlSheet->dataValidations && !$this->readDataOnly) {
1219
                                foreach ($xmlSheet->dataValidations->dataValidation as $dataValidation) {
1220
                                    // Uppercase coordinate
1221
                                    $range = strtoupper($dataValidation['sqref']);
1222
                                    $rangeSet = explode(' ', $range);
1223
                                    foreach ($rangeSet as $range) {
1224
                                        $stRange = $docSheet->shrinkRangeToFit($range);
1225
1226
                                        // Extract all cell references in $range
1227
                                        foreach (\PhpOffice\PhpSpreadsheet\Cell::extractAllCellReferencesInRange($stRange) as $reference) {
1228
                                            // Create validation
1229
                                            $docValidation = $docSheet->getCell($reference)->getDataValidation();
1230
                                            $docValidation->setType((string) $dataValidation['type']);
1231
                                            $docValidation->setErrorStyle((string) $dataValidation['errorStyle']);
1232
                                            $docValidation->setOperator((string) $dataValidation['operator']);
1233
                                            $docValidation->setAllowBlank($dataValidation['allowBlank'] != 0);
1234
                                            $docValidation->setShowDropDown($dataValidation['showDropDown'] == 0);
1235
                                            $docValidation->setShowInputMessage($dataValidation['showInputMessage'] != 0);
1236
                                            $docValidation->setShowErrorMessage($dataValidation['showErrorMessage'] != 0);
1237
                                            $docValidation->setErrorTitle((string) $dataValidation['errorTitle']);
1238
                                            $docValidation->setError((string) $dataValidation['error']);
1239
                                            $docValidation->setPromptTitle((string) $dataValidation['promptTitle']);
1240
                                            $docValidation->setPrompt((string) $dataValidation['prompt']);
1241
                                            $docValidation->setFormula1((string) $dataValidation->formula1);
1242
                                            $docValidation->setFormula2((string) $dataValidation->formula2);
1243
                                        }
1244
                                    }
1245
                                }
1246
                            }
1247
1248
                            // Add hyperlinks
1249
                            $hyperlinks = [];
1250
                            if (!$this->readDataOnly) {
1251
                                // Locate hyperlink relations
1252
                                if ($zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
1253
                                    $relsWorksheet = simplexml_load_string(
1254
                                        //~ http://schemas.openxmlformats.org/package/2006/relationships"
1255
                                        $this->securityScan(
1256
                                            $this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
1257
                                        ),
1258
                                        'SimpleXMLElement',
1259
                                        \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
1260
                                    );
1261
                                    foreach ($relsWorksheet->Relationship as $ele) {
1262
                                        if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink') {
1263
                                            $hyperlinks[(string) $ele['Id']] = (string) $ele['Target'];
1264
                                        }
1265
                                    }
1266
                                }
1267
1268
                                // Loop through hyperlinks
1269
                                if ($xmlSheet && $xmlSheet->hyperlinks) {
1270
                                    foreach ($xmlSheet->hyperlinks->hyperlink as $hyperlink) {
1271
                                        // Link url
1272
                                        $linkRel = $hyperlink->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships');
1273
1274
                                        foreach (\PhpOffice\PhpSpreadsheet\Cell::extractAllCellReferencesInRange($hyperlink['ref']) as $cellReference) {
1275
                                            $cell = $docSheet->getCell($cellReference);
1276
                                            if (isset($linkRel['id'])) {
1277
                                                $hyperlinkUrl = $hyperlinks[(string) $linkRel['id']];
1278
                                                if (isset($hyperlink['location'])) {
1279
                                                    $hyperlinkUrl .= '#' . (string) $hyperlink['location'];
1280
                                                }
1281
                                                $cell->getHyperlink()->setUrl($hyperlinkUrl);
1282
                                            } elseif (isset($hyperlink['location'])) {
1283
                                                $cell->getHyperlink()->setUrl('sheet://' . (string) $hyperlink['location']);
1284
                                            }
1285
1286
                                            // Tooltip
1287
                                            if (isset($hyperlink['tooltip'])) {
1288
                                                $cell->getHyperlink()->setTooltip((string) $hyperlink['tooltip']);
1289
                                            }
1290
                                        }
1291
                                    }
1292
                                }
1293
                            }
1294
1295
                            // Add comments
1296
                            $comments = [];
1297
                            $vmlComments = [];
1298
                            if (!$this->readDataOnly) {
1299
                                // Locate comment relations
1300
                                if ($zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
1301
                                    $relsWorksheet = simplexml_load_string(
1302
                                        //~ http://schemas.openxmlformats.org/package/2006/relationships"
1303
                                        $this->securityScan(
1304
                                            $this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
1305
                                        ),
1306
                                        'SimpleXMLElement',
1307
                                        \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
1308
                                    );
1309
                                    foreach ($relsWorksheet->Relationship as $ele) {
1310
                                        if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments') {
1311
                                            $comments[(string) $ele['Id']] = (string) $ele['Target'];
1312
                                        }
1313
                                        if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing') {
1314
                                            $vmlComments[(string) $ele['Id']] = (string) $ele['Target'];
1315
                                        }
1316
                                    }
1317
                                }
1318
1319
                                // Loop through comments
1320
                                foreach ($comments as $relName => $relPath) {
1321
                                    // Load comments file
1322
                                    $relPath = \PhpOffice\PhpSpreadsheet\Shared\File::realpath(dirname("$dir/$fileWorksheet") . '/' . $relPath);
1323
                                    $commentsFile = simplexml_load_string(
1324
                                        $this->securityScan($this->getFromZipArchive($zip, $relPath)),
1325
                                        'SimpleXMLElement',
1326
                                        \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
1327
                                    );
1328
1329
                                    // Utility variables
1330
                                    $authors = [];
1331
1332
                                    // Loop through authors
1333
                                    foreach ($commentsFile->authors->author as $author) {
1334
                                        $authors[] = (string) $author;
1335
                                    }
1336
1337
                                    // Loop through contents
1338
                                    foreach ($commentsFile->commentList->comment as $comment) {
1339
                                        if (!empty($comment['authorId'])) {
1340
                                            $docSheet->getComment((string) $comment['ref'])->setAuthor($authors[(string) $comment['authorId']]);
1341
                                        }
1342
                                        $docSheet->getComment((string) $comment['ref'])->setText($this->parseRichText($comment->text));
1343
                                    }
1344
                                }
1345
1346
                                // Loop through VML comments
1347
                                foreach ($vmlComments as $relName => $relPath) {
1348
                                    // Load VML comments file
1349
                                    $relPath = \PhpOffice\PhpSpreadsheet\Shared\File::realpath(dirname("$dir/$fileWorksheet") . '/' . $relPath);
1350
                                    $vmlCommentsFile = simplexml_load_string(
1351
                                        $this->securityScan($this->getFromZipArchive($zip, $relPath)),
1352
                                        'SimpleXMLElement',
1353
                                        \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
1354
                                    );
1355
                                    $vmlCommentsFile->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
1356
1357
                                    $shapes = $vmlCommentsFile->xpath('//v:shape');
1358
                                    foreach ($shapes as $shape) {
1359
                                        $shape->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
1360
1361
                                        if (isset($shape['style'])) {
1362
                                            $style = (string) $shape['style'];
1363
                                            $fillColor = strtoupper(substr((string) $shape['fillcolor'], 1));
1364
                                            $column = null;
1365
                                            $row = null;
1366
1367
                                            $clientData = $shape->xpath('.//x:ClientData');
1368
                                            if (is_array($clientData) && !empty($clientData)) {
1369
                                                $clientData = $clientData[0];
1370
1371
                                                if (isset($clientData['ObjectType']) && (string) $clientData['ObjectType'] == 'Note') {
1372
                                                    $temp = $clientData->xpath('.//x:Row');
1373
                                                    if (is_array($temp)) {
1374
                                                        $row = $temp[0];
1375
                                                    }
1376
1377
                                                    $temp = $clientData->xpath('.//x:Column');
1378
                                                    if (is_array($temp)) {
1379
                                                        $column = $temp[0];
1380
                                                    }
1381
                                                }
1382
                                            }
1383
1384
                                            if (($column !== null) && ($row !== null)) {
1385
                                                // Set comment properties
1386
                                                $comment = $docSheet->getCommentByColumnAndRow((string) $column, $row + 1);
1387
                                                $comment->getFillColor()->setRGB($fillColor);
1388
1389
                                                // Parse style
1390
                                                $styleArray = explode(';', str_replace(' ', '', $style));
1391
                                                foreach ($styleArray as $stylePair) {
1392
                                                    $stylePair = explode(':', $stylePair);
1393
1394
                                                    if ($stylePair[0] == 'margin-left') {
1395
                                                        $comment->setMarginLeft($stylePair[1]);
1396
                                                    }
1397
                                                    if ($stylePair[0] == 'margin-top') {
1398
                                                        $comment->setMarginTop($stylePair[1]);
1399
                                                    }
1400
                                                    if ($stylePair[0] == 'width') {
1401
                                                        $comment->setWidth($stylePair[1]);
1402
                                                    }
1403
                                                    if ($stylePair[0] == 'height') {
1404
                                                        $comment->setHeight($stylePair[1]);
1405
                                                    }
1406
                                                    if ($stylePair[0] == 'visibility') {
1407
                                                        $comment->setVisible($stylePair[1] == 'visible');
1408
                                                    }
1409
                                                }
1410
                                            }
1411
                                        }
1412
                                    }
1413
                                }
1414
1415
                                // Header/footer images
1416
                                if ($xmlSheet && $xmlSheet->legacyDrawingHF && !$this->readDataOnly) {
1417
                                    if ($zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
1418
                                        $relsWorksheet = simplexml_load_string(
1419
                                            //~ http://schemas.openxmlformats.org/package/2006/relationships"
1420
                                            $this->securityScan(
1421
                                                $this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
1422
                                            ),
1423
                                            'SimpleXMLElement',
1424
                                            \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
1425
                                        );
1426
                                        $vmlRelationship = '';
1427
1428
                                        foreach ($relsWorksheet->Relationship as $ele) {
1429
                                            if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing') {
1430
                                                $vmlRelationship = self::dirAdd("$dir/$fileWorksheet", $ele['Target']);
1431
                                            }
1432
                                        }
1433
1434
                                        if ($vmlRelationship != '') {
1435
                                            // Fetch linked images
1436
                                            $relsVML = simplexml_load_string(
1437
                                                //~ http://schemas.openxmlformats.org/package/2006/relationships"
1438
                                                $this->securityScan(
1439
                                                    $this->getFromZipArchive($zip, dirname($vmlRelationship) . '/_rels/' . basename($vmlRelationship) . '.rels')
1440
                                                ),
1441
                                                'SimpleXMLElement',
1442
                                                \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
1443
                                            );
1444
                                            $drawings = [];
1445 View Code Duplication
                                            foreach ($relsVML->Relationship as $ele) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1446
                                                if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') {
1447
                                                    $drawings[(string) $ele['Id']] = self::dirAdd($vmlRelationship, $ele['Target']);
1448
                                                }
1449
                                            }
1450
1451
                                            // Fetch VML document
1452
                                            $vmlDrawing = simplexml_load_string(
1453
                                                $this->securityScan($this->getFromZipArchive($zip, $vmlRelationship)),
1454
                                                'SimpleXMLElement',
1455
                                                \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
1456
                                            );
1457
                                            $vmlDrawing->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
1458
1459
                                            $hfImages = [];
1460
1461
                                            $shapes = $vmlDrawing->xpath('//v:shape');
1462
                                            foreach ($shapes as $idx => $shape) {
1463
                                                $shape->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
1464
                                                $imageData = $shape->xpath('//v:imagedata');
1465
                                                $imageData = $imageData[$idx];
1466
1467
                                                $imageData = $imageData->attributes('urn:schemas-microsoft-com:office:office');
1468
                                                $style = self::toCSSArray((string) $shape['style']);
1469
1470
                                                $hfImages[(string) $shape['id']] = new \PhpOffice\PhpSpreadsheet\Worksheet\HeaderFooterDrawing();
1471
                                                if (isset($imageData['title'])) {
1472
                                                    $hfImages[(string) $shape['id']]->setName((string) $imageData['title']);
1473
                                                }
1474
1475
                                                $hfImages[(string) $shape['id']]->setPath('zip://' . \PhpOffice\PhpSpreadsheet\Shared_File::realpath($pFilename) . '#' . $drawings[(string) $imageData['relid']], false);
1476
                                                $hfImages[(string) $shape['id']]->setResizeProportional(false);
1477
                                                $hfImages[(string) $shape['id']]->setWidth($style['width']);
1478
                                                $hfImages[(string) $shape['id']]->setHeight($style['height']);
1479
                                                if (isset($style['margin-left'])) {
1480
                                                    $hfImages[(string) $shape['id']]->setOffsetX($style['margin-left']);
1481
                                                }
1482
                                                $hfImages[(string) $shape['id']]->setOffsetY($style['margin-top']);
1483
                                                $hfImages[(string) $shape['id']]->setResizeProportional(true);
1484
                                            }
1485
1486
                                            $docSheet->getHeaderFooter()->setImages($hfImages);
1487
                                        }
1488
                                    }
1489
                                }
1490
                            }
1491
1492
                            // TODO: Autoshapes from twoCellAnchors!
1493
                            if ($zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
1494
                                $relsWorksheet = simplexml_load_string(
1495
                                    //~ http://schemas.openxmlformats.org/package/2006/relationships"
1496
                                    $this->securityScan(
1497
                                        $this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
1498
                                    ),
1499
                                    'SimpleXMLElement',
1500
                                    \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
1501
                                );
1502
                                $drawings = [];
1503 View Code Duplication
                                foreach ($relsWorksheet->Relationship as $ele) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1504
                                    if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing') {
1505
                                        $drawings[(string) $ele['Id']] = self::dirAdd("$dir/$fileWorksheet", $ele['Target']);
1506
                                    }
1507
                                }
1508
                                if ($xmlSheet->drawing && !$this->readDataOnly) {
1509
                                    foreach ($xmlSheet->drawing as $drawing) {
1510
                                        $fileDrawing = $drawings[(string) self::getArrayItem($drawing->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id')];
1511
                                        $relsDrawing = simplexml_load_string(
1512
                                            //~ http://schemas.openxmlformats.org/package/2006/relationships"
1513
                                            $this->securityScan(
1514
                                                $this->getFromZipArchive($zip, dirname($fileDrawing) . '/_rels/' . basename($fileDrawing) . '.rels')
1515
                                            ),
1516
                                            'SimpleXMLElement',
1517
                                            \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
1518
                                        );
1519
                                        $images = [];
1520
1521
                                        if ($relsDrawing && $relsDrawing->Relationship) {
1522
                                            foreach ($relsDrawing->Relationship as $ele) {
1523
                                                if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') {
1524
                                                    $images[(string) $ele['Id']] = self::dirAdd($fileDrawing, $ele['Target']);
1525
                                                } elseif ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart') {
1526
                                                    if ($this->includeCharts) {
1527
                                                        $charts[self::dirAdd($fileDrawing, $ele['Target'])] = [
1528
                                                            'id' => (string) $ele['Id'],
1529
                                                            'sheet' => $docSheet->getTitle(),
1530
                                                        ];
1531
                                                    }
1532
                                                }
1533
                                            }
1534
                                        }
1535
                                        $xmlDrawing = simplexml_load_string(
1536
                                            $this->securityScan($this->getFromZipArchive($zip, $fileDrawing)),
1537
                                            'SimpleXMLElement',
1538
                                            \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
1539
                                        )->children('http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing');
1540
1541
                                        if ($xmlDrawing->oneCellAnchor) {
1542
                                            foreach ($xmlDrawing->oneCellAnchor as $oneCellAnchor) {
1543
                                                if ($oneCellAnchor->pic->blipFill) {
1544
                                                    $blip = $oneCellAnchor->pic->blipFill->children('http://schemas.openxmlformats.org/drawingml/2006/main')->blip;
1545
                                                    $xfrm = $oneCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->xfrm;
1546
                                                    $outerShdw = $oneCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->effectLst->outerShdw;
1547
                                                    $objDrawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing();
1548
                                                    $objDrawing->setName((string) self::getArrayItem($oneCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'name'));
1549
                                                    $objDrawing->setDescription((string) self::getArrayItem($oneCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'descr'));
1550
                                                    $objDrawing->setPath(
1551
                                                        'zip://' . \PhpOffice\PhpSpreadsheet\Shared\File::realpath($pFilename) . '#' .
1552
                                                        $images[(string) self::getArrayItem(
1553
                                                            $blip->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'),
1554
                                                            'embed'
1555
                                                        )],
1556
                                                        false
1557
                                                    );
1558
                                                    $objDrawing->setCoordinates(\PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex((string) $oneCellAnchor->from->col) . ($oneCellAnchor->from->row + 1));
1559
                                                    $objDrawing->setOffsetX(\PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUToPixels($oneCellAnchor->from->colOff));
1560
                                                    $objDrawing->setOffsetY(\PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUToPixels($oneCellAnchor->from->rowOff));
1561
                                                    $objDrawing->setResizeProportional(false);
1562
                                                    $objDrawing->setWidth(\PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), 'cx')));
1563
                                                    $objDrawing->setHeight(\PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), 'cy')));
1564
                                                    if ($xfrm) {
1565
                                                        $objDrawing->setRotation(\PhpOffice\PhpSpreadsheet\Shared\Drawing::angleToDegrees(self::getArrayItem($xfrm->attributes(), 'rot')));
1566
                                                    }
1567 View Code Duplication
                                                    if ($outerShdw) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1568
                                                        $shadow = $objDrawing->getShadow();
1569
                                                        $shadow->setVisible(true);
1570
                                                        $shadow->setBlurRadius(\PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), 'blurRad')));
1571
                                                        $shadow->setDistance(\PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), 'dist')));
1572
                                                        $shadow->setDirection(\PhpOffice\PhpSpreadsheet\Shared\Drawing::angleToDegrees(self::getArrayItem($outerShdw->attributes(), 'dir')));
1573
                                                        $shadow->setAlignment((string) self::getArrayItem($outerShdw->attributes(), 'algn'));
1574
                                                        $shadow->getColor()->setRGB(self::getArrayItem($outerShdw->srgbClr->attributes(), 'val'));
1575
                                                        $shadow->setAlpha(self::getArrayItem($outerShdw->srgbClr->alpha->attributes(), 'val') / 1000);
1576
                                                    }
1577
                                                    $objDrawing->setWorksheet($docSheet);
1578
                                                } else {
1579
                                                    //    ? Can charts be positioned with a oneCellAnchor ?
1580
                                                    $coordinates = \PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex((string) $oneCellAnchor->from->col) . ($oneCellAnchor->from->row + 1);
0 ignored issues
show
Unused Code introduced by
$coordinates is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1581
                                                    $offsetX = \PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUToPixels($oneCellAnchor->from->colOff);
0 ignored issues
show
Unused Code introduced by
$offsetX is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1582
                                                    $offsetY = \PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUToPixels($oneCellAnchor->from->rowOff);
0 ignored issues
show
Unused Code introduced by
$offsetY is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1583
                                                    $width = \PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), 'cx'));
0 ignored issues
show
Unused Code introduced by
$width is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1584
                                                    $height = \PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), 'cy'));
0 ignored issues
show
Unused Code introduced by
$height is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1585
                                                }
1586
                                            }
1587
                                        }
1588
                                        if ($xmlDrawing->twoCellAnchor) {
1589
                                            foreach ($xmlDrawing->twoCellAnchor as $twoCellAnchor) {
1590
                                                if ($twoCellAnchor->pic->blipFill) {
1591
                                                    $blip = $twoCellAnchor->pic->blipFill->children('http://schemas.openxmlformats.org/drawingml/2006/main')->blip;
1592
                                                    $xfrm = $twoCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->xfrm;
1593
                                                    $outerShdw = $twoCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->effectLst->outerShdw;
1594
                                                    $objDrawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing();
1595
                                                    $objDrawing->setName((string) self::getArrayItem($twoCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'name'));
1596
                                                    $objDrawing->setDescription((string) self::getArrayItem($twoCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'descr'));
1597
                                                    $objDrawing->setPath(
1598
                                                        'zip://' . \PhpOffice\PhpSpreadsheet\Shared\File::realpath($pFilename) . '#' .
1599
                                                        $images[(string) self::getArrayItem(
1600
                                                            $blip->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'),
1601
                                                            'embed'
1602
                                                        )],
1603
                                                        false
1604
                                                    );
1605
                                                    $objDrawing->setCoordinates(\PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex((string) $twoCellAnchor->from->col) . ($twoCellAnchor->from->row + 1));
1606
                                                    $objDrawing->setOffsetX(\PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUToPixels($twoCellAnchor->from->colOff));
1607
                                                    $objDrawing->setOffsetY(\PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUToPixels($twoCellAnchor->from->rowOff));
1608
                                                    $objDrawing->setResizeProportional(false);
1609
1610
                                                    if ($xfrm) {
1611
                                                        $objDrawing->setWidth(\PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUToPixels(self::getArrayItem($xfrm->ext->attributes(), 'cx')));
1612
                                                        $objDrawing->setHeight(\PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUToPixels(self::getArrayItem($xfrm->ext->attributes(), 'cy')));
1613
                                                        $objDrawing->setRotation(\PhpOffice\PhpSpreadsheet\Shared\Drawing::angleToDegrees(self::getArrayItem($xfrm->attributes(), 'rot')));
1614
                                                    }
1615 View Code Duplication
                                                    if ($outerShdw) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1616
                                                        $shadow = $objDrawing->getShadow();
1617
                                                        $shadow->setVisible(true);
1618
                                                        $shadow->setBlurRadius(\PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), 'blurRad')));
1619
                                                        $shadow->setDistance(\PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), 'dist')));
1620
                                                        $shadow->setDirection(\PhpOffice\PhpSpreadsheet\Shared\Drawing::angleToDegrees(self::getArrayItem($outerShdw->attributes(), 'dir')));
1621
                                                        $shadow->setAlignment((string) self::getArrayItem($outerShdw->attributes(), 'algn'));
1622
                                                        $shadow->getColor()->setRGB(self::getArrayItem($outerShdw->srgbClr->attributes(), 'val'));
1623
                                                        $shadow->setAlpha(self::getArrayItem($outerShdw->srgbClr->alpha->attributes(), 'val') / 1000);
1624
                                                    }
1625
                                                    $objDrawing->setWorksheet($docSheet);
1626
                                                } elseif (($this->includeCharts) && ($twoCellAnchor->graphicFrame)) {
1627
                                                    $fromCoordinate = \PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex((string) $twoCellAnchor->from->col) . ($twoCellAnchor->from->row + 1);
1628
                                                    $fromOffsetX = \PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUToPixels($twoCellAnchor->from->colOff);
1629
                                                    $fromOffsetY = \PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUToPixels($twoCellAnchor->from->rowOff);
1630
                                                    $toCoordinate = \PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex((string) $twoCellAnchor->to->col) . ($twoCellAnchor->to->row + 1);
1631
                                                    $toOffsetX = \PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUToPixels($twoCellAnchor->to->colOff);
1632
                                                    $toOffsetY = \PhpOffice\PhpSpreadsheet\Shared\Drawing::EMUToPixels($twoCellAnchor->to->rowOff);
1633
                                                    $graphic = $twoCellAnchor->graphicFrame->children('http://schemas.openxmlformats.org/drawingml/2006/main')->graphic;
1634
                                                    $chartRef = $graphic->graphicData->children('http://schemas.openxmlformats.org/drawingml/2006/chart')->chart;
1635
                                                    $thisChart = (string) $chartRef->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships');
1636
1637
                                                    $chartDetails[$docSheet->getTitle() . '!' . $thisChart] = [
1638
                                                        'fromCoordinate' => $fromCoordinate,
1639
                                                        'fromOffsetX' => $fromOffsetX,
1640
                                                        'fromOffsetY' => $fromOffsetY,
1641
                                                        'toCoordinate' => $toCoordinate,
1642
                                                        'toOffsetX' => $toOffsetX,
1643
                                                        'toOffsetY' => $toOffsetY,
1644
                                                        'worksheetTitle' => $docSheet->getTitle(),
1645
                                                    ];
1646
                                                }
1647
                                            }
1648
                                        }
1649
                                    }
1650
                                }
1651
                            }
1652
1653
                            // Loop through definedNames
1654
                            if ($xmlWorkbook->definedNames) {
1655
                                foreach ($xmlWorkbook->definedNames->definedName as $definedName) {
1656
                                    // Extract range
1657
                                    $extractedRange = (string) $definedName;
1658
                                    $extractedRange = preg_replace('/\'(\w+)\'\!/', '', $extractedRange);
1659 View Code Duplication
                                    if (($spos = strpos($extractedRange, '!')) !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1660
                                        $extractedRange = substr($extractedRange, 0, $spos) . str_replace('$', '', substr($extractedRange, $spos));
1661
                                    } else {
1662
                                        $extractedRange = str_replace('$', '', $extractedRange);
1663
                                    }
1664
1665
                                    // Valid range?
1666
                                    if (stripos((string) $definedName, '#REF!') !== false || $extractedRange == '') {
1667
                                        continue;
1668
                                    }
1669
1670
                                    // Some definedNames are only applicable if we are on the same sheet...
1671
                                    if ((string) $definedName['localSheetId'] != '' && (string) $definedName['localSheetId'] == $sheetId) {
1672
                                        // Switch on type
1673
                                        switch ((string) $definedName['name']) {
1674
                                            case '_xlnm._FilterDatabase':
1675
                                                if ((string) $definedName['hidden'] !== '1') {
1676
                                                    $extractedRange = explode(',', $extractedRange);
1677
                                                    foreach ($extractedRange as $range) {
1678
                                                        $autoFilterRange = $range;
1679
                                                        if (strpos($autoFilterRange, ':') !== false) {
1680
                                                            $docSheet->getAutoFilter()->setRange($autoFilterRange);
1681
                                                        }
1682
                                                    }
1683
                                                }
1684
                                                break;
1685
                                            case '_xlnm.Print_Titles':
1686
                                                // Split $extractedRange
1687
                                                $extractedRange = explode(',', $extractedRange);
1688
1689
                                                // Set print titles
1690
                                                foreach ($extractedRange as $range) {
1691
                                                    $matches = [];
1692
                                                    $range = str_replace('$', '', $range);
1693
1694
                                                    // check for repeating columns, e g. 'A:A' or 'A:D'
1695
                                                    if (preg_match('/!?([A-Z]+)\:([A-Z]+)$/', $range, $matches)) {
1696
                                                        $docSheet->getPageSetup()->setColumnsToRepeatAtLeft([$matches[1], $matches[2]]);
1697
                                                    } elseif (preg_match('/!?(\d+)\:(\d+)$/', $range, $matches)) {
1698
                                                        // check for repeating rows, e.g. '1:1' or '1:5'
1699
                                                        $docSheet->getPageSetup()->setRowsToRepeatAtTop([$matches[1], $matches[2]]);
1700
                                                    }
1701
                                                }
1702
                                                break;
1703
                                            case '_xlnm.Print_Area':
1704
                                                $rangeSets = explode(',', $extractedRange); // FIXME: what if sheetname contains comma?
1705
                                                $newRangeSets = [];
1706
                                                foreach ($rangeSets as $rangeSet) {
1707
                                                    $range = explode('!', $rangeSet); // FIXME: what if sheetname contains exclamation mark?
1708
                                                    $rangeSet = isset($range[1]) ? $range[1] : $range[0];
1709
                                                    if (strpos($rangeSet, ':') === false) {
1710
                                                        $rangeSet = $rangeSet . ':' . $rangeSet;
1711
                                                    }
1712
                                                    $newRangeSets[] = str_replace('$', '', $rangeSet);
1713
                                                }
1714
                                                $docSheet->getPageSetup()->setPrintArea(implode(',', $newRangeSets));
1715
                                                break;
1716
1717
                                            default:
1718
                                                break;
1719
                                        }
1720
                                    }
1721
                                }
1722
                            }
1723
1724
                            // Next sheet id
1725
                            ++$sheetId;
1726
                        }
1727
1728
                        // Loop through definedNames
1729
                        if ($xmlWorkbook->definedNames) {
1730
                            foreach ($xmlWorkbook->definedNames->definedName as $definedName) {
1731
                                // Extract range
1732
                                $extractedRange = (string) $definedName;
1733
                                $extractedRange = preg_replace('/\'(\w+)\'\!/', '', $extractedRange);
1734 View Code Duplication
                                if (($spos = strpos($extractedRange, '!')) !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1735
                                    $extractedRange = substr($extractedRange, 0, $spos) . str_replace('$', '', substr($extractedRange, $spos));
1736
                                } else {
1737
                                    $extractedRange = str_replace('$', '', $extractedRange);
1738
                                }
1739
1740
                                // Valid range?
1741
                                if (stripos((string) $definedName, '#REF!') !== false || $extractedRange == '') {
1742
                                    continue;
1743
                                }
1744
1745
                                // Some definedNames are only applicable if we are on the same sheet...
1746
                                if ((string) $definedName['localSheetId'] != '') {
1747
                                    // Local defined name
1748
                                    // Switch on type
1749
                                    switch ((string) $definedName['name']) {
1750
                                        case '_xlnm._FilterDatabase':
1751
                                        case '_xlnm.Print_Titles':
1752
                                        case '_xlnm.Print_Area':
1753
                                            break;
1754
                                        default:
1755
                                            if ($mapSheetId[(integer) $definedName['localSheetId']] !== null) {
1756
                                                $range = explode('!', (string) $definedName);
1757
                                                if (count($range) == 2) {
1758
                                                    $range[0] = str_replace("''", "'", $range[0]);
1759
                                                    $range[0] = str_replace("'", '', $range[0]);
1760
                                                    if ($worksheet = $docSheet->getParent()->getSheetByName($range[0])) {
1761
                                                        $extractedRange = str_replace('$', '', $range[1]);
1762
                                                        $scope = $docSheet->getParent()->getSheet($mapSheetId[(integer) $definedName['localSheetId']]);
0 ignored issues
show
Bug introduced by
The variable $docSheet does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1763
                                                        $excel->addNamedRange(new \PhpOffice\PhpSpreadsheet\NamedRange((string) $definedName['name'], $worksheet, $extractedRange, true, $scope));
1764
                                                    }
1765
                                                }
1766
                                            }
1767
                                            break;
1768
                                    }
1769
                                } elseif (!isset($definedName['localSheetId'])) {
1770
                                    // "Global" definedNames
1771
                                    $locatedSheet = null;
1772
                                    $extractedSheetName = '';
0 ignored issues
show
Unused Code introduced by
$extractedSheetName is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1773
                                    if (strpos((string) $definedName, '!') !== false) {
1774
                                        // Extract sheet name
1775
                                        $extractedSheetName = \PhpOffice\PhpSpreadsheet\Worksheet::extractSheetTitle((string) $definedName, true);
1776
                                        $extractedSheetName = $extractedSheetName[0];
1777
1778
                                        // Locate sheet
1779
                                        $locatedSheet = $excel->getSheetByName($extractedSheetName);
1780
1781
                                        // Modify range
1782
                                        $range = explode('!', $extractedRange);
1783
                                        $extractedRange = isset($range[1]) ? $range[1] : $range[0];
1784
                                    }
1785
1786
                                    if ($locatedSheet !== null) {
1787
                                        $excel->addNamedRange(new \PhpOffice\PhpSpreadsheet\NamedRange((string) $definedName['name'], $locatedSheet, $extractedRange, false));
1788
                                    }
1789
                                }
1790
                            }
1791
                        }
1792
                    }
1793
1794
                    if ((!$this->readDataOnly) || (!empty($this->loadSheetsOnly))) {
1795
                        // active sheet index
1796
                        $activeTab = intval($xmlWorkbook->bookViews->workbookView['activeTab']); // refers to old sheet index
1797
1798
                        // keep active sheet index if sheet is still loaded, else first sheet is set as the active
1799
                        if (isset($mapSheetId[$activeTab]) && $mapSheetId[$activeTab] !== null) {
1800
                            $excel->setActiveSheetIndex($mapSheetId[$activeTab]);
1801
                        } else {
1802
                            if ($excel->getSheetCount() == 0) {
1803
                                $excel->createSheet();
1804
                            }
1805
                            $excel->setActiveSheetIndex(0);
1806
                        }
1807
                    }
1808
                    break;
1809
            }
1810
        }
1811
1812
        if (!$this->readDataOnly) {
1813
            $contentTypes = simplexml_load_string(
1814
                $this->securityScan(
1815
                    $this->getFromZipArchive($zip, '[Content_Types].xml')
1816
                ),
1817
                'SimpleXMLElement',
1818
                \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
1819
            );
1820
            foreach ($contentTypes->Override as $contentType) {
1821
                switch ($contentType['ContentType']) {
1822
                    case 'application/vnd.openxmlformats-officedocument.drawingml.chart+xml':
1823
                        if ($this->includeCharts) {
1824
                            $chartEntryRef = ltrim($contentType['PartName'], '/');
1825
                            $chartElements = simplexml_load_string(
1826
                                $this->securityScan(
1827
                                    $this->getFromZipArchive($zip, $chartEntryRef)
1828
                                ),
1829
                                'SimpleXMLElement',
1830
                                \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
1831
                            );
1832
                            $objChart = \PhpOffice\PhpSpreadsheet\Reader\Excel2007\Chart::readChart($chartElements, basename($chartEntryRef, '.xml'));
1833
1834
//
1835
                            if (isset($charts[$chartEntryRef])) {
1836
                                $chartPositionRef = $charts[$chartEntryRef]['sheet'] . '!' . $charts[$chartEntryRef]['id'];
1837
                                if (isset($chartDetails[$chartPositionRef])) {
1838
                                    $excel->getSheetByName($charts[$chartEntryRef]['sheet'])->addChart($objChart);
1839
                                    $objChart->setWorksheet($excel->getSheetByName($charts[$chartEntryRef]['sheet']));
1840
                                    $objChart->setTopLeftPosition($chartDetails[$chartPositionRef]['fromCoordinate'], $chartDetails[$chartPositionRef]['fromOffsetX'], $chartDetails[$chartPositionRef]['fromOffsetY']);
1841
                                    $objChart->setBottomRightPosition($chartDetails[$chartPositionRef]['toCoordinate'], $chartDetails[$chartPositionRef]['toOffsetX'], $chartDetails[$chartPositionRef]['toOffsetY']);
1842
                                }
1843
                            }
1844
                        }
1845
                }
1846
            }
1847
        }
1848
1849
        $zip->close();
1850
1851
        return $excel;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $excel; (PhpOffice\PhpSpreadsheet\Spreadsheet) is incompatible with the return type declared by the interface PhpOffice\PhpSpreadsheet\Reader\IReader::load of type PhpOffice\PhpSpreadsheet\Reader\PhpSpreadsheet.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
1852
    }
1853
1854
    private static function readColor($color, $background = false)
1855
    {
1856
        if (isset($color['rgb'])) {
1857
            return (string) $color['rgb'];
1858
        } elseif (isset($color['indexed'])) {
1859
            return \PhpOffice\PhpSpreadsheet\Style\Color::indexedColor($color['indexed'] - 7, $background)->getARGB();
1860
        } elseif (isset($color['theme'])) {
1861
            if (self::$theme !== null) {
1862
                $returnColour = self::$theme->getColourByIndex((int) $color['theme']);
1863
                if (isset($color['tint'])) {
1864
                    $tintAdjust = (float) $color['tint'];
1865
                    $returnColour = \PhpOffice\PhpSpreadsheet\Style\Color::changeBrightness($returnColour, $tintAdjust);
1866
                }
1867
1868
                return 'FF' . $returnColour;
1869
            }
1870
        }
1871
1872
        if ($background) {
1873
            return 'FFFFFFFF';
1874
        }
1875
1876
        return 'FF000000';
1877
    }
1878
1879
    /**
1880
     * @param \PhpOffice\PhpSpreadsheet\Style $docStyle
1881
     * @param \stdClass $style
1882
     */
1883
    private static function readStyle($docStyle, \stdClass $style)
1884
    {
1885
        $docStyle->getNumberFormat()->setFormatCode($style->numFmt);
1886
1887
        // font
1888
        if (isset($style->font)) {
1889
            $docStyle->getFont()->setName((string) $style->font->name['val']);
1890
            $docStyle->getFont()->setSize((string) $style->font->sz['val']);
1891 View Code Duplication
            if (isset($style->font->b)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1892
                $docStyle->getFont()->setBold(!isset($style->font->b['val']) || self::boolean((string) $style->font->b['val']));
1893
            }
1894 View Code Duplication
            if (isset($style->font->i)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1895
                $docStyle->getFont()->setItalic(!isset($style->font->i['val']) || self::boolean((string) $style->font->i['val']));
1896
            }
1897 View Code Duplication
            if (isset($style->font->strike)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1898
                $docStyle->getFont()->setStrikethrough(!isset($style->font->strike['val']) || self::boolean((string) $style->font->strike['val']));
1899
            }
1900
            $docStyle->getFont()->getColor()->setARGB(self::readColor($style->font->color));
1901
1902 View Code Duplication
            if (isset($style->font->u) && !isset($style->font->u['val'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1903
                $docStyle->getFont()->setUnderline(\PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_SINGLE);
1904
            } elseif (isset($style->font->u) && isset($style->font->u['val'])) {
1905
                $docStyle->getFont()->setUnderline((string) $style->font->u['val']);
1906
            }
1907
1908 View Code Duplication
            if (isset($style->font->vertAlign) && isset($style->font->vertAlign['val'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1909
                $vertAlign = strtolower((string) $style->font->vertAlign['val']);
1910
                if ($vertAlign == 'superscript') {
1911
                    $docStyle->getFont()->setSuperScript(true);
1912
                }
1913
                if ($vertAlign == 'subscript') {
1914
                    $docStyle->getFont()->setSubScript(true);
1915
                }
1916
            }
1917
        }
1918
1919
        // fill
1920
        if (isset($style->fill)) {
1921
            if ($style->fill->gradientFill) {
1922
                $gradientFill = $style->fill->gradientFill[0];
1923
                if (!empty($gradientFill['type'])) {
1924
                    $docStyle->getFill()->setFillType((string) $gradientFill['type']);
1925
                }
1926
                $docStyle->getFill()->setRotation(floatval($gradientFill['degree']));
1927
                $gradientFill->registerXPathNamespace('sml', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
1928
                $docStyle->getFill()->getStartColor()->setARGB(self::readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=0]'))->color));
1929
                $docStyle->getFill()->getEndColor()->setARGB(self::readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=1]'))->color));
1930
            } elseif ($style->fill->patternFill) {
1931
                $patternType = (string) $style->fill->patternFill['patternType'] != '' ? (string) $style->fill->patternFill['patternType'] : 'solid';
1932
                $docStyle->getFill()->setFillType($patternType);
1933
                if ($style->fill->patternFill->fgColor) {
1934
                    $docStyle->getFill()->getStartColor()->setARGB(self::readColor($style->fill->patternFill->fgColor, true));
1935
                } else {
1936
                    $docStyle->getFill()->getStartColor()->setARGB('FF000000');
1937
                }
1938
                if ($style->fill->patternFill->bgColor) {
1939
                    $docStyle->getFill()->getEndColor()->setARGB(self::readColor($style->fill->patternFill->bgColor, true));
1940
                }
1941
            }
1942
        }
1943
1944
        // border
1945
        if (isset($style->border)) {
1946
            $diagonalUp = self::boolean((string) $style->border['diagonalUp']);
1947
            $diagonalDown = self::boolean((string) $style->border['diagonalDown']);
1948
            if (!$diagonalUp && !$diagonalDown) {
1949
                $docStyle->getBorders()->setDiagonalDirection(\PhpOffice\PhpSpreadsheet\Style\Borders::DIAGONAL_NONE);
1950
            } elseif ($diagonalUp && !$diagonalDown) {
1951
                $docStyle->getBorders()->setDiagonalDirection(\PhpOffice\PhpSpreadsheet\Style\Borders::DIAGONAL_UP);
1952
            } elseif (!$diagonalUp && $diagonalDown) {
1953
                $docStyle->getBorders()->setDiagonalDirection(\PhpOffice\PhpSpreadsheet\Style\Borders::DIAGONAL_DOWN);
1954
            } else {
1955
                $docStyle->getBorders()->setDiagonalDirection(\PhpOffice\PhpSpreadsheet\Style\Borders::DIAGONAL_BOTH);
1956
            }
1957
            self::readBorder($docStyle->getBorders()->getLeft(), $style->border->left);
1958
            self::readBorder($docStyle->getBorders()->getRight(), $style->border->right);
1959
            self::readBorder($docStyle->getBorders()->getTop(), $style->border->top);
1960
            self::readBorder($docStyle->getBorders()->getBottom(), $style->border->bottom);
1961
            self::readBorder($docStyle->getBorders()->getDiagonal(), $style->border->diagonal);
1962
        }
1963
1964
        // alignment
1965
        if (isset($style->alignment)) {
1966
            $docStyle->getAlignment()->setHorizontal((string) $style->alignment['horizontal']);
1967
            $docStyle->getAlignment()->setVertical((string) $style->alignment['vertical']);
1968
1969
            $textRotation = 0;
1970
            if ((int) $style->alignment['textRotation'] <= 90) {
1971
                $textRotation = (int) $style->alignment['textRotation'];
1972
            } elseif ((int) $style->alignment['textRotation'] > 90) {
1973
                $textRotation = 90 - (int) $style->alignment['textRotation'];
1974
            }
1975
1976
            $docStyle->getAlignment()->setTextRotation(intval($textRotation));
1977
            $docStyle->getAlignment()->setWrapText(self::boolean((string) $style->alignment['wrapText']));
1978
            $docStyle->getAlignment()->setShrinkToFit(self::boolean((string) $style->alignment['shrinkToFit']));
1979
            $docStyle->getAlignment()->setIndent(intval((string) $style->alignment['indent']) > 0 ? intval((string) $style->alignment['indent']) : 0);
1980
            $docStyle->getAlignment()->setReadorder(intval((string) $style->alignment['readingOrder']) > 0 ? intval((string) $style->alignment['readingOrder']) : 0);
1981
        }
1982
1983
        // protection
1984
        if (isset($style->protection)) {
1985 View Code Duplication
            if (isset($style->protection['locked'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1986
                if (self::boolean((string) $style->protection['locked'])) {
1987
                    $docStyle->getProtection()->setLocked(\PhpOffice\PhpSpreadsheet\Style\Protection::PROTECTION_PROTECTED);
1988
                } else {
1989
                    $docStyle->getProtection()->setLocked(\PhpOffice\PhpSpreadsheet\Style\Protection::PROTECTION_UNPROTECTED);
1990
                }
1991
            }
1992
1993 View Code Duplication
            if (isset($style->protection['hidden'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1994
                if (self::boolean((string) $style->protection['hidden'])) {
1995
                    $docStyle->getProtection()->setHidden(\PhpOffice\PhpSpreadsheet\Style\Protection::PROTECTION_PROTECTED);
1996
                } else {
1997
                    $docStyle->getProtection()->setHidden(\PhpOffice\PhpSpreadsheet\Style\Protection::PROTECTION_UNPROTECTED);
1998
                }
1999
            }
2000
        }
2001
2002
        // top-level style settings
2003
        if (isset($style->quotePrefix)) {
2004
            $docStyle->setQuotePrefix($style->quotePrefix);
2005
        }
2006
    }
2007
2008
    private static function readBorder($docBorder, $eleBorder)
2009
    {
2010
        if (isset($eleBorder['style'])) {
2011
            $docBorder->setBorderStyle((string) $eleBorder['style']);
2012
        }
2013
        if (isset($eleBorder->color)) {
2014
            $docBorder->getColor()->setARGB(self::readColor($eleBorder->color));
2015
        }
2016
    }
2017
2018
    private function parseRichText($is = null)
2019
    {
2020
        $value = new \PhpOffice\PhpSpreadsheet\RichText();
2021
2022
        if (isset($is->t)) {
2023
            $value->createText(\PhpOffice\PhpSpreadsheet\Shared\StringHelper::controlCharacterOOXML2PHP((string) $is->t));
2024
        } else {
2025
            if (is_object($is->r)) {
2026
                foreach ($is->r as $run) {
2027
                    if (!isset($run->rPr)) {
2028
                        $objText = $value->createText(\PhpOffice\PhpSpreadsheet\Shared\StringHelper::controlCharacterOOXML2PHP((string) $run->t));
0 ignored issues
show
Unused Code introduced by
$objText is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2029
                    } else {
2030
                        $objText = $value->createTextRun(\PhpOffice\PhpSpreadsheet\Shared\StringHelper::controlCharacterOOXML2PHP((string) $run->t));
2031
2032 View Code Duplication
                        if (isset($run->rPr->rFont['val'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2033
                            $objText->getFont()->setName((string) $run->rPr->rFont['val']);
2034
                        }
2035
                        if (isset($run->rPr->sz['val'])) {
2036
                            $objText->getFont()->setSize((string) $run->rPr->sz['val']);
2037
                        }
2038
                        if (isset($run->rPr->color)) {
2039
                            $objText->getFont()->setColor(new \PhpOffice\PhpSpreadsheet\Style\Color(self::readColor($run->rPr->color)));
2040
                        }
2041 View Code Duplication
                        if ((isset($run->rPr->b['val']) && self::boolean((string) $run->rPr->b['val'])) ||
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2042
                            (isset($run->rPr->b) && !isset($run->rPr->b['val']))) {
2043
                            $objText->getFont()->setBold(true);
2044
                        }
2045 View Code Duplication
                        if ((isset($run->rPr->i['val']) && self::boolean((string) $run->rPr->i['val'])) ||
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2046
                            (isset($run->rPr->i) && !isset($run->rPr->i['val']))) {
2047
                            $objText->getFont()->setItalic(true);
2048
                        }
2049 View Code Duplication
                        if (isset($run->rPr->vertAlign) && isset($run->rPr->vertAlign['val'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2050
                            $vertAlign = strtolower((string) $run->rPr->vertAlign['val']);
2051
                            if ($vertAlign == 'superscript') {
2052
                                $objText->getFont()->setSuperScript(true);
2053
                            }
2054
                            if ($vertAlign == 'subscript') {
2055
                                $objText->getFont()->setSubScript(true);
2056
                            }
2057
                        }
2058 View Code Duplication
                        if (isset($run->rPr->u) && !isset($run->rPr->u['val'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2059
                            $objText->getFont()->setUnderline(\PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_SINGLE);
2060
                        } elseif (isset($run->rPr->u) && isset($run->rPr->u['val'])) {
2061
                            $objText->getFont()->setUnderline((string) $run->rPr->u['val']);
2062
                        }
2063 View Code Duplication
                        if ((isset($run->rPr->strike['val']) && self::boolean((string) $run->rPr->strike['val'])) ||
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2064
                            (isset($run->rPr->strike) && !isset($run->rPr->strike['val']))) {
2065
                            $objText->getFont()->setStrikethrough(true);
2066
                        }
2067
                    }
2068
                }
2069
            }
2070
        }
2071
2072
        return $value;
2073
    }
2074
2075
    /**
2076
     * @param \PhpOffice\PhpSpreadsheet\Spreadsheet $excel
2077
     */
2078
    private function readRibbon(\PhpOffice\PhpSpreadsheet\Spreadsheet $excel, $customUITarget, $zip)
2079
    {
2080
        $baseDir = dirname($customUITarget);
2081
        $nameCustomUI = basename($customUITarget);
2082
        // get the xml file (ribbon)
2083
        $localRibbon = $this->getFromZipArchive($zip, $customUITarget);
2084
        $customUIImagesNames = [];
2085
        $customUIImagesBinaries = [];
2086
        // something like customUI/_rels/customUI.xml.rels
2087
        $pathRels = $baseDir . '/_rels/' . $nameCustomUI . '.rels';
2088
        $dataRels = $this->getFromZipArchive($zip, $pathRels);
2089
        if ($dataRels) {
2090
            // exists and not empty if the ribbon have some pictures (other than internal MSO)
2091
            $UIRels = simplexml_load_string(
2092
                $this->securityScan($dataRels),
2093
                'SimpleXMLElement',
2094
                \PhpOffice\PhpSpreadsheet\Settings::getLibXmlLoaderOptions()
2095
            );
2096
            if ($UIRels) {
2097
                // we need to save id and target to avoid parsing customUI.xml and "guess" if it's a pseudo callback who load the image
2098
                foreach ($UIRels->Relationship as $ele) {
2099
                    if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') {
2100
                        // an image ?
2101
                        $customUIImagesNames[(string) $ele['Id']] = (string) $ele['Target'];
2102
                        $customUIImagesBinaries[(string) $ele['Target']] = $this->getFromZipArchive($zip, $baseDir . '/' . (string) $ele['Target']);
2103
                    }
2104
                }
2105
            }
2106
        }
2107
        if ($localRibbon) {
2108
            $excel->setRibbonXMLData($customUITarget, $localRibbon);
2109
            if (count($customUIImagesNames) > 0 && count($customUIImagesBinaries) > 0) {
2110
                $excel->setRibbonBinObjects($customUIImagesNames, $customUIImagesBinaries);
2111
            } else {
2112
                $excel->setRibbonBinObjects(null);
2113
            }
2114
        } else {
2115
            $excel->setRibbonXMLData(null);
2116
            $excel->setRibbonBinObjects(null);
2117
        }
2118
    }
2119
2120
    private static function getArrayItem($array, $key = 0)
2121
    {
2122
        return isset($array[$key]) ? $array[$key] : null;
2123
    }
2124
2125
    private static function dirAdd($base, $add)
2126
    {
2127
        return preg_replace('~[^/]+/\.\./~', '', dirname($base) . "/$add");
2128
    }
2129
2130
    private static function toCSSArray($style)
2131
    {
2132
        $style = str_replace(["\r", "\n"], '', $style);
2133
2134
        $temp = explode(';', $style);
2135
        $style = [];
2136
        foreach ($temp as $item) {
2137
            $item = explode(':', $item);
2138
2139
            if (strpos($item[1], 'px') !== false) {
2140
                $item[1] = str_replace('px', '', $item[1]);
2141
            }
2142 View Code Duplication
            if (strpos($item[1], 'pt') !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2143
                $item[1] = str_replace('pt', '', $item[1]);
2144
                $item[1] = \PhpOffice\PhpSpreadsheet\Shared\Font::fontSizeToPixels($item[1]);
2145
            }
2146 View Code Duplication
            if (strpos($item[1], 'in') !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2147
                $item[1] = str_replace('in', '', $item[1]);
2148
                $item[1] = \PhpOffice\PhpSpreadsheet\Shared\Font::inchSizeToPixels($item[1]);
2149
            }
2150 View Code Duplication
            if (strpos($item[1], 'cm') !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2151
                $item[1] = str_replace('cm', '', $item[1]);
2152
                $item[1] = \PhpOffice\PhpSpreadsheet\Shared\Font::centimeterSizeToPixels($item[1]);
2153
            }
2154
2155
            $style[$item[0]] = $item[1];
2156
        }
2157
2158
        return $style;
2159
    }
2160
2161
    private static function boolean($value = null)
2162
    {
2163
        if (is_object($value)) {
2164
            $value = (string) $value;
2165
        }
2166
        if (is_numeric($value)) {
2167
            return (bool) $value;
2168
        }
2169
2170
        return $value === 'true' || $value === 'TRUE';
2171
    }
2172
}
2173