Completed
Push — develop ( d3e769...440bfe )
by Adrien
22:10
created

Xlsx::readStyle()   F

Complexity

Conditions 39
Paths > 20000

Size

Total Lines 125
Code Lines 82

Duplication

Lines 37
Ratio 29.6 %

Code Coverage

Tests 62
CRAP Score 54.1584

Importance

Changes 0
Metric Value
cc 39
eloc 82
nc 429496.7295
nop 2
dl 37
loc 125
ccs 62
cts 79
cp 0.7848
crap 54.1584
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Reader;
4
5
use PhpOffice\PhpSpreadsheet\Cell;
6
use PhpOffice\PhpSpreadsheet\Document\Properties;
7
use PhpOffice\PhpSpreadsheet\NamedRange;
8
use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Chart;
9
use PhpOffice\PhpSpreadsheet\ReferenceHelper;
10
use PhpOffice\PhpSpreadsheet\RichText;
11
use PhpOffice\PhpSpreadsheet\Settings;
12
use PhpOffice\PhpSpreadsheet\Shared\Date;
13
use PhpOffice\PhpSpreadsheet\Shared\Drawing;
14
use PhpOffice\PhpSpreadsheet\Shared\File;
15
use PhpOffice\PhpSpreadsheet\Shared\Font;
16
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
17
use PhpOffice\PhpSpreadsheet\Spreadsheet;
18
use PhpOffice\PhpSpreadsheet\Style;
19
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
20
use PhpOffice\PhpSpreadsheet\Worksheet;
21
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column;
22
use XMLReader;
23
use ZipArchive;
24
25
class Xlsx extends BaseReader implements IReader
26
{
27
    /**
28
     * ReferenceHelper instance.
29
     *
30
     * @var ReferenceHelper
31
     */
32
    private $referenceHelper;
33
34
    /**
35
     * Xlsx\Theme instance.
36
     *
37
     * @var Xlsx\Theme
38
     */
39
    private static $theme = null;
40
41
    /**
42
     * Create a new Xlsx Reader instance.
43
     */
44 13
    public function __construct()
45
    {
46 13
        $this->readFilter = new DefaultReadFilter();
47 13
        $this->referenceHelper = ReferenceHelper::getInstance();
48 13
    }
49
50
    /**
51
     * Can the current IReader read the file?
52
     *
53
     * @param string $pFilename
54
     *
55
     * @throws Exception
56
     *
57
     * @return bool
58
     */
59 5
    public function canRead($pFilename)
60
    {
61 5
        File::assertFile($pFilename);
62
63 5
        $xl = false;
64
        // Load file
65 5
        $zip = new ZipArchive();
66 5
        if ($zip->open($pFilename) === true) {
67
            // check if it is an OOXML archive
68 5
            $rels = simplexml_load_string(
69 5
                $this->securityScan(
70 5
                    $this->getFromZipArchive($zip, '_rels/.rels')
71
                ),
72 5
                'SimpleXMLElement',
73 5
                Settings::getLibXmlLoaderOptions()
74
            );
75 5
            if ($rels !== false) {
76 5
                foreach ($rels->Relationship as $rel) {
77 5
                    switch ($rel['Type']) {
78 5
                        case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument':
79 5
                            if (basename($rel['Target']) == 'workbook.xml') {
80 5
                                $xl = true;
81
                            }
82
83 5
                            break;
84
                    }
85
                }
86
            }
87 5
            $zip->close();
88
        }
89
90 5
        return $xl;
91
    }
92
93
    /**
94
     * Reads names of the worksheets from a file, without parsing the whole file to a Spreadsheet object.
95
     *
96
     * @param string $pFilename
97
     *
98
     * @throws Exception
99
     *
100
     * @return array
101
     */
102 1
    public function listWorksheetNames($pFilename)
103
    {
104 1
        File::assertFile($pFilename);
105
106 1
        $worksheetNames = [];
107
108 1
        $zip = new ZipArchive();
109 1
        $zip->open($pFilename);
110
111
        //    The files we're looking at here are small enough that simpleXML is more efficient than XMLReader
112 1
        $rels = simplexml_load_string(
113 1
            $this->securityScan($this->getFromZipArchive($zip, '_rels/.rels'))
114
        ); //~ http://schemas.openxmlformats.org/package/2006/relationships");
115 1
        foreach ($rels->Relationship as $rel) {
116 1
            switch ($rel['Type']) {
117 1
                case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument':
118 1
                    $xmlWorkbook = simplexml_load_string(
119 1
                        $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}"))
120
                    ); //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
121
122 1
                    if ($xmlWorkbook->sheets) {
123 1
                        foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
124
                            // Check if sheet should be skipped
125 1
                            $worksheetNames[] = (string) $eleSheet['name'];
126
                        }
127
                    }
128
            }
129
        }
130
131 1
        $zip->close();
132
133 1
        return $worksheetNames;
134
    }
135
136
    /**
137
     * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns).
138
     *
139
     * @param string $pFilename
140
     *
141
     * @throws Exception
142
     *
143
     * @return array
144
     */
145 1
    public function listWorksheetInfo($pFilename)
146
    {
147 1
        File::assertFile($pFilename);
148
149 1
        $worksheetInfo = [];
150
151 1
        $zip = new ZipArchive();
152 1
        $zip->open($pFilename);
153
154 1
        $rels = simplexml_load_string(
155
            //~ http://schemas.openxmlformats.org/package/2006/relationships"
156 1
            $this->securityScan($this->getFromZipArchive($zip, '_rels/.rels')),
157 1
            'SimpleXMLElement',
158 1
            Settings::getLibXmlLoaderOptions()
159
        );
160 1
        foreach ($rels->Relationship as $rel) {
161 1
            if ($rel['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument') {
162 1
                $dir = dirname($rel['Target']);
163 1
                $relsWorkbook = simplexml_load_string(
164
                    //~ http://schemas.openxmlformats.org/package/2006/relationships"
165 1
                    $this->securityScan(
166 1
                        $this->getFromZipArchive($zip, "$dir/_rels/" . basename($rel['Target']) . '.rels')
167
                    ),
168 1
                    'SimpleXMLElement',
169 1
                    Settings::getLibXmlLoaderOptions()
170
                );
171 1
                $relsWorkbook->registerXPathNamespace('rel', 'http://schemas.openxmlformats.org/package/2006/relationships');
172
173 1
                $worksheets = [];
174 1
                foreach ($relsWorkbook->Relationship as $ele) {
175 1
                    if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet') {
176 1
                        $worksheets[(string) $ele['Id']] = $ele['Target'];
177
                    }
178
                }
179
180 1
                $xmlWorkbook = simplexml_load_string(
181
                    //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
182 1
                    $this->securityScan(
183 1
                        $this->getFromZipArchive($zip, "{$rel['Target']}")
184
                    ),
185 1
                    'SimpleXMLElement',
186 1
                    Settings::getLibXmlLoaderOptions()
187
                );
188 1
                if ($xmlWorkbook->sheets) {
189 1
                    $dir = dirname($rel['Target']);
190
                    /** @var \SimpleXMLElement $eleSheet */
191 1
                    foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
192
                        $tmpInfo = [
193 1
                            'worksheetName' => (string) $eleSheet['name'],
194 1
                            'lastColumnLetter' => 'A',
195 1
                            'lastColumnIndex' => 0,
196 1
                            'totalRows' => 0,
197 1
                            'totalColumns' => 0,
198
                        ];
199
200 1
                        $fileWorksheet = $worksheets[(string) self::getArrayItem($eleSheet->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id')];
201
202 1
                        $xml = new XMLReader();
203 1
                        $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...
204 1
                            $this->securityScanFile(
205 1
                                'zip://' . File::realpath($pFilename) . '#' . "$dir/$fileWorksheet"
206
                            ),
207 1
                            null,
208 1
                            Settings::getLibXmlLoaderOptions()
209
                        );
210 1
                        $xml->setParserProperty(2, true);
211
212 1
                        $currCells = 0;
213 1
                        while ($xml->read()) {
214 1
                            if ($xml->name == 'row' && $xml->nodeType == XMLReader::ELEMENT) {
215 1
                                $row = $xml->getAttribute('r');
216 1
                                $tmpInfo['totalRows'] = $row;
217 1
                                $tmpInfo['totalColumns'] = max($tmpInfo['totalColumns'], $currCells);
218 1
                                $currCells = 0;
219 1
                            } elseif ($xml->name == 'c' && $xml->nodeType == XMLReader::ELEMENT) {
220 1
                                ++$currCells;
221
                            }
222
                        }
223 1
                        $tmpInfo['totalColumns'] = max($tmpInfo['totalColumns'], $currCells);
224 1
                        $xml->close();
225
226 1
                        $tmpInfo['lastColumnIndex'] = $tmpInfo['totalColumns'] - 1;
227 1
                        $tmpInfo['lastColumnLetter'] = Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
228
229 1
                        $worksheetInfo[] = $tmpInfo;
230
                    }
231
                }
232
            }
233
        }
234
235 1
        $zip->close();
236
237 1
        return $worksheetInfo;
238
    }
239
240 1
    private static function castToBoolean($c)
241
    {
242 1
        $value = isset($c->v) ? (string) $c->v : null;
243 1
        if ($value == '0') {
244
            return false;
245 1
        } elseif ($value == '1') {
246 1
            return true;
247
        }
248
249
        return (bool) $c->v;
250
        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...
251
    }
252
253
    private static function castToError($c)
254
    {
255
        return isset($c->v) ? (string) $c->v : null;
256
    }
257
258 6
    private static function castToString($c)
259
    {
260 6
        return isset($c->v) ? (string) $c->v : null;
261
    }
262
263 3
    private function castToFormula($c, $r, &$cellDataType, &$value, &$calculatedValue, &$sharedFormulas, $castBaseType)
264
    {
265 3
        $cellDataType = 'f';
266 3
        $value = "={$c->f}";
267 3
        $calculatedValue = self::$castBaseType($c);
268
269
        // Shared formula?
270 3
        if (isset($c->f['t']) && strtolower((string) $c->f['t']) == 'shared') {
271 1
            $instance = (string) $c->f['si'];
272
273 1
            if (!isset($sharedFormulas[(string) $c->f['si']])) {
274 1
                $sharedFormulas[$instance] = ['master' => $r, 'formula' => $value];
275
            } else {
276 1
                $master = Cell::coordinateFromString($sharedFormulas[$instance]['master']);
277 1
                $current = Cell::coordinateFromString($r);
278
279 1
                $difference = [0, 0];
280 1
                $difference[0] = Cell::columnIndexFromString($current[0]) - Cell::columnIndexFromString($master[0]);
281 1
                $difference[1] = $current[1] - $master[1];
282
283 1
                $value = $this->referenceHelper->updateFormulaReferences($sharedFormulas[$instance]['formula'], 'A1', $difference[0], $difference[1]);
284
            }
285
        }
286 3
    }
287
288
    /**
289
     * @param ZipArchive $archive
290
     * @param string $fileName
291
     *
292
     * @return string
293
     */
294 13
    private function getFromZipArchive(ZipArchive $archive, $fileName = '')
295
    {
296
        // Root-relative paths
297 13
        if (strpos($fileName, '//') !== false) {
298
            $fileName = substr($fileName, strpos($fileName, '//') + 1);
299
        }
300 13
        $fileName = File::realpath($fileName);
301
302
        // Sadly, some 3rd party xlsx generators don't use consistent case for filenaming
303
        //    so we need to load case-insensitively from the zip file
304
305
        // Apache POI fixes
306 13
        $contents = $archive->getFromIndex(
307 13
            $archive->locateName($fileName, ZipArchive::FL_NOCASE)
308
        );
309 13
        if ($contents === false) {
310
            $contents = $archive->getFromIndex(
311
                $archive->locateName(substr($fileName, 1), ZipArchive::FL_NOCASE)
312
            );
313
        }
314
315 13
        return $contents;
316
    }
317
318
    /**
319
     * Loads Spreadsheet from file.
320
     *
321
     * @param string $pFilename
322
     *
323
     * @throws Exception
324
     *
325
     * @return Spreadsheet
326
     */
327 11
    public function load($pFilename)
328
    {
329 11
        File::assertFile($pFilename);
330
331
        // Initialisations
332 11
        $excel = new Spreadsheet();
333 11
        $excel->removeSheetByIndex(0);
334 11
        if (!$this->readDataOnly) {
335 11
            $excel->removeCellStyleXfByIndex(0); // remove the default style
336 11
            $excel->removeCellXfByIndex(0); // remove the default style
337
        }
338
339 11
        $zip = new ZipArchive();
340 11
        $zip->open($pFilename);
341
342
        //    Read the theme first, because we need the colour scheme when reading the styles
343 11
        $wbRels = simplexml_load_string(
344
            //~ http://schemas.openxmlformats.org/package/2006/relationships"
345 11
            $this->securityScan($this->getFromZipArchive($zip, 'xl/_rels/workbook.xml.rels')),
346 11
            'SimpleXMLElement',
347 11
            Settings::getLibXmlLoaderOptions()
348
        );
349 11
        foreach ($wbRels->Relationship as $rel) {
350 11
            switch ($rel['Type']) {
351 11
                case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme':
352 11
                    $themeOrderArray = ['lt1', 'dk1', 'lt2', 'dk2'];
353 11
                    $themeOrderAdditional = count($themeOrderArray);
354
355 11
                    $xmlTheme = simplexml_load_string(
356 11
                        $this->securityScan($this->getFromZipArchive($zip, "xl/{$rel['Target']}")),
357 11
                        'SimpleXMLElement',
358 11
                        Settings::getLibXmlLoaderOptions()
359
                    );
360 11
                    if (is_object($xmlTheme)) {
361 11
                        $xmlThemeName = $xmlTheme->attributes();
362 11
                        $xmlTheme = $xmlTheme->children('http://schemas.openxmlformats.org/drawingml/2006/main');
363 11
                        $themeName = (string) $xmlThemeName['name'];
364
365 11
                        $colourScheme = $xmlTheme->themeElements->clrScheme->attributes();
366 11
                        $colourSchemeName = (string) $colourScheme['name'];
367 11
                        $colourScheme = $xmlTheme->themeElements->clrScheme->children('http://schemas.openxmlformats.org/drawingml/2006/main');
368
369 11
                        $themeColours = [];
370 11
                        foreach ($colourScheme as $k => $xmlColour) {
371 11
                            $themePos = array_search($k, $themeOrderArray);
372 11
                            if ($themePos === false) {
373 11
                                $themePos = $themeOrderAdditional++;
374
                            }
375 11
                            if (isset($xmlColour->sysClr)) {
376 11
                                $xmlColourData = $xmlColour->sysClr->attributes();
377 11
                                $themeColours[$themePos] = $xmlColourData['lastClr'];
378 11
                            } elseif (isset($xmlColour->srgbClr)) {
379 11
                                $xmlColourData = $xmlColour->srgbClr->attributes();
380 11
                                $themeColours[$themePos] = $xmlColourData['val'];
381
                            }
382
                        }
383 11
                        self::$theme = new Xlsx\Theme($themeName, $colourSchemeName, $themeColours);
384
                    }
385
386 11
                    break;
387
            }
388
        }
389
390 11
        $rels = simplexml_load_string(
391
            //~ http://schemas.openxmlformats.org/package/2006/relationships"
392 11
            $this->securityScan($this->getFromZipArchive($zip, '_rels/.rels')),
393 11
            'SimpleXMLElement',
394 11
            Settings::getLibXmlLoaderOptions()
395
        );
396 11
        foreach ($rels->Relationship as $rel) {
397 11
            switch ($rel['Type']) {
398 11
                case 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties':
399 10
                    $xmlCore = simplexml_load_string(
400 10
                        $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")),
401 10
                        'SimpleXMLElement',
402 10
                        Settings::getLibXmlLoaderOptions()
403
                    );
404 10
                    if (is_object($xmlCore)) {
405 10
                        $xmlCore->registerXPathNamespace('dc', 'http://purl.org/dc/elements/1.1/');
406 10
                        $xmlCore->registerXPathNamespace('dcterms', 'http://purl.org/dc/terms/');
407 10
                        $xmlCore->registerXPathNamespace('cp', 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties');
408 10
                        $docProps = $excel->getProperties();
409 10
                        $docProps->setCreator((string) self::getArrayItem($xmlCore->xpath('dc:creator')));
410 10
                        $docProps->setLastModifiedBy((string) self::getArrayItem($xmlCore->xpath('cp:lastModifiedBy')));
411 10
                        $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...heet\Document\datetime>.

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...
412 10
                        $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...heet\Document\datetime>.

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...
413 10
                        $docProps->setTitle((string) self::getArrayItem($xmlCore->xpath('dc:title')));
414 10
                        $docProps->setDescription((string) self::getArrayItem($xmlCore->xpath('dc:description')));
415 10
                        $docProps->setSubject((string) self::getArrayItem($xmlCore->xpath('dc:subject')));
416 10
                        $docProps->setKeywords((string) self::getArrayItem($xmlCore->xpath('cp:keywords')));
417 10
                        $docProps->setCategory((string) self::getArrayItem($xmlCore->xpath('cp:category')));
418
                    }
419
420 10
                    break;
421 11
                case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties':
422 10
                    $xmlCore = simplexml_load_string(
423 10
                        $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")),
424 10
                        'SimpleXMLElement',
425 10
                        Settings::getLibXmlLoaderOptions()
426
                    );
427 10
                    if (is_object($xmlCore)) {
428 10
                        $docProps = $excel->getProperties();
429 10
                        if (isset($xmlCore->Company)) {
430 9
                            $docProps->setCompany((string) $xmlCore->Company);
431
                        }
432 10
                        if (isset($xmlCore->Manager)) {
433 7
                            $docProps->setManager((string) $xmlCore->Manager);
434
                        }
435
                    }
436
437 10
                    break;
438 11
                case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties':
439 3
                    $xmlCore = simplexml_load_string(
440 3
                        $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")),
441 3
                        'SimpleXMLElement',
442 3
                        Settings::getLibXmlLoaderOptions()
443
                    );
444 3
                    if (is_object($xmlCore)) {
445 3
                        $docProps = $excel->getProperties();
446
                        /** @var \SimpleXMLElement $xmlProperty */
447 3
                        foreach ($xmlCore as $xmlProperty) {
448 3
                            $cellDataOfficeAttributes = $xmlProperty->attributes();
449 3
                            if (isset($cellDataOfficeAttributes['name'])) {
450 3
                                $propertyName = (string) $cellDataOfficeAttributes['name'];
451 3
                                $cellDataOfficeChildren = $xmlProperty->children('http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes');
452 3
                                $attributeType = $cellDataOfficeChildren->getName();
453 3
                                $attributeValue = (string) $cellDataOfficeChildren->{$attributeType};
454 3
                                $attributeValue = Properties::convertProperty($attributeValue, $attributeType);
455 3
                                $attributeType = Properties::convertPropertyType($attributeType);
456 3
                                $docProps->setCustomProperty($propertyName, $attributeValue, $attributeType);
457
                            }
458
                        }
459
                    }
460
461 3
                    break;
462
                //Ribbon
463 11
                case 'http://schemas.microsoft.com/office/2006/relationships/ui/extensibility':
464
                    $customUI = $rel['Target'];
465
                    if ($customUI !== null) {
466
                        $this->readRibbon($excel, $customUI, $zip);
467
                    }
468
469
                    break;
470 11
                case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument':
471 11
                    $dir = dirname($rel['Target']);
472 11
                    $relsWorkbook = simplexml_load_string(
473
                        //~ http://schemas.openxmlformats.org/package/2006/relationships"
474 11
                        $this->securityScan($this->getFromZipArchive($zip, "$dir/_rels/" . basename($rel['Target']) . '.rels')),
475 11
                        'SimpleXMLElement',
476 11
                        Settings::getLibXmlLoaderOptions()
477
                    );
478 11
                    $relsWorkbook->registerXPathNamespace('rel', 'http://schemas.openxmlformats.org/package/2006/relationships');
479
480 11
                    $sharedStrings = [];
481 11
                    $xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings']"));
482 11
                    $xmlStrings = simplexml_load_string(
483
                        //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
484 11
                        $this->securityScan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")),
485 11
                        'SimpleXMLElement',
486 11
                        Settings::getLibXmlLoaderOptions()
487
                    );
488 11
                    if (isset($xmlStrings, $xmlStrings->si)) {
489 10
                        foreach ($xmlStrings->si as $val) {
490 10
                            if (isset($val->t)) {
491 10
                                $sharedStrings[] = StringHelper::controlCharacterOOXML2PHP((string) $val->t);
492 3
                            } elseif (isset($val->r)) {
493 10
                                $sharedStrings[] = $this->parseRichText($val);
494
                            }
495
                        }
496
                    }
497
498 11
                    $worksheets = [];
499 11
                    $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...
500 11
                    foreach ($relsWorkbook->Relationship as $ele) {
501 11
                        switch ($ele['Type']) {
502 11
                            case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet':
503 11
                                $worksheets[(string) $ele['Id']] = $ele['Target'];
504
505 11
                                break;
506
                            // a vbaProject ? (: some macros)
507 11
                            case 'http://schemas.microsoft.com/office/2006/relationships/vbaProject':
508
                                $macros = $ele['Target'];
509
510 11
                                break;
511
                        }
512
                    }
513
514 11
                    if ($macros !== null) {
515
                        $macrosCode = $this->getFromZipArchive($zip, 'xl/vbaProject.bin'); //vbaProject.bin always in 'xl' dir and always named vbaProject.bin
516
                        if ($macrosCode !== false) {
517
                            $excel->setMacrosCode($macrosCode);
518
                            $excel->setHasMacros(true);
519
                            //short-circuit : not reading vbaProject.bin.rel to get Signature =>allways vbaProjectSignature.bin in 'xl' dir
520
                            $Certificate = $this->getFromZipArchive($zip, 'xl/vbaProjectSignature.bin');
521
                            if ($Certificate !== false) {
522
                                $excel->setMacrosCertificate($Certificate);
523
                            }
524
                        }
525
                    }
526 11
                    $styles = [];
527 11
                    $cellStyles = [];
528 11
                    $xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles']"));
529 11
                    $xmlStyles = simplexml_load_string(
530
                        //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
531 11
                        $this->securityScan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")),
532 11
                        'SimpleXMLElement',
533 11
                        Settings::getLibXmlLoaderOptions()
534
                    );
535 11
                    $numFmts = null;
536 11
                    if ($xmlStyles && $xmlStyles->numFmts[0]) {
537 6
                        $numFmts = $xmlStyles->numFmts[0];
538
                    }
539 11
                    if (isset($numFmts) && ($numFmts !== null)) {
540 6
                        $numFmts->registerXPathNamespace('sml', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
541
                    }
542 11
                    if (!$this->readDataOnly && $xmlStyles) {
543 11
                        foreach ($xmlStyles->cellXfs->xf as $xf) {
544 11
                            $numFmt = NumberFormat::FORMAT_GENERAL;
545
546 11
                            if ($xf['numFmtId']) {
547 11
                                if (isset($numFmts)) {
548 6
                                    $tmpNumFmt = self::getArrayItem($numFmts->xpath("sml:numFmt[@numFmtId=$xf[numFmtId]]"));
549
550 6
                                    if (isset($tmpNumFmt['formatCode'])) {
551 3
                                        $numFmt = (string) $tmpNumFmt['formatCode'];
552
                                    }
553
                                }
554
555
                                // We shouldn't override any of the built-in MS Excel values (values below id 164)
556
                                //  But there's a lot of naughty homebrew xlsx writers that do use "reserved" id values that aren't actually used
557
                                //  So we make allowance for them rather than lose formatting masks
558 11
                                if ((int) $xf['numFmtId'] < 164 &&
559 11
                                    NumberFormat::builtInFormatCode((int) $xf['numFmtId']) !== '') {
560 11
                                    $numFmt = NumberFormat::builtInFormatCode((int) $xf['numFmtId']);
561
                                }
562
                            }
563 11
                            $quotePrefix = false;
564 11
                            if (isset($xf['quotePrefix'])) {
565
                                $quotePrefix = (bool) $xf['quotePrefix'];
566
                            }
567
568
                            $style = (object) [
569 11
                                'numFmt' => $numFmt,
570 11
                                'font' => $xmlStyles->fonts->font[(int) ($xf['fontId'])],
571 11
                                'fill' => $xmlStyles->fills->fill[(int) ($xf['fillId'])],
572 11
                                'border' => $xmlStyles->borders->border[(int) ($xf['borderId'])],
573 11
                                'alignment' => $xf->alignment,
574 11
                                'protection' => $xf->protection,
575 11
                                'quotePrefix' => $quotePrefix,
576
                            ];
577 11
                            $styles[] = $style;
578
579
                            // add style to cellXf collection
580 11
                            $objStyle = new Style();
581 11
                            self::readStyle($objStyle, $style);
582 11
                            $excel->addCellXf($objStyle);
583
                        }
584
585 11
                        foreach ($xmlStyles->cellStyleXfs->xf as $xf) {
586 11
                            $numFmt = NumberFormat::FORMAT_GENERAL;
587 11
                            if ($numFmts && $xf['numFmtId']) {
588 6
                                $tmpNumFmt = self::getArrayItem($numFmts->xpath("sml:numFmt[@numFmtId=$xf[numFmtId]]"));
589 6
                                if (isset($tmpNumFmt['formatCode'])) {
590 1
                                    $numFmt = (string) $tmpNumFmt['formatCode'];
591 6
                                } elseif ((int) $xf['numFmtId'] < 165) {
592 6
                                    $numFmt = NumberFormat::builtInFormatCode((int) $xf['numFmtId']);
593
                                }
594
                            }
595
596
                            $cellStyle = (object) [
597 11
                                'numFmt' => $numFmt,
598 11
                                'font' => $xmlStyles->fonts->font[(int) ($xf['fontId'])],
599 11
                                'fill' => $xmlStyles->fills->fill[(int) ($xf['fillId'])],
600 11
                                'border' => $xmlStyles->borders->border[(int) ($xf['borderId'])],
601 11
                                'alignment' => $xf->alignment,
602 11
                                'protection' => $xf->protection,
603 11
                                '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...
604
                            ];
605 11
                            $cellStyles[] = $cellStyle;
606
607
                            // add style to cellStyleXf collection
608 11
                            $objStyle = new Style();
609 11
                            self::readStyle($objStyle, $cellStyle);
610 11
                            $excel->addCellStyleXf($objStyle);
611
                        }
612
                    }
613
614 11
                    $dxfs = [];
615 11
                    if (!$this->readDataOnly && $xmlStyles) {
616
                        //    Conditional Styles
617 11
                        if ($xmlStyles->dxfs) {
618 11
                            foreach ($xmlStyles->dxfs->dxf as $dxf) {
619
                                $style = new Style(false, true);
620
                                self::readStyle($style, $dxf);
621
                                $dxfs[] = $style;
622
                            }
623
                        }
624
                        //    Cell Styles
625 11
                        if ($xmlStyles->cellStyles) {
626 11
                            foreach ($xmlStyles->cellStyles->cellStyle as $cellStyle) {
627 11
                                if ((int) ($cellStyle['builtinId']) == 0) {
628 11
                                    if (isset($cellStyles[(int) ($cellStyle['xfId'])])) {
629
                                        // Set default style
630 11
                                        $style = new Style();
631 11
                                        self::readStyle($style, $cellStyles[(int) ($cellStyle['xfId'])]);
632
633
                                        // normal style, currently not using it for anything
634
                                    }
635
                                }
636
                            }
637
                        }
638
                    }
639
640 11
                    $xmlWorkbook = simplexml_load_string(
641
                        //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
642 11
                        $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")),
643 11
                        'SimpleXMLElement',
644 11
                        Settings::getLibXmlLoaderOptions()
645
                    );
646
647
                    // Set base date
648 11
                    if ($xmlWorkbook->workbookPr) {
649 10
                        Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
650 10
                        if (isset($xmlWorkbook->workbookPr['date1904'])) {
651
                            if (self::boolean((string) $xmlWorkbook->workbookPr['date1904'])) {
652
                                Date::setExcelCalendar(Date::CALENDAR_MAC_1904);
653
                            }
654
                        }
655
                    }
656
657 11
                    $sheetId = 0; // keep track of new sheet id in final workbook
658 11
                    $oldSheetId = -1; // keep track of old sheet id in final workbook
659 11
                    $countSkippedSheets = 0; // keep track of number of skipped sheets
660 11
                    $mapSheetId = []; // mapping of sheet ids from old to new
661
662 11
                    $charts = $chartDetails = [];
663
664 11
                    if ($xmlWorkbook->sheets) {
665
                        /** @var \SimpleXMLElement $eleSheet */
666 11
                        foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
667 11
                            ++$oldSheetId;
668
669
                            // Check if sheet should be skipped
670 11
                            if (isset($this->loadSheetsOnly) && !in_array((string) $eleSheet['name'], $this->loadSheetsOnly)) {
671
                                ++$countSkippedSheets;
672
                                $mapSheetId[$oldSheetId] = null;
673
674
                                continue;
675
                            }
676
677
                            // Map old sheet id in original workbook to new sheet id.
678
                            // They will differ if loadSheetsOnly() is being used
679 11
                            $mapSheetId[$oldSheetId] = $oldSheetId - $countSkippedSheets;
680
681
                            // Load sheet
682 11
                            $docSheet = $excel->createSheet();
683
                            //    Use false for $updateFormulaCellReferences to prevent adjustment of worksheet
684
                            //        references in formula cells... during the load, all formulae should be correct,
685
                            //        and we're simply bringing the worksheet name in line with the formula, not the
686
                            //        reverse
687 11
                            $docSheet->setTitle((string) $eleSheet['name'], false, false);
688 11
                            $fileWorksheet = $worksheets[(string) self::getArrayItem($eleSheet->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id')];
689 11
                            $xmlSheet = simplexml_load_string(
690
                                //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
691 11
                                $this->securityScan($this->getFromZipArchive($zip, "$dir/$fileWorksheet")),
692 11
                                'SimpleXMLElement',
693 11
                                Settings::getLibXmlLoaderOptions()
694
                            );
695
696 11
                            $sharedFormulas = [];
697
698 11
                            if (isset($eleSheet['state']) && (string) $eleSheet['state'] != '') {
699
                                $docSheet->setSheetState((string) $eleSheet['state']);
700
                            }
701
702 11
                            if (isset($xmlSheet->sheetViews, $xmlSheet->sheetViews->sheetView)) {
703 11 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...
704
                                    $docSheet->getSheetView()->setZoomScale((int) ($xmlSheet->sheetViews->sheetView['zoomScale']));
705
                                }
706 11 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...
707
                                    $docSheet->getSheetView()->setZoomScaleNormal((int) ($xmlSheet->sheetViews->sheetView['zoomScaleNormal']));
708
                                }
709 11 View Code Duplication
                                if (isset($xmlSheet->sheetViews->sheetView['view'])) {
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...
710
                                    $docSheet->getSheetView()->setView((string) $xmlSheet->sheetViews->sheetView['view']);
711
                                }
712 11 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...
713 5
                                    $docSheet->setShowGridLines(self::boolean((string) $xmlSheet->sheetViews->sheetView['showGridLines']));
714
                                }
715 11 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...
716 5
                                    $docSheet->setShowRowColHeaders(self::boolean((string) $xmlSheet->sheetViews->sheetView['showRowColHeaders']));
717
                                }
718 11 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...
719
                                    $docSheet->setRightToLeft(self::boolean((string) $xmlSheet->sheetViews->sheetView['rightToLeft']));
720
                                }
721 11
                                if (isset($xmlSheet->sheetViews->sheetView->pane)) {
722 1
                                    if (isset($xmlSheet->sheetViews->sheetView->pane['topLeftCell'])) {
723 1
                                        $docSheet->freezePane((string) $xmlSheet->sheetViews->sheetView->pane['topLeftCell']);
724
                                    } else {
725
                                        $xSplit = 0;
726
                                        $ySplit = 0;
727
728
                                        if (isset($xmlSheet->sheetViews->sheetView->pane['xSplit'])) {
729
                                            $xSplit = 1 + (int) ($xmlSheet->sheetViews->sheetView->pane['xSplit']);
730
                                        }
731
732
                                        if (isset($xmlSheet->sheetViews->sheetView->pane['ySplit'])) {
733
                                            $ySplit = 1 + (int) ($xmlSheet->sheetViews->sheetView->pane['ySplit']);
734
                                        }
735
736
                                        $docSheet->freezePaneByColumnAndRow($xSplit, $ySplit);
737
                                    }
738
                                }
739
740 11
                                if (isset($xmlSheet->sheetViews->sheetView->selection)) {
741 9
                                    if (isset($xmlSheet->sheetViews->sheetView->selection['sqref'])) {
742 9
                                        $sqref = (string) $xmlSheet->sheetViews->sheetView->selection['sqref'];
743 9
                                        $sqref = explode(' ', $sqref);
744 9
                                        $sqref = $sqref[0];
745 9
                                        $docSheet->setSelectedCells($sqref);
746
                                    }
747
                                }
748
                            }
749
750 11
                            if (isset($xmlSheet->sheetPr, $xmlSheet->sheetPr->tabColor)) {
751 2
                                if (isset($xmlSheet->sheetPr->tabColor['rgb'])) {
752 2
                                    $docSheet->getTabColor()->setARGB((string) $xmlSheet->sheetPr->tabColor['rgb']);
753
                                }
754
                            }
755 11
                            if (isset($xmlSheet->sheetPr, $xmlSheet->sheetPr['codeName'])) {
756
                                $docSheet->setCodeName((string) $xmlSheet->sheetPr['codeName'], false);
757
                            }
758 11
                            if (isset($xmlSheet->sheetPr, $xmlSheet->sheetPr->outlinePr)) {
759 5 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...
760 5
                                    !self::boolean((string) $xmlSheet->sheetPr->outlinePr['summaryRight'])) {
761
                                    $docSheet->setShowSummaryRight(false);
762
                                } else {
763 5
                                    $docSheet->setShowSummaryRight(true);
764
                                }
765
766 5 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...
767 5
                                    !self::boolean((string) $xmlSheet->sheetPr->outlinePr['summaryBelow'])) {
768
                                    $docSheet->setShowSummaryBelow(false);
769
                                } else {
770 5
                                    $docSheet->setShowSummaryBelow(true);
771
                                }
772
                            }
773
774 11
                            if (isset($xmlSheet->sheetPr, $xmlSheet->sheetPr->pageSetUpPr)) {
775
                                if (isset($xmlSheet->sheetPr->pageSetUpPr['fitToPage']) &&
776
                                    !self::boolean((string) $xmlSheet->sheetPr->pageSetUpPr['fitToPage'])) {
777
                                    $docSheet->getPageSetup()->setFitToPage(false);
778
                                } else {
779
                                    $docSheet->getPageSetup()->setFitToPage(true);
780
                                }
781
                            }
782
783 11
                            if (isset($xmlSheet->sheetFormatPr)) {
784 11
                                if (isset($xmlSheet->sheetFormatPr['customHeight']) &&
785 11
                                    self::boolean((string) $xmlSheet->sheetFormatPr['customHeight']) &&
786 11
                                    isset($xmlSheet->sheetFormatPr['defaultRowHeight'])) {
787 1
                                    $docSheet->getDefaultRowDimension()->setRowHeight((float) $xmlSheet->sheetFormatPr['defaultRowHeight']);
788
                                }
789 11
                                if (isset($xmlSheet->sheetFormatPr['defaultColWidth'])) {
790 1
                                    $docSheet->getDefaultColumnDimension()->setWidth((float) $xmlSheet->sheetFormatPr['defaultColWidth']);
791
                                }
792 11
                                if (isset($xmlSheet->sheetFormatPr['zeroHeight']) &&
793 11
                                    ((string) $xmlSheet->sheetFormatPr['zeroHeight'] == '1')) {
794
                                    $docSheet->getDefaultRowDimension()->setZeroHeight(true);
795
                                }
796
                            }
797
798 11
                            if (isset($xmlSheet->cols) && !$this->readDataOnly) {
799 6
                                foreach ($xmlSheet->cols->col as $col) {
800 6
                                    for ($i = (int) ($col['min']) - 1; $i < (int) ($col['max']); ++$i) {
801 6
                                        if ($col['style'] && !$this->readDataOnly) {
802 3
                                            $docSheet->getColumnDimension(Cell::stringFromColumnIndex($i))->setXfIndex((int) ($col['style']));
803
                                        }
804 6
                                        if (self::boolean($col['hidden'])) {
805 1
                                            $docSheet->getColumnDimension(Cell::stringFromColumnIndex($i))->setVisible(false);
806
                                        }
807 6
                                        if (self::boolean($col['collapsed'])) {
808 1
                                            $docSheet->getColumnDimension(Cell::stringFromColumnIndex($i))->setCollapsed(true);
809
                                        }
810 6
                                        if ($col['outlineLevel'] > 0) {
811 1
                                            $docSheet->getColumnDimension(Cell::stringFromColumnIndex($i))->setOutlineLevel((int) ($col['outlineLevel']));
812
                                        }
813 6
                                        $docSheet->getColumnDimension(Cell::stringFromColumnIndex($i))->setWidth((float) ($col['width']));
814
815 6
                                        if ((int) ($col['max']) == 16384) {
816
                                            break;
817
                                        }
818
                                    }
819
                                }
820
                            }
821
822 11
                            if (isset($xmlSheet->printOptions) && !$this->readDataOnly) {
823 5
                                if (self::boolean((string) $xmlSheet->printOptions['gridLinesSet'])) {
824 5
                                    $docSheet->setShowGridlines(true);
825
                                }
826 5
                                if (self::boolean((string) $xmlSheet->printOptions['gridLines'])) {
827
                                    $docSheet->setPrintGridlines(true);
828
                                }
829 5
                                if (self::boolean((string) $xmlSheet->printOptions['horizontalCentered'])) {
830
                                    $docSheet->getPageSetup()->setHorizontalCentered(true);
831
                                }
832 5
                                if (self::boolean((string) $xmlSheet->printOptions['verticalCentered'])) {
833
                                    $docSheet->getPageSetup()->setVerticalCentered(true);
834
                                }
835
                            }
836
837 11
                            if ($xmlSheet && $xmlSheet->sheetData && $xmlSheet->sheetData->row) {
838 11
                                $cIndex = 1; // Cell Start from 1
839 11
                                foreach ($xmlSheet->sheetData->row as $row) {
840 11
                                    if ($row['ht'] && !$this->readDataOnly) {
841 2
                                        $docSheet->getRowDimension((int) ($row['r']))->setRowHeight((float) ($row['ht']));
842
                                    }
843 11
                                    if (self::boolean($row['hidden']) && !$this->readDataOnly) {
844
                                        $docSheet->getRowDimension((int) ($row['r']))->setVisible(false);
845
                                    }
846 11
                                    if (self::boolean($row['collapsed'])) {
847
                                        $docSheet->getRowDimension((int) ($row['r']))->setCollapsed(true);
848
                                    }
849 11
                                    if ($row['outlineLevel'] > 0) {
850
                                        $docSheet->getRowDimension((int) ($row['r']))->setOutlineLevel((int) ($row['outlineLevel']));
851
                                    }
852 11
                                    if ($row['s'] && !$this->readDataOnly) {
853
                                        $docSheet->getRowDimension((int) ($row['r']))->setXfIndex((int) ($row['s']));
854
                                    }
855
856 11
                                    $rowIndex = 0; // Start form zero because Cell::stringFromColumnIndex start from A default, actually is 1
857 11
                                    foreach ($row->c as $c) {
858 11
                                        $r = (string) $c['r'];
859 11
                                        if ($r == '') {
860 1
                                            $r = Cell::stringFromColumnIndex($rowIndex) . $cIndex;
861
                                        }
862 11
                                        $cellDataType = (string) $c['t'];
863 11
                                        $value = null;
864 11
                                        $calculatedValue = null;
865
866
                                        // Read cell?
867 11
                                        if ($this->getReadFilter() !== null) {
868 11
                                            $coordinates = Cell::coordinateFromString($r);
869
870 11
                                            if (!$this->getReadFilter()->readCell($coordinates[0], $coordinates[1], $docSheet->getTitle())) {
871 1
                                                continue;
872
                                            }
873
                                        }
874
875
                                        // Read cell!
876
                                        switch ($cellDataType) {
877 11
                                            case 's':
878 10
                                                if ((string) $c->v != '') {
879 10
                                                    $value = $sharedStrings[(int) ($c->v)];
880
881 10
                                                    if ($value instanceof RichText) {
882 10
                                                        $value = clone $value;
883
                                                    }
884
                                                } else {
885
                                                    $value = '';
886
                                                }
887
888 10
                                                break;
889 7
                                            case 'b':
890 1
                                                if (!isset($c->f)) {
891 1
                                                    $value = self::castToBoolean($c);
892
                                                } else {
893
                                                    // Formula
894
                                                    $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToBoolean');
895
                                                    if (isset($c->f['t'])) {
896
                                                        $att = $c->f;
897
                                                        $docSheet->getCell($r)->setFormulaAttributes($att);
898
                                                    }
899
                                                }
900
901 1
                                                break;
902 6 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...
903 2
                                                if (isset($c->f)) {
904
                                                    $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToError');
905
                                                } else {
906 2
                                                    $value = $this->parseRichText($c->is);
907
                                                }
908
909 2
                                                break;
910 6 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...
911
                                                if (!isset($c->f)) {
912
                                                    $value = self::castToError($c);
913
                                                } else {
914
                                                    // Formula
915
                                                    $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToError');
916
                                                }
917
918
                                                break;
919
                                            default:
920 6
                                                if (!isset($c->f)) {
921 6
                                                    $value = self::castToString($c);
922
                                                } else {
923
                                                    // Formula
924 3
                                                    $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToString');
925
                                                }
926
927 6
                                                break;
928
                                        }
929
930
                                        // Check for numeric values
931 11
                                        if (is_numeric($value) && $cellDataType != 's') {
932 6
                                            if ($value == (int) $value) {
933 6
                                                $value = (int) $value;
934
                                            } elseif ($value == (float) $value) {
935
                                                $value = (float) $value;
936
                                            } elseif ($value == (float) $value) {
937
                                                $value = (float) $value;
938
                                            }
939
                                        }
940
941
                                        // Rich text?
942 11
                                        if ($value instanceof RichText && $this->readDataOnly) {
943
                                            $value = $value->getPlainText();
944
                                        }
945
946 11
                                        $cell = $docSheet->getCell($r);
947
                                        // Assign value
948 11
                                        if ($cellDataType != '') {
949 10
                                            $cell->setValueExplicit($value, $cellDataType);
950
                                        } else {
951 6
                                            $cell->setValue($value);
952
                                        }
953 11
                                        if ($calculatedValue !== null) {
954 3
                                            $cell->setCalculatedValue($calculatedValue);
955
                                        }
956
957
                                        // Style information?
958 11
                                        if ($c['s'] && !$this->readDataOnly) {
959
                                            // no style index means 0, it seems
960 6
                                            $cell->setXfIndex(isset($styles[(int) ($c['s'])]) ?
961 6
                                                (int) ($c['s']) : 0);
962
                                        }
963 11
                                        $rowIndex += 1;
964
                                    }
965 11
                                    $cIndex += 1;
966
                                }
967
                            }
968
969 11
                            $conditionals = [];
970 11
                            if (!$this->readDataOnly && $xmlSheet && $xmlSheet->conditionalFormatting) {
971
                                foreach ($xmlSheet->conditionalFormatting as $conditional) {
972
                                    foreach ($conditional->cfRule as $cfRule) {
973
                                        if (((string) $cfRule['type'] == Style\Conditional::CONDITION_NONE || (string) $cfRule['type'] == Style\Conditional::CONDITION_CELLIS || (string) $cfRule['type'] == Style\Conditional::CONDITION_CONTAINSTEXT || (string) $cfRule['type'] == Style\Conditional::CONDITION_EXPRESSION) && isset($dxfs[(int) ($cfRule['dxfId'])])) {
974
                                            $conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule;
975
                                        }
976
                                    }
977
                                }
978
979
                                foreach ($conditionals as $ref => $cfRules) {
980
                                    ksort($cfRules);
981
                                    $conditionalStyles = [];
982
                                    foreach ($cfRules as $cfRule) {
983
                                        $objConditional = new Style\Conditional();
984
                                        $objConditional->setConditionType((string) $cfRule['type']);
985
                                        $objConditional->setOperatorType((string) $cfRule['operator']);
986
987
                                        if ((string) $cfRule['text'] != '') {
988
                                            $objConditional->setText((string) $cfRule['text']);
989
                                        }
990
991
                                        if (count($cfRule->formula) > 1) {
992
                                            foreach ($cfRule->formula as $formula) {
993
                                                $objConditional->addCondition((string) $formula);
994
                                            }
995
                                        } else {
996
                                            $objConditional->addCondition((string) $cfRule->formula);
997
                                        }
998
                                        $objConditional->setStyle(clone $dxfs[(int) ($cfRule['dxfId'])]);
999
                                        $conditionalStyles[] = $objConditional;
1000
                                    }
1001
1002
                                    // Extract all cell references in $ref
1003
                                    $cellBlocks = explode(' ', str_replace('$', '', strtoupper($ref)));
1004
                                    foreach ($cellBlocks as $cellBlock) {
1005
                                        $docSheet->getStyle($cellBlock)->setConditionalStyles($conditionalStyles);
1006
                                    }
1007
                                }
1008
                            }
1009
1010 11
                            $aKeys = ['sheet', 'objects', 'scenarios', 'formatCells', 'formatColumns', 'formatRows', 'insertColumns', 'insertRows', 'insertHyperlinks', 'deleteColumns', 'deleteRows', 'selectLockedCells', 'sort', 'autoFilter', 'pivotTables', 'selectUnlockedCells'];
1011 11
                            if (!$this->readDataOnly && $xmlSheet && $xmlSheet->sheetProtection) {
1012 7
                                foreach ($aKeys as $key) {
1013 7
                                    $method = 'set' . ucfirst($key);
1014 7
                                    $docSheet->getProtection()->$method(self::boolean((string) $xmlSheet->sheetProtection[$key]));
1015
                                }
1016
                            }
1017
1018 11
                            if (!$this->readDataOnly && $xmlSheet && $xmlSheet->sheetProtection) {
1019 7
                                $docSheet->getProtection()->setPassword((string) $xmlSheet->sheetProtection['password'], true);
1020 7
                                if ($xmlSheet->protectedRanges->protectedRange) {
1021 2
                                    foreach ($xmlSheet->protectedRanges->protectedRange as $protectedRange) {
1022 2
                                        $docSheet->protectCells((string) $protectedRange['sqref'], (string) $protectedRange['password'], true);
1023
                                    }
1024
                                }
1025
                            }
1026
1027 11
                            if ($xmlSheet && $xmlSheet->autoFilter && !$this->readDataOnly) {
1028
                                $autoFilterRange = (string) $xmlSheet->autoFilter['ref'];
1029
                                if (strpos($autoFilterRange, ':') !== false) {
1030
                                    $autoFilter = $docSheet->getAutoFilter();
1031
                                    $autoFilter->setRange($autoFilterRange);
1032
1033
                                    foreach ($xmlSheet->autoFilter->filterColumn as $filterColumn) {
1034
                                        $column = $autoFilter->getColumnByOffset((int) $filterColumn['colId']);
1035
                                        //    Check for standard filters
1036
                                        if ($filterColumn->filters) {
1037
                                            $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER);
1038
                                            $filters = $filterColumn->filters;
1039
                                            if ((isset($filters['blank'])) && ($filters['blank'] == 1)) {
1040
                                                //    Operator is undefined, but always treated as EQUAL
1041
                                                $column->createRule()->setRule(null, '')->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_FILTER);
1042
                                            }
1043
                                            //    Standard filters are always an OR join, so no join rule needs to be set
1044
                                            //    Entries can be either filter elements
1045 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...
1046
                                                //    Operator is undefined, but always treated as EQUAL
1047
                                                $column->createRule()->setRule(null, (string) $filterRule['val'])->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_FILTER);
1048
                                            }
1049
                                            //    Or Date Group elements
1050
                                            foreach ($filters->dateGroupItem as $dateGroupItem) {
1051
                                                $column->createRule()->setRule(
1052
                                                    //    Operator is undefined, but always treated as EQUAL
1053
                                                    null,
1054
                                                    [
1055
                                                        'year' => (string) $dateGroupItem['year'],
1056
                                                        'month' => (string) $dateGroupItem['month'],
1057
                                                        'day' => (string) $dateGroupItem['day'],
1058
                                                        'hour' => (string) $dateGroupItem['hour'],
1059
                                                        'minute' => (string) $dateGroupItem['minute'],
1060
                                                        'second' => (string) $dateGroupItem['second'],
1061
                                                    ],
1062
                                                    (string) $dateGroupItem['dateTimeGrouping']
1063
                                                )
1064
                                                ->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP);
1065
                                            }
1066
                                        }
1067
                                        //    Check for custom filters
1068
                                        if ($filterColumn->customFilters) {
1069
                                            $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_CUSTOMFILTER);
1070
                                            $customFilters = $filterColumn->customFilters;
1071
                                            //    Custom filters can an AND or an OR join;
1072
                                            //        and there should only ever be one or two entries
1073
                                            if ((isset($customFilters['and'])) && ($customFilters['and'] == 1)) {
1074
                                                $column->setJoin(Column::AUTOFILTER_COLUMN_JOIN_AND);
1075
                                            }
1076 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...
1077
                                                $column->createRule()->setRule(
1078
                                                    (string) $filterRule['operator'],
1079
                                                    (string) $filterRule['val']
1080
                                                )
1081
                                                ->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER);
1082
                                            }
1083
                                        }
1084
                                        //    Check for dynamic filters
1085
                                        if ($filterColumn->dynamicFilter) {
1086
                                            $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER);
1087
                                            //    We should only ever have one dynamic filter
1088
                                            foreach ($filterColumn->dynamicFilter as $filterRule) {
1089
                                                $column->createRule()->setRule(
1090
                                                    //    Operator is undefined, but always treated as EQUAL
1091
                                                    null,
1092
                                                    (string) $filterRule['val'],
1093
                                                    (string) $filterRule['type']
1094
                                                )
1095
                                                ->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER);
1096
                                                if (isset($filterRule['val'])) {
1097
                                                    $column->setAttribute('val', (string) $filterRule['val']);
1098
                                                }
1099
                                                if (isset($filterRule['maxVal'])) {
1100
                                                    $column->setAttribute('maxVal', (string) $filterRule['maxVal']);
1101
                                                }
1102
                                            }
1103
                                        }
1104
                                        //    Check for dynamic filters
1105
                                        if ($filterColumn->top10) {
1106
                                            $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_TOPTENFILTER);
1107
                                            //    We should only ever have one top10 filter
1108
                                            foreach ($filterColumn->top10 as $filterRule) {
1109
                                                $column->createRule()->setRule(
1110
                                                    (((isset($filterRule['percent'])) && ($filterRule['percent'] == 1))
1111
                                                        ? Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT
1112
                                                        : Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE
1113
                                                    ),
1114
                                                    (string) $filterRule['val'],
1115
                                                    (((isset($filterRule['top'])) && ($filterRule['top'] == 1))
1116
                                                        ? Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP
1117
                                                        : Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM
1118
                                                    )
1119
                                                )
1120
                                                ->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_TOPTENFILTER);
1121
                                            }
1122
                                        }
1123
                                    }
1124
                                }
1125
                            }
1126
1127 11
                            if ($xmlSheet && $xmlSheet->mergeCells && $xmlSheet->mergeCells->mergeCell && !$this->readDataOnly) {
1128 4
                                foreach ($xmlSheet->mergeCells->mergeCell as $mergeCell) {
1129 4
                                    $mergeRef = (string) $mergeCell['ref'];
1130 4
                                    if (strpos($mergeRef, ':') !== false) {
1131 4
                                        $docSheet->mergeCells((string) $mergeCell['ref']);
1132
                                    }
1133
                                }
1134
                            }
1135
1136 11
                            if ($xmlSheet && $xmlSheet->pageMargins && !$this->readDataOnly) {
1137 10
                                $docPageMargins = $docSheet->getPageMargins();
1138 10
                                $docPageMargins->setLeft((float) ($xmlSheet->pageMargins['left']));
1139 10
                                $docPageMargins->setRight((float) ($xmlSheet->pageMargins['right']));
1140 10
                                $docPageMargins->setTop((float) ($xmlSheet->pageMargins['top']));
1141 10
                                $docPageMargins->setBottom((float) ($xmlSheet->pageMargins['bottom']));
1142 10
                                $docPageMargins->setHeader((float) ($xmlSheet->pageMargins['header']));
1143 10
                                $docPageMargins->setFooter((float) ($xmlSheet->pageMargins['footer']));
1144
                            }
1145
1146 11
                            if ($xmlSheet && $xmlSheet->pageSetup && !$this->readDataOnly) {
1147 10
                                $docPageSetup = $docSheet->getPageSetup();
1148
1149 10
                                if (isset($xmlSheet->pageSetup['orientation'])) {
1150 10
                                    $docPageSetup->setOrientation((string) $xmlSheet->pageSetup['orientation']);
1151
                                }
1152 10
                                if (isset($xmlSheet->pageSetup['paperSize'])) {
1153 8
                                    $docPageSetup->setPaperSize((int) ($xmlSheet->pageSetup['paperSize']));
1154
                                }
1155 10
                                if (isset($xmlSheet->pageSetup['scale'])) {
1156 5
                                    $docPageSetup->setScale((int) ($xmlSheet->pageSetup['scale']), false);
1157
                                }
1158 10 View Code Duplication
                                if (isset($xmlSheet->pageSetup['fitToHeight']) && (int) ($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...
1159 5
                                    $docPageSetup->setFitToHeight((int) ($xmlSheet->pageSetup['fitToHeight']), false);
1160
                                }
1161 10 View Code Duplication
                                if (isset($xmlSheet->pageSetup['fitToWidth']) && (int) ($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...
1162 5
                                    $docPageSetup->setFitToWidth((int) ($xmlSheet->pageSetup['fitToWidth']), false);
1163
                                }
1164 10
                                if (isset($xmlSheet->pageSetup['firstPageNumber'], $xmlSheet->pageSetup['useFirstPageNumber']) &&
1165 10
                                    self::boolean((string) $xmlSheet->pageSetup['useFirstPageNumber'])) {
1166
                                    $docPageSetup->setFirstPageNumber((int) ($xmlSheet->pageSetup['firstPageNumber']));
1167
                                }
1168
                            }
1169
1170 11
                            if ($xmlSheet && $xmlSheet->headerFooter && !$this->readDataOnly) {
1171 7
                                $docHeaderFooter = $docSheet->getHeaderFooter();
1172
1173 7 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...
1174 7
                                    self::boolean((string) $xmlSheet->headerFooter['differentOddEven'])) {
1175
                                    $docHeaderFooter->setDifferentOddEven(true);
1176
                                } else {
1177 7
                                    $docHeaderFooter->setDifferentOddEven(false);
1178
                                }
1179 7 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...
1180 7
                                    self::boolean((string) $xmlSheet->headerFooter['differentFirst'])) {
1181
                                    $docHeaderFooter->setDifferentFirst(true);
1182
                                } else {
1183 7
                                    $docHeaderFooter->setDifferentFirst(false);
1184
                                }
1185 7 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...
1186 7
                                    !self::boolean((string) $xmlSheet->headerFooter['scaleWithDoc'])) {
1187
                                    $docHeaderFooter->setScaleWithDocument(false);
1188
                                } else {
1189 7
                                    $docHeaderFooter->setScaleWithDocument(true);
1190
                                }
1191 7 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...
1192 7
                                    !self::boolean((string) $xmlSheet->headerFooter['alignWithMargins'])) {
1193 3
                                    $docHeaderFooter->setAlignWithMargins(false);
1194
                                } else {
1195 4
                                    $docHeaderFooter->setAlignWithMargins(true);
1196
                                }
1197
1198 7
                                $docHeaderFooter->setOddHeader((string) $xmlSheet->headerFooter->oddHeader);
1199 7
                                $docHeaderFooter->setOddFooter((string) $xmlSheet->headerFooter->oddFooter);
1200 7
                                $docHeaderFooter->setEvenHeader((string) $xmlSheet->headerFooter->evenHeader);
1201 7
                                $docHeaderFooter->setEvenFooter((string) $xmlSheet->headerFooter->evenFooter);
1202 7
                                $docHeaderFooter->setFirstHeader((string) $xmlSheet->headerFooter->firstHeader);
1203 7
                                $docHeaderFooter->setFirstFooter((string) $xmlSheet->headerFooter->firstFooter);
1204
                            }
1205
1206 11
                            if ($xmlSheet && $xmlSheet->rowBreaks && $xmlSheet->rowBreaks->brk && !$this->readDataOnly) {
1207
                                foreach ($xmlSheet->rowBreaks->brk as $brk) {
1208
                                    if ($brk['man']) {
1209
                                        $docSheet->setBreak("A$brk[id]", Worksheet::BREAK_ROW);
1210
                                    }
1211
                                }
1212
                            }
1213 11
                            if ($xmlSheet && $xmlSheet->colBreaks && $xmlSheet->colBreaks->brk && !$this->readDataOnly) {
1214
                                foreach ($xmlSheet->colBreaks->brk as $brk) {
1215
                                    if ($brk['man']) {
1216
                                        $docSheet->setBreak(Cell::stringFromColumnIndex((string) $brk['id']) . '1', Worksheet::BREAK_COLUMN);
1217
                                    }
1218
                                }
1219
                            }
1220
1221 11
                            if ($xmlSheet && $xmlSheet->dataValidations && !$this->readDataOnly) {
1222
                                foreach ($xmlSheet->dataValidations->dataValidation as $dataValidation) {
1223
                                    // Uppercase coordinate
1224
                                    $range = strtoupper($dataValidation['sqref']);
1225
                                    $rangeSet = explode(' ', $range);
1226
                                    foreach ($rangeSet as $range) {
1227
                                        $stRange = $docSheet->shrinkRangeToFit($range);
1228
1229
                                        // Extract all cell references in $range
1230
                                        foreach (Cell::extractAllCellReferencesInRange($stRange) as $reference) {
1231
                                            // Create validation
1232
                                            $docValidation = $docSheet->getCell($reference)->getDataValidation();
1233
                                            $docValidation->setType((string) $dataValidation['type']);
1234
                                            $docValidation->setErrorStyle((string) $dataValidation['errorStyle']);
1235
                                            $docValidation->setOperator((string) $dataValidation['operator']);
1236
                                            $docValidation->setAllowBlank($dataValidation['allowBlank'] != 0);
1237
                                            $docValidation->setShowDropDown($dataValidation['showDropDown'] == 0);
1238
                                            $docValidation->setShowInputMessage($dataValidation['showInputMessage'] != 0);
1239
                                            $docValidation->setShowErrorMessage($dataValidation['showErrorMessage'] != 0);
1240
                                            $docValidation->setErrorTitle((string) $dataValidation['errorTitle']);
1241
                                            $docValidation->setError((string) $dataValidation['error']);
1242
                                            $docValidation->setPromptTitle((string) $dataValidation['promptTitle']);
1243
                                            $docValidation->setPrompt((string) $dataValidation['prompt']);
1244
                                            $docValidation->setFormula1((string) $dataValidation->formula1);
1245
                                            $docValidation->setFormula2((string) $dataValidation->formula2);
1246
                                        }
1247
                                    }
1248
                                }
1249
                            }
1250
1251
                            // Add hyperlinks
1252 11
                            $hyperlinks = [];
1253 11
                            if (!$this->readDataOnly) {
1254
                                // Locate hyperlink relations
1255 11
                                if ($zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
1256 10
                                    $relsWorksheet = simplexml_load_string(
1257
                                        //~ http://schemas.openxmlformats.org/package/2006/relationships"
1258 10
                                        $this->securityScan(
1259 10
                                            $this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
1260
                                        ),
1261 10
                                        'SimpleXMLElement',
1262 10
                                        Settings::getLibXmlLoaderOptions()
1263
                                    );
1264 10
                                    foreach ($relsWorksheet->Relationship as $ele) {
1265 7
                                        if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink') {
1266 7
                                            $hyperlinks[(string) $ele['Id']] = (string) $ele['Target'];
1267
                                        }
1268
                                    }
1269
                                }
1270
1271
                                // Loop through hyperlinks
1272 11
                                if ($xmlSheet && $xmlSheet->hyperlinks) {
1273
                                    /** @var \SimpleXMLElement $hyperlink */
1274 2
                                    foreach ($xmlSheet->hyperlinks->hyperlink as $hyperlink) {
1275
                                        // Link url
1276 2
                                        $linkRel = $hyperlink->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships');
1277
1278 2
                                        foreach (Cell::extractAllCellReferencesInRange($hyperlink['ref']) as $cellReference) {
1279 2
                                            $cell = $docSheet->getCell($cellReference);
1280 2
                                            if (isset($linkRel['id'])) {
1281 2
                                                $hyperlinkUrl = $hyperlinks[(string) $linkRel['id']];
1282 2
                                                if (isset($hyperlink['location'])) {
1283
                                                    $hyperlinkUrl .= '#' . (string) $hyperlink['location'];
1284
                                                }
1285 2
                                                $cell->getHyperlink()->setUrl($hyperlinkUrl);
1286 2
                                            } elseif (isset($hyperlink['location'])) {
1287 2
                                                $cell->getHyperlink()->setUrl('sheet://' . (string) $hyperlink['location']);
1288
                                            }
1289
1290
                                            // Tooltip
1291 2
                                            if (isset($hyperlink['tooltip'])) {
1292 2
                                                $cell->getHyperlink()->setTooltip((string) $hyperlink['tooltip']);
1293
                                            }
1294
                                        }
1295
                                    }
1296
                                }
1297
                            }
1298
1299
                            // Add comments
1300 11
                            $comments = [];
1301 11
                            $vmlComments = [];
1302 11
                            if (!$this->readDataOnly) {
1303
                                // Locate comment relations
1304 11
                                if ($zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
1305 10
                                    $relsWorksheet = simplexml_load_string(
1306
                                        //~ http://schemas.openxmlformats.org/package/2006/relationships"
1307 10
                                        $this->securityScan(
1308 10
                                            $this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
1309
                                        ),
1310 10
                                        'SimpleXMLElement',
1311 10
                                        Settings::getLibXmlLoaderOptions()
1312
                                    );
1313 10
                                    foreach ($relsWorksheet->Relationship as $ele) {
1314 7
                                        if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments') {
1315 2
                                            $comments[(string) $ele['Id']] = (string) $ele['Target'];
1316
                                        }
1317 7
                                        if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing') {
1318 7
                                            $vmlComments[(string) $ele['Id']] = (string) $ele['Target'];
1319
                                        }
1320
                                    }
1321
                                }
1322
1323
                                // Loop through comments
1324 11
                                foreach ($comments as $relName => $relPath) {
1325
                                    // Load comments file
1326 2
                                    $relPath = File::realpath(dirname("$dir/$fileWorksheet") . '/' . $relPath);
1327 2
                                    $commentsFile = simplexml_load_string(
1328 2
                                        $this->securityScan($this->getFromZipArchive($zip, $relPath)),
1329 2
                                        'SimpleXMLElement',
1330 2
                                        Settings::getLibXmlLoaderOptions()
1331
                                    );
1332
1333
                                    // Utility variables
1334 2
                                    $authors = [];
1335
1336
                                    // Loop through authors
1337 2
                                    foreach ($commentsFile->authors->author as $author) {
1338 2
                                        $authors[] = (string) $author;
1339
                                    }
1340
1341
                                    // Loop through contents
1342 2
                                    foreach ($commentsFile->commentList->comment as $comment) {
1343 2
                                        if (!empty($comment['authorId'])) {
1344
                                            $docSheet->getComment((string) $comment['ref'])->setAuthor($authors[(string) $comment['authorId']]);
1345
                                        }
1346 2
                                        $docSheet->getComment((string) $comment['ref'])->setText($this->parseRichText($comment->text));
1347
                                    }
1348
                                }
1349
1350
                                // Loop through VML comments
1351 11
                                foreach ($vmlComments as $relName => $relPath) {
1352
                                    // Load VML comments file
1353 2
                                    $relPath = File::realpath(dirname("$dir/$fileWorksheet") . '/' . $relPath);
1354 2
                                    $vmlCommentsFile = simplexml_load_string(
1355 2
                                        $this->securityScan($this->getFromZipArchive($zip, $relPath)),
1356 2
                                        'SimpleXMLElement',
1357 2
                                        Settings::getLibXmlLoaderOptions()
1358
                                    );
1359 2
                                    $vmlCommentsFile->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
1360
1361 2
                                    $shapes = $vmlCommentsFile->xpath('//v:shape');
1362 2
                                    foreach ($shapes as $shape) {
1363 2
                                        $shape->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
1364
1365 2
                                        if (isset($shape['style'])) {
1366 2
                                            $style = (string) $shape['style'];
1367 2
                                            $fillColor = strtoupper(substr((string) $shape['fillcolor'], 1));
1368 2
                                            $column = null;
1369 2
                                            $row = null;
1370
1371 2
                                            $clientData = $shape->xpath('.//x:ClientData');
1372 2
                                            if (is_array($clientData) && !empty($clientData)) {
1373 2
                                                $clientData = $clientData[0];
1374
1375 2
                                                if (isset($clientData['ObjectType']) && (string) $clientData['ObjectType'] == 'Note') {
1376 2
                                                    $temp = $clientData->xpath('.//x:Row');
1377 2
                                                    if (is_array($temp)) {
1378 2
                                                        $row = $temp[0];
1379
                                                    }
1380
1381 2
                                                    $temp = $clientData->xpath('.//x:Column');
1382 2
                                                    if (is_array($temp)) {
1383 2
                                                        $column = $temp[0];
1384
                                                    }
1385
                                                }
1386
                                            }
1387
1388 2
                                            if (($column !== null) && ($row !== null)) {
1389
                                                // Set comment properties
1390 2
                                                $comment = $docSheet->getCommentByColumnAndRow((string) $column, $row + 1);
1391 2
                                                $comment->getFillColor()->setRGB($fillColor);
1392
1393
                                                // Parse style
1394 2
                                                $styleArray = explode(';', str_replace(' ', '', $style));
1395 2
                                                foreach ($styleArray as $stylePair) {
1396 2
                                                    $stylePair = explode(':', $stylePair);
1397
1398 2
                                                    if ($stylePair[0] == 'margin-left') {
1399 2
                                                        $comment->setMarginLeft($stylePair[1]);
1400
                                                    }
1401 2
                                                    if ($stylePair[0] == 'margin-top') {
1402 2
                                                        $comment->setMarginTop($stylePair[1]);
1403
                                                    }
1404 2
                                                    if ($stylePair[0] == 'width') {
1405 2
                                                        $comment->setWidth($stylePair[1]);
1406
                                                    }
1407 2
                                                    if ($stylePair[0] == 'height') {
1408 2
                                                        $comment->setHeight($stylePair[1]);
1409
                                                    }
1410 2
                                                    if ($stylePair[0] == 'visibility') {
1411 2
                                                        $comment->setVisible($stylePair[1] == 'visible');
1412
                                                    }
1413
                                                }
1414
                                            }
1415
                                        }
1416
                                    }
1417
                                }
1418
1419
                                // Header/footer images
1420 11
                                if ($xmlSheet && $xmlSheet->legacyDrawingHF && !$this->readDataOnly) {
1421
                                    if ($zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
1422
                                        $relsWorksheet = simplexml_load_string(
1423
                                            //~ http://schemas.openxmlformats.org/package/2006/relationships"
1424
                                            $this->securityScan(
1425
                                                $this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
1426
                                            ),
1427
                                            'SimpleXMLElement',
1428
                                            Settings::getLibXmlLoaderOptions()
1429
                                        );
1430
                                        $vmlRelationship = '';
1431
1432
                                        foreach ($relsWorksheet->Relationship as $ele) {
1433
                                            if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing') {
1434
                                                $vmlRelationship = self::dirAdd("$dir/$fileWorksheet", $ele['Target']);
1435
                                            }
1436
                                        }
1437
1438
                                        if ($vmlRelationship != '') {
1439
                                            // Fetch linked images
1440
                                            $relsVML = simplexml_load_string(
1441
                                                //~ http://schemas.openxmlformats.org/package/2006/relationships"
1442
                                                $this->securityScan(
1443
                                                    $this->getFromZipArchive($zip, dirname($vmlRelationship) . '/_rels/' . basename($vmlRelationship) . '.rels')
1444
                                                ),
1445
                                                'SimpleXMLElement',
1446
                                                Settings::getLibXmlLoaderOptions()
1447
                                            );
1448
                                            $drawings = [];
1449 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...
1450
                                                if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') {
1451
                                                    $drawings[(string) $ele['Id']] = self::dirAdd($vmlRelationship, $ele['Target']);
1452
                                                }
1453
                                            }
1454
1455
                                            // Fetch VML document
1456
                                            $vmlDrawing = simplexml_load_string(
1457
                                                $this->securityScan($this->getFromZipArchive($zip, $vmlRelationship)),
1458
                                                'SimpleXMLElement',
1459
                                                Settings::getLibXmlLoaderOptions()
1460
                                            );
1461
                                            $vmlDrawing->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
1462
1463
                                            $hfImages = [];
1464
1465
                                            $shapes = $vmlDrawing->xpath('//v:shape');
1466
                                            foreach ($shapes as $idx => $shape) {
1467
                                                $shape->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
1468
                                                $imageData = $shape->xpath('//v:imagedata');
1469
1470
                                                if (!$imageData) {
1471
                                                    continue;
1472
                                                }
1473
1474
                                                $imageData = $imageData[$idx];
1475
1476
                                                $imageData = $imageData->attributes('urn:schemas-microsoft-com:office:office');
1477
                                                $style = self::toCSSArray((string) $shape['style']);
1478
1479
                                                $hfImages[(string) $shape['id']] = new Worksheet\HeaderFooterDrawing();
1480
                                                if (isset($imageData['title'])) {
1481
                                                    $hfImages[(string) $shape['id']]->setName((string) $imageData['title']);
1482
                                                }
1483
1484
                                                $hfImages[(string) $shape['id']]->setPath('zip://' . File::realpath($pFilename) . '#' . $drawings[(string) $imageData['relid']], false);
1485
                                                $hfImages[(string) $shape['id']]->setResizeProportional(false);
1486
                                                $hfImages[(string) $shape['id']]->setWidth($style['width']);
1487
                                                $hfImages[(string) $shape['id']]->setHeight($style['height']);
1488
                                                if (isset($style['margin-left'])) {
1489
                                                    $hfImages[(string) $shape['id']]->setOffsetX($style['margin-left']);
1490
                                                }
1491
                                                $hfImages[(string) $shape['id']]->setOffsetY($style['margin-top']);
1492
                                                $hfImages[(string) $shape['id']]->setResizeProportional(true);
1493
                                            }
1494
1495
                                            $docSheet->getHeaderFooter()->setImages($hfImages);
1496
                                        }
1497
                                    }
1498
                                }
1499
                            }
1500
1501
                            // TODO: Autoshapes from twoCellAnchors!
1502 11
                            if ($zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
1503 10
                                $relsWorksheet = simplexml_load_string(
1504
                                    //~ http://schemas.openxmlformats.org/package/2006/relationships"
1505 10
                                    $this->securityScan(
1506 10
                                        $this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
1507
                                    ),
1508 10
                                    'SimpleXMLElement',
1509 10
                                    Settings::getLibXmlLoaderOptions()
1510
                                );
1511 10
                                $drawings = [];
1512 10 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...
1513 7
                                    if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing') {
1514 7
                                        $drawings[(string) $ele['Id']] = self::dirAdd("$dir/$fileWorksheet", $ele['Target']);
1515
                                    }
1516
                                }
1517 10
                                if ($xmlSheet->drawing && !$this->readDataOnly) {
1518 3
                                    foreach ($xmlSheet->drawing as $drawing) {
1519 3
                                        $fileDrawing = $drawings[(string) self::getArrayItem($drawing->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id')];
1520 3
                                        $relsDrawing = simplexml_load_string(
1521
                                            //~ http://schemas.openxmlformats.org/package/2006/relationships"
1522 3
                                            $this->securityScan(
1523 3
                                                $this->getFromZipArchive($zip, dirname($fileDrawing) . '/_rels/' . basename($fileDrawing) . '.rels')
1524
                                            ),
1525 3
                                            'SimpleXMLElement',
1526 3
                                            Settings::getLibXmlLoaderOptions()
1527
                                        );
1528 3
                                        $images = [];
1529
1530 3
                                        if ($relsDrawing && $relsDrawing->Relationship) {
1531 3
                                            foreach ($relsDrawing->Relationship as $ele) {
1532 3
                                                if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') {
1533 3
                                                    $images[(string) $ele['Id']] = self::dirAdd($fileDrawing, $ele['Target']);
1534 1
                                                } elseif ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart') {
1535 1
                                                    if ($this->includeCharts) {
1536 1
                                                        $charts[self::dirAdd($fileDrawing, $ele['Target'])] = [
1537 1
                                                            'id' => (string) $ele['Id'],
1538 3
                                                            'sheet' => $docSheet->getTitle(),
1539
                                                        ];
1540
                                                    }
1541
                                                }
1542
                                            }
1543
                                        }
1544 3
                                        $xmlDrawing = simplexml_load_string(
1545 3
                                            $this->securityScan($this->getFromZipArchive($zip, $fileDrawing)),
1546 3
                                            'SimpleXMLElement',
1547 3
                                            Settings::getLibXmlLoaderOptions()
1548 3
                                        )->children('http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing');
1549
1550 3
                                        if ($xmlDrawing->oneCellAnchor) {
1551 2
                                            foreach ($xmlDrawing->oneCellAnchor as $oneCellAnchor) {
1552 2
                                                if ($oneCellAnchor->pic->blipFill) {
1553
                                                    /** @var \SimpleXMLElement $blip */
1554 2
                                                    $blip = $oneCellAnchor->pic->blipFill->children('http://schemas.openxmlformats.org/drawingml/2006/main')->blip;
1555
                                                    /** @var \SimpleXMLElement $xfrm */
1556 2
                                                    $xfrm = $oneCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->xfrm;
1557
                                                    /** @var \SimpleXMLElement $outerShdw */
1558 2
                                                    $outerShdw = $oneCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->effectLst->outerShdw;
1559 2
                                                    $objDrawing = new Worksheet\Drawing();
1560 2
                                                    $objDrawing->setName((string) self::getArrayItem($oneCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'name'));
1561 2
                                                    $objDrawing->setDescription((string) self::getArrayItem($oneCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'descr'));
1562 2
                                                    $objDrawing->setPath(
1563 2
                                                        'zip://' . File::realpath($pFilename) . '#' .
1564 2
                                                        $images[(string) self::getArrayItem(
1565 2
                                                            $blip->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'),
1566 2
                                                            'embed'
1567
                                                        )],
1568 2
                                                        false
1569
                                                    );
1570 2
                                                    $objDrawing->setCoordinates(Cell::stringFromColumnIndex((string) $oneCellAnchor->from->col) . ($oneCellAnchor->from->row + 1));
1571 2
                                                    $objDrawing->setOffsetX(Drawing::EMUToPixels($oneCellAnchor->from->colOff));
1572 2
                                                    $objDrawing->setOffsetY(Drawing::EMUToPixels($oneCellAnchor->from->rowOff));
1573 2
                                                    $objDrawing->setResizeProportional(false);
1574 2
                                                    $objDrawing->setWidth(Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), 'cx')));
1575 2
                                                    $objDrawing->setHeight(Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), 'cy')));
1576 2
                                                    if ($xfrm) {
1577 2
                                                        $objDrawing->setRotation(Drawing::angleToDegrees(self::getArrayItem($xfrm->attributes(), 'rot')));
1578
                                                    }
1579 2 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...
1580 2
                                                        $shadow = $objDrawing->getShadow();
1581 2
                                                        $shadow->setVisible(true);
1582 2
                                                        $shadow->setBlurRadius(Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), 'blurRad')));
1583 2
                                                        $shadow->setDistance(Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), 'dist')));
1584 2
                                                        $shadow->setDirection(Drawing::angleToDegrees(self::getArrayItem($outerShdw->attributes(), 'dir')));
1585 2
                                                        $shadow->setAlignment((string) self::getArrayItem($outerShdw->attributes(), 'algn'));
1586 2
                                                        $shadow->getColor()->setRGB(self::getArrayItem($outerShdw->srgbClr->attributes(), 'val'));
1587 2
                                                        $shadow->setAlpha(self::getArrayItem($outerShdw->srgbClr->alpha->attributes(), 'val') / 1000);
1588
                                                    }
1589 2
                                                    $objDrawing->setWorksheet($docSheet);
1590
                                                } else {
1591
                                                    //    ? Can charts be positioned with a oneCellAnchor ?
1592
                                                    $coordinates = 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...
1593
                                                    $offsetX = 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...
1594
                                                    $offsetY = 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...
1595
                                                    $width = 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...
1596 2
                                                    $height = 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...
1597
                                                }
1598
                                            }
1599
                                        }
1600 3
                                        if ($xmlDrawing->twoCellAnchor) {
1601 1
                                            foreach ($xmlDrawing->twoCellAnchor as $twoCellAnchor) {
1602 1
                                                if ($twoCellAnchor->pic->blipFill) {
1603 1
                                                    $blip = $twoCellAnchor->pic->blipFill->children('http://schemas.openxmlformats.org/drawingml/2006/main')->blip;
1604 1
                                                    $xfrm = $twoCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->xfrm;
1605 1
                                                    $outerShdw = $twoCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->effectLst->outerShdw;
1606 1
                                                    $objDrawing = new Worksheet\Drawing();
1607 1
                                                    $objDrawing->setName((string) self::getArrayItem($twoCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'name'));
1608 1
                                                    $objDrawing->setDescription((string) self::getArrayItem($twoCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'descr'));
1609 1
                                                    $objDrawing->setPath(
1610 1
                                                        'zip://' . File::realpath($pFilename) . '#' .
1611 1
                                                        $images[(string) self::getArrayItem(
1612 1
                                                            $blip->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'),
1613 1
                                                            'embed'
1614
                                                        )],
1615 1
                                                        false
1616
                                                    );
1617 1
                                                    $objDrawing->setCoordinates(Cell::stringFromColumnIndex((string) $twoCellAnchor->from->col) . ($twoCellAnchor->from->row + 1));
1618 1
                                                    $objDrawing->setOffsetX(Drawing::EMUToPixels($twoCellAnchor->from->colOff));
1619 1
                                                    $objDrawing->setOffsetY(Drawing::EMUToPixels($twoCellAnchor->from->rowOff));
1620 1
                                                    $objDrawing->setResizeProportional(false);
1621
1622 1
                                                    if ($xfrm) {
1623 1
                                                        $objDrawing->setWidth(Drawing::EMUToPixels(self::getArrayItem($xfrm->ext->attributes(), 'cx')));
1624 1
                                                        $objDrawing->setHeight(Drawing::EMUToPixels(self::getArrayItem($xfrm->ext->attributes(), 'cy')));
1625 1
                                                        $objDrawing->setRotation(Drawing::angleToDegrees(self::getArrayItem($xfrm->attributes(), 'rot')));
1626
                                                    }
1627 1 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...
1628
                                                        $shadow = $objDrawing->getShadow();
1629
                                                        $shadow->setVisible(true);
1630
                                                        $shadow->setBlurRadius(Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), 'blurRad')));
1631
                                                        $shadow->setDistance(Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), 'dist')));
1632
                                                        $shadow->setDirection(Drawing::angleToDegrees(self::getArrayItem($outerShdw->attributes(), 'dir')));
1633
                                                        $shadow->setAlignment((string) self::getArrayItem($outerShdw->attributes(), 'algn'));
1634
                                                        $shadow->getColor()->setRGB(self::getArrayItem($outerShdw->srgbClr->attributes(), 'val'));
1635
                                                        $shadow->setAlpha(self::getArrayItem($outerShdw->srgbClr->alpha->attributes(), 'val') / 1000);
1636
                                                    }
1637 1
                                                    $objDrawing->setWorksheet($docSheet);
1638 1
                                                } elseif (($this->includeCharts) && ($twoCellAnchor->graphicFrame)) {
1639 1
                                                    $fromCoordinate = Cell::stringFromColumnIndex((string) $twoCellAnchor->from->col) . ($twoCellAnchor->from->row + 1);
1640 1
                                                    $fromOffsetX = Drawing::EMUToPixels($twoCellAnchor->from->colOff);
1641 1
                                                    $fromOffsetY = Drawing::EMUToPixels($twoCellAnchor->from->rowOff);
1642 1
                                                    $toCoordinate = Cell::stringFromColumnIndex((string) $twoCellAnchor->to->col) . ($twoCellAnchor->to->row + 1);
1643 1
                                                    $toOffsetX = Drawing::EMUToPixels($twoCellAnchor->to->colOff);
1644 1
                                                    $toOffsetY = Drawing::EMUToPixels($twoCellAnchor->to->rowOff);
1645 1
                                                    $graphic = $twoCellAnchor->graphicFrame->children('http://schemas.openxmlformats.org/drawingml/2006/main')->graphic;
1646
                                                    /** @var \SimpleXMLElement $chartRef */
1647 1
                                                    $chartRef = $graphic->graphicData->children('http://schemas.openxmlformats.org/drawingml/2006/chart')->chart;
1648 1
                                                    $thisChart = (string) $chartRef->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships');
1649
1650 1
                                                    $chartDetails[$docSheet->getTitle() . '!' . $thisChart] = [
1651 1
                                                        'fromCoordinate' => $fromCoordinate,
1652 1
                                                        'fromOffsetX' => $fromOffsetX,
1653 1
                                                        'fromOffsetY' => $fromOffsetY,
1654 1
                                                        'toCoordinate' => $toCoordinate,
1655 1
                                                        'toOffsetX' => $toOffsetX,
1656 1
                                                        'toOffsetY' => $toOffsetY,
1657 3
                                                        'worksheetTitle' => $docSheet->getTitle(),
1658
                                                    ];
1659
                                                }
1660
                                            }
1661
                                        }
1662
                                    }
1663
                                }
1664
                            }
1665
1666
                            // Loop through definedNames
1667 11
                            if ($xmlWorkbook->definedNames) {
1668 5
                                foreach ($xmlWorkbook->definedNames->definedName as $definedName) {
1669
                                    // Extract range
1670 1
                                    $extractedRange = (string) $definedName;
1671 1 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...
1672 1
                                        $extractedRange = substr($extractedRange, 0, $spos) . str_replace('$', '', substr($extractedRange, $spos));
1673
                                    } else {
1674
                                        $extractedRange = str_replace('$', '', $extractedRange);
1675
                                    }
1676
1677
                                    // Valid range?
1678 1
                                    if (stripos((string) $definedName, '#REF!') !== false || $extractedRange == '') {
1679
                                        continue;
1680
                                    }
1681
1682
                                    // Some definedNames are only applicable if we are on the same sheet...
1683 1
                                    if ((string) $definedName['localSheetId'] != '' && (string) $definedName['localSheetId'] == $sheetId) {
1684
                                        // Switch on type
1685 1
                                        switch ((string) $definedName['name']) {
1686 1
                                            case '_xlnm._FilterDatabase':
1687
                                                if ((string) $definedName['hidden'] !== '1') {
1688
                                                    $extractedRange = explode(',', $extractedRange);
1689
                                                    foreach ($extractedRange as $range) {
1690
                                                        $autoFilterRange = $range;
1691
                                                        if (strpos($autoFilterRange, ':') !== false) {
1692
                                                            $docSheet->getAutoFilter()->setRange($autoFilterRange);
1693
                                                        }
1694
                                                    }
1695
                                                }
1696
1697
                                                break;
1698 1
                                            case '_xlnm.Print_Titles':
1699
                                                // Split $extractedRange
1700 1
                                                $extractedRange = explode(',', $extractedRange);
1701
1702
                                                // Set print titles
1703 1
                                                foreach ($extractedRange as $range) {
1704 1
                                                    $matches = [];
1705 1
                                                    $range = str_replace('$', '', $range);
1706
1707
                                                    // check for repeating columns, e g. 'A:A' or 'A:D'
1708 1
                                                    if (preg_match('/!?([A-Z]+)\:([A-Z]+)$/', $range, $matches)) {
1709
                                                        $docSheet->getPageSetup()->setColumnsToRepeatAtLeft([$matches[1], $matches[2]]);
1710 1
                                                    } elseif (preg_match('/!?(\d+)\:(\d+)$/', $range, $matches)) {
1711
                                                        // check for repeating rows, e.g. '1:1' or '1:5'
1712 1
                                                        $docSheet->getPageSetup()->setRowsToRepeatAtTop([$matches[1], $matches[2]]);
1713
                                                    }
1714
                                                }
1715
1716 1
                                                break;
1717
                                            case '_xlnm.Print_Area':
1718
                                                $rangeSets = preg_split("/'(.*?)'(?:![A-Z0-9]+:[A-Z0-9]+,?)/", $extractedRange, PREG_SPLIT_NO_EMPTY);
1719
                                                $newRangeSets = [];
1720
                                                foreach ($rangeSets as $rangeSet) {
1721
                                                    $range = explode('!', $rangeSet); // FIXME: what if sheetname contains exclamation mark?
1722
                                                    $rangeSet = isset($range[1]) ? $range[1] : $range[0];
1723
                                                    if (strpos($rangeSet, ':') === false) {
1724
                                                        $rangeSet = $rangeSet . ':' . $rangeSet;
1725
                                                    }
1726
                                                    $newRangeSets[] = str_replace('$', '', $rangeSet);
1727
                                                }
1728
                                                $docSheet->getPageSetup()->setPrintArea(implode(',', $newRangeSets));
1729
1730
                                                break;
1731
                                            default:
1732 1
                                                break;
1733
                                        }
1734
                                    }
1735
                                }
1736
                            }
1737
1738
                            // Next sheet id
1739 11
                            ++$sheetId;
1740
                        }
1741
1742
                        // Loop through definedNames
1743 11
                        if ($xmlWorkbook->definedNames) {
1744 5
                            foreach ($xmlWorkbook->definedNames->definedName as $definedName) {
1745
                                // Extract range
1746 1
                                $extractedRange = (string) $definedName;
1747 1 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...
1748 1
                                    $extractedRange = substr($extractedRange, 0, $spos) . str_replace('$', '', substr($extractedRange, $spos));
1749
                                } else {
1750
                                    $extractedRange = str_replace('$', '', $extractedRange);
1751
                                }
1752
1753
                                // Valid range?
1754 1
                                if (stripos((string) $definedName, '#REF!') !== false || $extractedRange == '') {
1755
                                    continue;
1756
                                }
1757
1758
                                // Some definedNames are only applicable if we are on the same sheet...
1759 1
                                if ((string) $definedName['localSheetId'] != '') {
1760
                                    // Local defined name
1761
                                    // Switch on type
1762 1
                                    switch ((string) $definedName['name']) {
1763 1
                                        case '_xlnm._FilterDatabase':
1764 1
                                        case '_xlnm.Print_Titles':
1765
                                        case '_xlnm.Print_Area':
1766 1
                                            break;
1767
                                        default:
1768
                                            if ($mapSheetId[(int) $definedName['localSheetId']] !== null) {
1769
                                                $range = explode('!', (string) $definedName);
1770
                                                if (count($range) == 2) {
1771
                                                    $range[0] = str_replace("''", "'", $range[0]);
1772
                                                    $range[0] = str_replace("'", '', $range[0]);
1773
                                                    if ($worksheet = $docSheet->getParent()->getSheetByName($range[0])) {
1774
                                                        $extractedRange = str_replace('$', '', $range[1]);
1775
                                                        $scope = $docSheet->getParent()->getSheet($mapSheetId[(int) $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...
1776
                                                        $excel->addNamedRange(new NamedRange((string) $definedName['name'], $worksheet, $extractedRange, true, $scope));
1777
                                                    }
1778
                                                }
1779
                                            }
1780
1781 1
                                            break;
1782
                                    }
1783
                                } elseif (!isset($definedName['localSheetId'])) {
1784
                                    // "Global" definedNames
1785
                                    $locatedSheet = null;
1786
                                    $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...
1787
                                    if (strpos((string) $definedName, '!') !== false) {
1788
                                        // Extract sheet name
1789
                                        $extractedSheetName = Worksheet::extractSheetTitle((string) $definedName, true);
1790
                                        $extractedSheetName = $extractedSheetName[0];
1791
1792
                                        // Locate sheet
1793
                                        $locatedSheet = $excel->getSheetByName($extractedSheetName);
1794
1795
                                        // Modify range
1796
                                        $range = explode('!', $extractedRange);
1797
                                        $extractedRange = isset($range[1]) ? $range[1] : $range[0];
1798
                                    }
1799
1800
                                    if ($locatedSheet !== null) {
1801 1
                                        $excel->addNamedRange(new NamedRange((string) $definedName['name'], $locatedSheet, $extractedRange, false));
1802
                                    }
1803
                                }
1804
                            }
1805
                        }
1806
                    }
1807
1808 11
                    if ((!$this->readDataOnly) || (!empty($this->loadSheetsOnly))) {
1809
                        // active sheet index
1810 11
                        $activeTab = (int) ($xmlWorkbook->bookViews->workbookView['activeTab']); // refers to old sheet index
1811
1812
                        // keep active sheet index if sheet is still loaded, else first sheet is set as the active
1813 11
                        if (isset($mapSheetId[$activeTab]) && $mapSheetId[$activeTab] !== null) {
1814 11
                            $excel->setActiveSheetIndex($mapSheetId[$activeTab]);
1815
                        } else {
1816
                            if ($excel->getSheetCount() == 0) {
1817
                                $excel->createSheet();
1818
                            }
1819
                            $excel->setActiveSheetIndex(0);
1820
                        }
1821
                    }
1822
1823 11
                    break;
1824
            }
1825
        }
1826
1827 11
        if (!$this->readDataOnly) {
1828 11
            $contentTypes = simplexml_load_string(
1829 11
                $this->securityScan(
1830 11
                    $this->getFromZipArchive($zip, '[Content_Types].xml')
1831
                ),
1832 11
                'SimpleXMLElement',
1833 11
                Settings::getLibXmlLoaderOptions()
1834
            );
1835 11
            foreach ($contentTypes->Override as $contentType) {
1836 11
                switch ($contentType['ContentType']) {
1837 11
                    case 'application/vnd.openxmlformats-officedocument.drawingml.chart+xml':
1838 1
                        if ($this->includeCharts) {
1839 1
                            $chartEntryRef = ltrim($contentType['PartName'], '/');
1840 1
                            $chartElements = simplexml_load_string(
1841 1
                                $this->securityScan(
1842 1
                                    $this->getFromZipArchive($zip, $chartEntryRef)
1843
                                ),
1844 1
                                'SimpleXMLElement',
1845 1
                                Settings::getLibXmlLoaderOptions()
1846
                            );
1847 1
                            $objChart = Chart::readChart($chartElements, basename($chartEntryRef, '.xml'));
1848
1849 1
                            if (isset($charts[$chartEntryRef])) {
1850 1
                                $chartPositionRef = $charts[$chartEntryRef]['sheet'] . '!' . $charts[$chartEntryRef]['id'];
1851 1
                                if (isset($chartDetails[$chartPositionRef])) {
1852 1
                                    $excel->getSheetByName($charts[$chartEntryRef]['sheet'])->addChart($objChart);
1853 1
                                    $objChart->setWorksheet($excel->getSheetByName($charts[$chartEntryRef]['sheet']));
1854 1
                                    $objChart->setTopLeftPosition($chartDetails[$chartPositionRef]['fromCoordinate'], $chartDetails[$chartPositionRef]['fromOffsetX'], $chartDetails[$chartPositionRef]['fromOffsetY']);
1855 11
                                    $objChart->setBottomRightPosition($chartDetails[$chartPositionRef]['toCoordinate'], $chartDetails[$chartPositionRef]['toOffsetX'], $chartDetails[$chartPositionRef]['toOffsetY']);
1856
                                }
1857
                            }
1858
                        }
1859
                }
1860
            }
1861
        }
1862
1863 11
        $zip->close();
1864
1865 11
        return $excel;
1866
    }
1867
1868 11
    private static function readColor($color, $background = false)
1869
    {
1870 11
        if (isset($color['rgb'])) {
1871 8
            return (string) $color['rgb'];
1872 7
        } elseif (isset($color['indexed'])) {
1873 6
            return Style\Color::indexedColor($color['indexed'] - 7, $background)->getARGB();
1874 4
        } elseif (isset($color['theme'])) {
1875 4
            if (self::$theme !== null) {
1876 4
                $returnColour = self::$theme->getColourByIndex((int) $color['theme']);
1877 4
                if (isset($color['tint'])) {
1878 1
                    $tintAdjust = (float) $color['tint'];
1879 1
                    $returnColour = Style\Color::changeBrightness($returnColour, $tintAdjust);
1880
                }
1881
1882 4
                return 'FF' . $returnColour;
1883
            }
1884
        }
1885
1886 1
        if ($background) {
1887
            return 'FFFFFFFF';
1888
        }
1889
1890 1
        return 'FF000000';
1891
    }
1892
1893
    /**
1894
     * @param Style $docStyle
1895
     * @param \SimpleXMLElement|\stdClass $style
1896
     */
1897 11
    private static function readStyle(Style $docStyle, $style)
1898
    {
1899 11
        $docStyle->getNumberFormat()->setFormatCode($style->numFmt);
1900
1901
        // font
1902 11
        if (isset($style->font)) {
1903 11
            $docStyle->getFont()->setName((string) $style->font->name['val']);
1904 11
            $docStyle->getFont()->setSize((string) $style->font->sz['val']);
1905 11 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...
1906 8
                $docStyle->getFont()->setBold(!isset($style->font->b['val']) || self::boolean((string) $style->font->b['val']));
1907
            }
1908 11 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...
1909 6
                $docStyle->getFont()->setItalic(!isset($style->font->i['val']) || self::boolean((string) $style->font->i['val']));
1910
            }
1911 11 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...
1912 5
                $docStyle->getFont()->setStrikethrough(!isset($style->font->strike['val']) || self::boolean((string) $style->font->strike['val']));
1913
            }
1914 11
            $docStyle->getFont()->getColor()->setARGB(self::readColor($style->font->color));
1915
1916 11 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...
1917
                $docStyle->getFont()->setUnderline(Style\Font::UNDERLINE_SINGLE);
1918 11
            } elseif (isset($style->font->u, $style->font->u['val'])) {
1919 5
                $docStyle->getFont()->setUnderline((string) $style->font->u['val']);
1920
            }
1921
1922 11 View Code Duplication
            if (isset($style->font->vertAlign, $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...
1923
                $vertAlign = strtolower((string) $style->font->vertAlign['val']);
1924
                if ($vertAlign == 'superscript') {
1925
                    $docStyle->getFont()->setSuperscript(true);
1926
                }
1927
                if ($vertAlign == 'subscript') {
1928
                    $docStyle->getFont()->setSubscript(true);
1929
                }
1930
            }
1931
        }
1932
1933
        // fill
1934 11
        if (isset($style->fill)) {
1935 11
            if ($style->fill->gradientFill) {
1936
                /** @var \SimpleXMLElement $gradientFill */
1937 2
                $gradientFill = $style->fill->gradientFill[0];
1938 2
                if (!empty($gradientFill['type'])) {
1939 2
                    $docStyle->getFill()->setFillType((string) $gradientFill['type']);
1940
                }
1941 2
                $docStyle->getFill()->setRotation((float) ($gradientFill['degree']));
1942 2
                $gradientFill->registerXPathNamespace('sml', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
1943 2
                $docStyle->getFill()->getStartColor()->setARGB(self::readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=0]'))->color));
1944 2
                $docStyle->getFill()->getEndColor()->setARGB(self::readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=1]'))->color));
1945 11
            } elseif ($style->fill->patternFill) {
1946 11
                $patternType = (string) $style->fill->patternFill['patternType'] != '' ? (string) $style->fill->patternFill['patternType'] : 'solid';
1947 11
                $docStyle->getFill()->setFillType($patternType);
1948 11
                if ($style->fill->patternFill->fgColor) {
1949 4
                    $docStyle->getFill()->getStartColor()->setARGB(self::readColor($style->fill->patternFill->fgColor, true));
1950
                } else {
1951 11
                    $docStyle->getFill()->getStartColor()->setARGB('FF000000');
1952
                }
1953 11
                if ($style->fill->patternFill->bgColor) {
1954 4
                    $docStyle->getFill()->getEndColor()->setARGB(self::readColor($style->fill->patternFill->bgColor, true));
1955
                }
1956
            }
1957
        }
1958
1959
        // border
1960 11
        if (isset($style->border)) {
1961 11
            $diagonalUp = self::boolean((string) $style->border['diagonalUp']);
1962 11
            $diagonalDown = self::boolean((string) $style->border['diagonalDown']);
1963 11
            if (!$diagonalUp && !$diagonalDown) {
1964 11
                $docStyle->getBorders()->setDiagonalDirection(Style\Borders::DIAGONAL_NONE);
1965
            } elseif ($diagonalUp && !$diagonalDown) {
1966
                $docStyle->getBorders()->setDiagonalDirection(Style\Borders::DIAGONAL_UP);
1967
            } elseif (!$diagonalUp && $diagonalDown) {
1968
                $docStyle->getBorders()->setDiagonalDirection(Style\Borders::DIAGONAL_DOWN);
1969
            } else {
1970
                $docStyle->getBorders()->setDiagonalDirection(Style\Borders::DIAGONAL_BOTH);
1971
            }
1972 11
            self::readBorder($docStyle->getBorders()->getLeft(), $style->border->left);
1973 11
            self::readBorder($docStyle->getBorders()->getRight(), $style->border->right);
1974 11
            self::readBorder($docStyle->getBorders()->getTop(), $style->border->top);
1975 11
            self::readBorder($docStyle->getBorders()->getBottom(), $style->border->bottom);
1976 11
            self::readBorder($docStyle->getBorders()->getDiagonal(), $style->border->diagonal);
1977
        }
1978
1979
        // alignment
1980 11
        if (isset($style->alignment)) {
1981 11
            $docStyle->getAlignment()->setHorizontal((string) $style->alignment['horizontal']);
1982 11
            $docStyle->getAlignment()->setVertical((string) $style->alignment['vertical']);
1983
1984 11
            $textRotation = 0;
1985 11
            if ((int) $style->alignment['textRotation'] <= 90) {
1986 11
                $textRotation = (int) $style->alignment['textRotation'];
1987
            } elseif ((int) $style->alignment['textRotation'] > 90) {
1988
                $textRotation = 90 - (int) $style->alignment['textRotation'];
1989
            }
1990
1991 11
            $docStyle->getAlignment()->setTextRotation((int) $textRotation);
1992 11
            $docStyle->getAlignment()->setWrapText(self::boolean((string) $style->alignment['wrapText']));
1993 11
            $docStyle->getAlignment()->setShrinkToFit(self::boolean((string) $style->alignment['shrinkToFit']));
1994 11
            $docStyle->getAlignment()->setIndent((int) ((string) $style->alignment['indent']) > 0 ? (int) ((string) $style->alignment['indent']) : 0);
1995 11
            $docStyle->getAlignment()->setReadOrder((int) ((string) $style->alignment['readingOrder']) > 0 ? (int) ((string) $style->alignment['readingOrder']) : 0);
1996
        }
1997
1998
        // protection
1999 11
        if (isset($style->protection)) {
2000 11 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...
2001 2
                if (self::boolean((string) $style->protection['locked'])) {
2002
                    $docStyle->getProtection()->setLocked(Style\Protection::PROTECTION_PROTECTED);
2003
                } else {
2004 2
                    $docStyle->getProtection()->setLocked(Style\Protection::PROTECTION_UNPROTECTED);
2005
                }
2006
            }
2007
2008 11 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...
2009
                if (self::boolean((string) $style->protection['hidden'])) {
2010
                    $docStyle->getProtection()->setHidden(Style\Protection::PROTECTION_PROTECTED);
2011
                } else {
2012
                    $docStyle->getProtection()->setHidden(Style\Protection::PROTECTION_UNPROTECTED);
2013
                }
2014
            }
2015
        }
2016
2017
        // top-level style settings
2018 11
        if (isset($style->quotePrefix)) {
2019 11
            $docStyle->setQuotePrefix($style->quotePrefix);
2020
        }
2021 11
    }
2022
2023
    /**
2024
     * @param Style\Border $docBorder
2025
     * @param \SimpleXMLElement $eleBorder
2026
     */
2027 11
    private static function readBorder($docBorder, $eleBorder)
2028
    {
2029 11
        if (isset($eleBorder['style'])) {
2030 3
            $docBorder->setBorderStyle((string) $eleBorder['style']);
2031
        }
2032 11
        if (isset($eleBorder->color)) {
2033 3
            $docBorder->getColor()->setARGB(self::readColor($eleBorder->color));
2034
        }
2035 11
    }
2036
2037
    /**
2038
     * @param \SimpleXMLElement | null $is
2039
     *
2040
     * @return RichText
2041
     */
2042 3
    private function parseRichText($is)
2043
    {
2044 3
        $value = new RichText();
2045
2046 3
        if (isset($is->t)) {
2047
            $value->createText(StringHelper::controlCharacterOOXML2PHP((string) $is->t));
2048
        } else {
2049 3
            if (is_object($is->r)) {
2050 3
                foreach ($is->r as $run) {
2051 3
                    if (!isset($run->rPr)) {
2052 3
                        $objText = $value->createText(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...
2053
                    } else {
2054 3
                        $objText = $value->createTextRun(StringHelper::controlCharacterOOXML2PHP((string) $run->t));
2055
2056 3 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...
2057 3
                            $objText->getFont()->setName((string) $run->rPr->rFont['val']);
2058
                        }
2059 3
                        if (isset($run->rPr->sz['val'])) {
2060 3
                            $objText->getFont()->setSize((string) $run->rPr->sz['val']);
2061
                        }
2062 3
                        if (isset($run->rPr->color)) {
2063 3
                            $objText->getFont()->setColor(new Style\Color(self::readColor($run->rPr->color)));
2064
                        }
2065 3 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...
2066 3
                            (isset($run->rPr->b) && !isset($run->rPr->b['val']))) {
2067 3
                            $objText->getFont()->setBold(true);
2068
                        }
2069 3 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...
2070 3
                            (isset($run->rPr->i) && !isset($run->rPr->i['val']))) {
2071 2
                            $objText->getFont()->setItalic(true);
2072
                        }
2073 3 View Code Duplication
                        if (isset($run->rPr->vertAlign, $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...
2074
                            $vertAlign = strtolower((string) $run->rPr->vertAlign['val']);
2075
                            if ($vertAlign == 'superscript') {
2076
                                $objText->getFont()->setSuperscript(true);
2077
                            }
2078
                            if ($vertAlign == 'subscript') {
2079
                                $objText->getFont()->setSubscript(true);
2080
                            }
2081
                        }
2082 3 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...
2083
                            $objText->getFont()->setUnderline(Style\Font::UNDERLINE_SINGLE);
2084 3
                        } elseif (isset($run->rPr->u, $run->rPr->u['val'])) {
2085 2
                            $objText->getFont()->setUnderline((string) $run->rPr->u['val']);
2086
                        }
2087 3 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...
2088 3
                            (isset($run->rPr->strike) && !isset($run->rPr->strike['val']))) {
2089 3
                            $objText->getFont()->setStrikethrough(true);
2090
                        }
2091
                    }
2092
                }
2093
            }
2094
        }
2095
2096 3
        return $value;
2097
    }
2098
2099
    /**
2100
     * @param Spreadsheet $excel
2101
     * @param mixed $customUITarget
2102
     * @param mixed $zip
2103
     */
2104
    private function readRibbon(Spreadsheet $excel, $customUITarget, $zip)
2105
    {
2106
        $baseDir = dirname($customUITarget);
2107
        $nameCustomUI = basename($customUITarget);
2108
        // get the xml file (ribbon)
2109
        $localRibbon = $this->getFromZipArchive($zip, $customUITarget);
2110
        $customUIImagesNames = [];
2111
        $customUIImagesBinaries = [];
2112
        // something like customUI/_rels/customUI.xml.rels
2113
        $pathRels = $baseDir . '/_rels/' . $nameCustomUI . '.rels';
2114
        $dataRels = $this->getFromZipArchive($zip, $pathRels);
2115
        if ($dataRels) {
2116
            // exists and not empty if the ribbon have some pictures (other than internal MSO)
2117
            $UIRels = simplexml_load_string(
2118
                $this->securityScan($dataRels),
2119
                'SimpleXMLElement',
2120
                Settings::getLibXmlLoaderOptions()
2121
            );
2122
            if ($UIRels) {
2123
                // we need to save id and target to avoid parsing customUI.xml and "guess" if it's a pseudo callback who load the image
2124
                foreach ($UIRels->Relationship as $ele) {
2125
                    if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') {
2126
                        // an image ?
2127
                        $customUIImagesNames[(string) $ele['Id']] = (string) $ele['Target'];
2128
                        $customUIImagesBinaries[(string) $ele['Target']] = $this->getFromZipArchive($zip, $baseDir . '/' . (string) $ele['Target']);
2129
                    }
2130
                }
2131
            }
2132
        }
2133
        if ($localRibbon) {
2134
            $excel->setRibbonXMLData($customUITarget, $localRibbon);
2135
            if (count($customUIImagesNames) > 0 && count($customUIImagesBinaries) > 0) {
2136
                $excel->setRibbonBinObjects($customUIImagesNames, $customUIImagesBinaries);
2137
            } else {
2138
                $excel->setRibbonBinObjects(null);
0 ignored issues
show
Bug introduced by
The call to setRibbonBinObjects() misses a required argument $BinObjectsData.

This check looks for function calls that miss required arguments.

Loading history...
2139
            }
2140
        } else {
2141
            $excel->setRibbonXMLData(null);
0 ignored issues
show
Bug introduced by
The call to setRibbonXMLData() misses a required argument $xmlData.

This check looks for function calls that miss required arguments.

Loading history...
2142
            $excel->setRibbonBinObjects(null);
0 ignored issues
show
Bug introduced by
The call to setRibbonBinObjects() misses a required argument $BinObjectsData.

This check looks for function calls that miss required arguments.

Loading history...
2143
        }
2144
    }
2145
2146 12
    private static function getArrayItem($array, $key = 0)
2147
    {
2148 12
        return isset($array[$key]) ? $array[$key] : null;
2149
    }
2150
2151 3
    private static function dirAdd($base, $add)
2152
    {
2153 3
        return preg_replace('~[^/]+/\.\./~', '', dirname($base) . "/$add");
2154
    }
2155
2156
    private static function toCSSArray($style)
2157
    {
2158
        $style = str_replace(["\r", "\n"], '', $style);
2159
2160
        $temp = explode(';', $style);
2161
        $style = [];
2162
        foreach ($temp as $item) {
2163
            $item = explode(':', $item);
2164
2165
            if (strpos($item[1], 'px') !== false) {
2166
                $item[1] = str_replace('px', '', $item[1]);
2167
            }
2168 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...
2169
                $item[1] = str_replace('pt', '', $item[1]);
2170
                $item[1] = Font::fontSizeToPixels($item[1]);
2171
            }
2172 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...
2173
                $item[1] = str_replace('in', '', $item[1]);
2174
                $item[1] = Font::inchSizeToPixels($item[1]);
2175
            }
2176 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...
2177
                $item[1] = str_replace('cm', '', $item[1]);
2178
                $item[1] = Font::centimeterSizeToPixels($item[1]);
2179
            }
2180
2181
            $style[$item[0]] = $item[1];
2182
        }
2183
2184
        return $style;
2185
    }
2186
2187 11
    private static function boolean($value)
2188
    {
2189 11
        if (is_object($value)) {
2190 1
            $value = (string) $value;
2191
        }
2192 11
        if (is_numeric($value)) {
2193 9
            return (bool) $value;
2194
        }
2195
2196 11
        return $value === 'true' || $value === 'TRUE';
2197
    }
2198
}
2199