Completed
Push — develop ( 1c4f11...47d726 )
by Adrien
17:07
created

Xlsx::canRead()   B

Complexity

Conditions 6
Paths 3

Size

Total Lines 40
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 6

Importance

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

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

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

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

Loading history...
87
//        if (!class_exists($zipClass, false)) {
88
//            throw new Exception($zipClass . " library is not enabled");
89
//        }
90
91 5
        $xl = false;
92
        // Load file
93
        /** @var \ZipArchive | ZipArchive $zip */
94 5
        $zip = new $zipClass();
95 5
        if ($zip->open($pFilename) === true) {
96
            // check if it is an OOXML archive
97 5
            $rels = simplexml_load_string(
98 5
                $this->securityScan(
99 5
                    $this->getFromZipArchive($zip, '_rels/.rels')
100
                ),
101 5
                'SimpleXMLElement',
102 5
                Settings::getLibXmlLoaderOptions()
103
            );
104 5
            if ($rels !== false) {
105 5
                foreach ($rels->Relationship as $rel) {
106 5
                    switch ($rel['Type']) {
107 5
                        case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument':
108 5
                            if (basename($rel['Target']) == 'workbook.xml') {
109 5
                                $xl = true;
110
                            }
111 5
                            break;
112
                    }
113
                }
114
            }
115 5
            $zip->close();
116
        }
117
118 5
        return $xl;
119
    }
120
121
    /**
122
     * Reads names of the worksheets from a file, without parsing the whole file to a Spreadsheet object.
123
     *
124
     * @param string $pFilename
125
     *
126
     * @throws Exception
127
     *
128
     * @return array
129
     */
130 1
    public function listWorksheetNames($pFilename)
131
    {
132 1
        File::assertFile($pFilename);
133
134 1
        $worksheetNames = [];
135
136 1
        $zipClass = Settings::getZipClass();
137
138
        /** @var \ZipArchive | ZipArchive $zip */
139 1
        $zip = new $zipClass();
140 1
        $zip->open($pFilename);
141
142
        //    The files we're looking at here are small enough that simpleXML is more efficient than XMLReader
143 1
        $rels = simplexml_load_string(
144 1
            $this->securityScan($this->getFromZipArchive($zip, '_rels/.rels'))
145
        ); //~ http://schemas.openxmlformats.org/package/2006/relationships");
146 1
        foreach ($rels->Relationship as $rel) {
147 1
            switch ($rel['Type']) {
148 1
                case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument':
149 1
                    $xmlWorkbook = simplexml_load_string(
150 1
                        $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}"))
151
                    ); //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
152
153 1
                    if ($xmlWorkbook->sheets) {
154 1
                        foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
155
                            // Check if sheet should be skipped
156 1
                            $worksheetNames[] = (string) $eleSheet['name'];
157
                        }
158
                    }
159
            }
160
        }
161
162 1
        $zip->close();
163
164 1
        return $worksheetNames;
165
    }
166
167
    /**
168
     * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns).
169
     *
170
     * @param string $pFilename
171
     *
172
     * @throws Exception
173
     *
174
     * @return array
175
     */
176 1
    public function listWorksheetInfo($pFilename)
177
    {
178 1
        File::assertFile($pFilename);
179
180 1
        $worksheetInfo = [];
181
182 1
        $zipClass = Settings::getZipClass();
183
184
        /** @var \ZipArchive | ZipArchive $zip */
185 1
        $zip = new $zipClass();
186 1
        $zip->open($pFilename);
187
188 1
        $rels = simplexml_load_string(
189
            //~ http://schemas.openxmlformats.org/package/2006/relationships"
190 1
            $this->securityScan($this->getFromZipArchive($zip, '_rels/.rels')),
191 1
            'SimpleXMLElement',
192 1
            Settings::getLibXmlLoaderOptions()
193
        );
194 1
        foreach ($rels->Relationship as $rel) {
195 1
            if ($rel['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument') {
196 1
                $dir = dirname($rel['Target']);
197 1
                $relsWorkbook = simplexml_load_string(
198
                    //~ http://schemas.openxmlformats.org/package/2006/relationships"
199 1
                    $this->securityScan(
200 1
                        $this->getFromZipArchive($zip, "$dir/_rels/" . basename($rel['Target']) . '.rels')
201
                    ),
202 1
                    'SimpleXMLElement',
203 1
                    Settings::getLibXmlLoaderOptions()
204
                );
205 1
                $relsWorkbook->registerXPathNamespace('rel', 'http://schemas.openxmlformats.org/package/2006/relationships');
206
207 1
                $worksheets = [];
208 1
                foreach ($relsWorkbook->Relationship as $ele) {
209 1
                    if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet') {
210 1
                        $worksheets[(string) $ele['Id']] = $ele['Target'];
211
                    }
212
                }
213
214 1
                $xmlWorkbook = simplexml_load_string(
215
                    //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
216 1
                    $this->securityScan(
217 1
                        $this->getFromZipArchive($zip, "{$rel['Target']}")
218
                    ),
219 1
                    'SimpleXMLElement',
220 1
                    Settings::getLibXmlLoaderOptions()
221
                );
222 1
                if ($xmlWorkbook->sheets) {
223 1
                    $dir = dirname($rel['Target']);
224
                    /** @var \SimpleXMLElement $eleSheet */
225 1
                    foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
226
                        $tmpInfo = [
227 1
                            'worksheetName' => (string) $eleSheet['name'],
228 1
                            'lastColumnLetter' => 'A',
229 1
                            'lastColumnIndex' => 0,
230 1
                            'totalRows' => 0,
231 1
                            'totalColumns' => 0,
232
                        ];
233
234 1
                        $fileWorksheet = $worksheets[(string) self::getArrayItem($eleSheet->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id')];
235
236 1
                        $xml = new \XMLReader();
237 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...
238 1
                            $this->securityScanFile(
239 1
                                'zip://' . File::realpath($pFilename) . '#' . "$dir/$fileWorksheet"
240
                            ),
241 1
                            null,
242 1
                            Settings::getLibXmlLoaderOptions()
243
                        );
244 1
                        $xml->setParserProperty(2, true);
245
246 1
                        $currCells = 0;
247 1
                        while ($xml->read()) {
248 1
                            if ($xml->name == 'row' && $xml->nodeType == \XMLReader::ELEMENT) {
249 1
                                $row = $xml->getAttribute('r');
250 1
                                $tmpInfo['totalRows'] = $row;
251 1
                                $tmpInfo['totalColumns'] = max($tmpInfo['totalColumns'], $currCells);
252 1
                                $currCells = 0;
253 1
                            } elseif ($xml->name == 'c' && $xml->nodeType == \XMLReader::ELEMENT) {
254 1
                                ++$currCells;
255
                            }
256
                        }
257 1
                        $tmpInfo['totalColumns'] = max($tmpInfo['totalColumns'], $currCells);
258 1
                        $xml->close();
259
260 1
                        $tmpInfo['lastColumnIndex'] = $tmpInfo['totalColumns'] - 1;
261 1
                        $tmpInfo['lastColumnLetter'] = Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
262
263 1
                        $worksheetInfo[] = $tmpInfo;
264
                    }
265
                }
266
            }
267
        }
268
269 1
        $zip->close();
270
271 1
        return $worksheetInfo;
272
    }
273
274 1
    private static function castToBoolean($c)
275
    {
276 1
        $value = isset($c->v) ? (string) $c->v : null;
277 1
        if ($value == '0') {
278
            return false;
279 1
        } elseif ($value == '1') {
280 1
            return true;
281
        }
282
283
        return (bool) $c->v;
284
        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...
285
    }
286
287
    private static function castToError($c)
288
    {
289
        return isset($c->v) ? (string) $c->v : null;
290
    }
291
292 5
    private static function castToString($c)
293
    {
294 5
        return isset($c->v) ? (string) $c->v : null;
295
    }
296
297 3
    private function castToFormula($c, $r, &$cellDataType, &$value, &$calculatedValue, &$sharedFormulas, $castBaseType)
298
    {
299 3
        $cellDataType = 'f';
300 3
        $value = "={$c->f}";
301 3
        $calculatedValue = self::$castBaseType($c);
302
303
        // Shared formula?
304 3
        if (isset($c->f['t']) && strtolower((string) $c->f['t']) == 'shared') {
305 1
            $instance = (string) $c->f['si'];
306
307 1
            if (!isset($sharedFormulas[(string) $c->f['si']])) {
308 1
                $sharedFormulas[$instance] = ['master' => $r, 'formula' => $value];
309
            } else {
310 1
                $master = Cell::coordinateFromString($sharedFormulas[$instance]['master']);
311 1
                $current = Cell::coordinateFromString($r);
312
313 1
                $difference = [0, 0];
314 1
                $difference[0] = Cell::columnIndexFromString($current[0]) - Cell::columnIndexFromString($master[0]);
315 1
                $difference[1] = $current[1] - $master[1];
316
317 1
                $value = $this->referenceHelper->updateFormulaReferences($sharedFormulas[$instance]['formula'], 'A1', $difference[0], $difference[1]);
318
            }
319
        }
320 3
    }
321
322
    /**
323
     * @param \ZipArchive | ZipArchive $archive
324
     * @param string $fileName
325
     *
326
     * @return string
327
     */
328 10
    private function getFromZipArchive($archive, $fileName = '')
329
    {
330
        // Root-relative paths
331 10
        if (strpos($fileName, '//') !== false) {
332
            $fileName = substr($fileName, strpos($fileName, '//') + 1);
333
        }
334 10
        $fileName = File::realpath($fileName);
335
336
        // Sadly, some 3rd party xlsx generators don't use consistent case for filenaming
337
        //    so we need to load case-insensitively from the zip file
338
339
        // Apache POI fixes
340 10
        $contents = $archive->getFromIndex(
341 10
            $archive->locateName($fileName, \ZipArchive::FL_NOCASE)
342
        );
343 10
        if ($contents === false) {
344
            $contents = $archive->getFromIndex(
345
                $archive->locateName(substr($fileName, 1), \ZipArchive::FL_NOCASE)
346
            );
347
        }
348
349 10
        return $contents;
350
    }
351
352
    /**
353
     * Loads Spreadsheet from file.
354
     *
355
     * @param string $pFilename
356
     *
357
     * @throws Exception
358
     *
359
     * @return Spreadsheet
360
     */
361 8
    public function load($pFilename)
362
    {
363 8
        File::assertFile($pFilename);
364
365
        // Initialisations
366 8
        $excel = new Spreadsheet();
367 8
        $excel->removeSheetByIndex(0);
368 8
        if (!$this->readDataOnly) {
369 8
            $excel->removeCellStyleXfByIndex(0); // remove the default style
370 8
            $excel->removeCellXfByIndex(0); // remove the default style
371
        }
372
373 8
        $zipClass = Settings::getZipClass();
374
375
        /** @var \ZipArchive | ZipArchive $zip */
376 8
        $zip = new $zipClass();
377 8
        $zip->open($pFilename);
378
379
        //    Read the theme first, because we need the colour scheme when reading the styles
380 8
        $wbRels = simplexml_load_string(
381
            //~ http://schemas.openxmlformats.org/package/2006/relationships"
382 8
            $this->securityScan($this->getFromZipArchive($zip, 'xl/_rels/workbook.xml.rels')),
383 8
            'SimpleXMLElement',
384 8
            Settings::getLibXmlLoaderOptions()
385
        );
386 8
        foreach ($wbRels->Relationship as $rel) {
387 8
            switch ($rel['Type']) {
388 8
                case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme':
389 8
                    $themeOrderArray = ['lt1', 'dk1', 'lt2', 'dk2'];
390 8
                    $themeOrderAdditional = count($themeOrderArray);
391
392 8
                    $xmlTheme = simplexml_load_string(
393 8
                        $this->securityScan($this->getFromZipArchive($zip, "xl/{$rel['Target']}")),
394 8
                        'SimpleXMLElement',
395 8
                        Settings::getLibXmlLoaderOptions()
396
                    );
397 8
                    if (is_object($xmlTheme)) {
398 8
                        $xmlThemeName = $xmlTheme->attributes();
399 8
                        $xmlTheme = $xmlTheme->children('http://schemas.openxmlformats.org/drawingml/2006/main');
400 8
                        $themeName = (string) $xmlThemeName['name'];
401
402 8
                        $colourScheme = $xmlTheme->themeElements->clrScheme->attributes();
403 8
                        $colourSchemeName = (string) $colourScheme['name'];
404 8
                        $colourScheme = $xmlTheme->themeElements->clrScheme->children('http://schemas.openxmlformats.org/drawingml/2006/main');
405
406 8
                        $themeColours = [];
407 8
                        foreach ($colourScheme as $k => $xmlColour) {
408 8
                            $themePos = array_search($k, $themeOrderArray);
409 8
                            if ($themePos === false) {
410 8
                                $themePos = $themeOrderAdditional++;
411
                            }
412 8
                            if (isset($xmlColour->sysClr)) {
413 8
                                $xmlColourData = $xmlColour->sysClr->attributes();
414 8
                                $themeColours[$themePos] = $xmlColourData['lastClr'];
415
                            } elseif (isset($xmlColour->srgbClr)) {
416 8
                                $xmlColourData = $xmlColour->srgbClr->attributes();
417 8
                                $themeColours[$themePos] = $xmlColourData['val'];
418
                            }
419
                        }
420 8
                        self::$theme = new Xlsx\Theme($themeName, $colourSchemeName, $themeColours);
421
                    }
422 8
                    break;
423
            }
424
        }
425
426 8
        $rels = simplexml_load_string(
427
            //~ http://schemas.openxmlformats.org/package/2006/relationships"
428 8
            $this->securityScan($this->getFromZipArchive($zip, '_rels/.rels')),
429 8
            'SimpleXMLElement',
430 8
            Settings::getLibXmlLoaderOptions()
431
        );
432 8
        foreach ($rels->Relationship as $rel) {
433 8
            switch ($rel['Type']) {
434 8
                case 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties':
435 8
                    $xmlCore = simplexml_load_string(
436 8
                        $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")),
437 8
                        'SimpleXMLElement',
438 8
                        Settings::getLibXmlLoaderOptions()
439
                    );
440 8
                    if (is_object($xmlCore)) {
441 8
                        $xmlCore->registerXPathNamespace('dc', 'http://purl.org/dc/elements/1.1/');
442 8
                        $xmlCore->registerXPathNamespace('dcterms', 'http://purl.org/dc/terms/');
443 8
                        $xmlCore->registerXPathNamespace('cp', 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties');
444 8
                        $docProps = $excel->getProperties();
445 8
                        $docProps->setCreator((string) self::getArrayItem($xmlCore->xpath('dc:creator')));
446 8
                        $docProps->setLastModifiedBy((string) self::getArrayItem($xmlCore->xpath('cp:lastModifiedBy')));
447 8
                        $docProps->setCreated(strtotime(self::getArrayItem($xmlCore->xpath('dcterms:created')))); //! respect xsi:type
0 ignored issues
show
Documentation introduced by
strtotime(self::getArray...th('dcterms:created'))) is of type integer, but the function expects a object<PhpOffice\PhpSpre...Document\datetime>|null.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

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

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
449 8
                        $docProps->setTitle((string) self::getArrayItem($xmlCore->xpath('dc:title')));
450 8
                        $docProps->setDescription((string) self::getArrayItem($xmlCore->xpath('dc:description')));
451 8
                        $docProps->setSubject((string) self::getArrayItem($xmlCore->xpath('dc:subject')));
452 8
                        $docProps->setKeywords((string) self::getArrayItem($xmlCore->xpath('cp:keywords')));
453 8
                        $docProps->setCategory((string) self::getArrayItem($xmlCore->xpath('cp:category')));
454
                    }
455 8
                    break;
456 8
                case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties':
457 8
                    $xmlCore = simplexml_load_string(
458 8
                        $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")),
459 8
                        'SimpleXMLElement',
460 8
                        Settings::getLibXmlLoaderOptions()
461
                    );
462 8
                    if (is_object($xmlCore)) {
463 8
                        $docProps = $excel->getProperties();
464 8
                        if (isset($xmlCore->Company)) {
465 7
                            $docProps->setCompany((string) $xmlCore->Company);
466
                        }
467 8
                        if (isset($xmlCore->Manager)) {
468 5
                            $docProps->setManager((string) $xmlCore->Manager);
469
                        }
470
                    }
471 8
                    break;
472 8
                case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties':
473 1
                    $xmlCore = simplexml_load_string(
474 1
                        $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")),
475 1
                        'SimpleXMLElement',
476 1
                        Settings::getLibXmlLoaderOptions()
477
                    );
478 1
                    if (is_object($xmlCore)) {
479 1
                        $docProps = $excel->getProperties();
480
                        /** @var \SimpleXMLElement $xmlProperty */
481 1
                        foreach ($xmlCore as $xmlProperty) {
482 1
                            $cellDataOfficeAttributes = $xmlProperty->attributes();
483 1
                            if (isset($cellDataOfficeAttributes['name'])) {
484 1
                                $propertyName = (string) $cellDataOfficeAttributes['name'];
485 1
                                $cellDataOfficeChildren = $xmlProperty->children('http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes');
486 1
                                $attributeType = $cellDataOfficeChildren->getName();
487 1
                                $attributeValue = (string) $cellDataOfficeChildren->{$attributeType};
488 1
                                $attributeValue = Properties::convertProperty($attributeValue, $attributeType);
489 1
                                $attributeType = Properties::convertPropertyType($attributeType);
490 1
                                $docProps->setCustomProperty($propertyName, $attributeValue, $attributeType);
491
                            }
492
                        }
493
                    }
494 1
                    break;
495
                //Ribbon
496 8
                case 'http://schemas.microsoft.com/office/2006/relationships/ui/extensibility':
497
                    $customUI = $rel['Target'];
498
                    if (!is_null($customUI)) {
499
                        $this->readRibbon($excel, $customUI, $zip);
500
                    }
501
                    break;
502 8
                case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument':
503 8
                    $dir = dirname($rel['Target']);
504 8
                    $relsWorkbook = simplexml_load_string(
505
                        //~ http://schemas.openxmlformats.org/package/2006/relationships"
506 8
                        $this->securityScan($this->getFromZipArchive($zip, "$dir/_rels/" . basename($rel['Target']) . '.rels')),
507 8
                        'SimpleXMLElement',
508 8
                        Settings::getLibXmlLoaderOptions()
509
                    );
510 8
                    $relsWorkbook->registerXPathNamespace('rel', 'http://schemas.openxmlformats.org/package/2006/relationships');
511
512 8
                    $sharedStrings = [];
513 8
                    $xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings']"));
514 8
                    $xmlStrings = simplexml_load_string(
515
                        //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
516 8
                        $this->securityScan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")),
517 8
                        'SimpleXMLElement',
518 8
                        Settings::getLibXmlLoaderOptions()
519
                    );
520 8
                    if (isset($xmlStrings) && isset($xmlStrings->si)) {
521 8
                        foreach ($xmlStrings->si as $val) {
522 8
                            if (isset($val->t)) {
523 8
                                $sharedStrings[] = StringHelper::controlCharacterOOXML2PHP((string) $val->t);
524
                            } elseif (isset($val->r)) {
525 8
                                $sharedStrings[] = $this->parseRichText($val);
526
                            }
527
                        }
528
                    }
529
530 8
                    $worksheets = [];
531 8
                    $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...
532 8
                    foreach ($relsWorkbook->Relationship as $ele) {
533 8
                        switch ($ele['Type']) {
534 8
                            case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet':
535 8
                                $worksheets[(string) $ele['Id']] = $ele['Target'];
536 8
                                break;
537
                            // a vbaProject ? (: some macros)
538 8
                            case 'http://schemas.microsoft.com/office/2006/relationships/vbaProject':
539
                                $macros = $ele['Target'];
540 8
                                break;
541
                        }
542
                    }
543
544 8
                    if (!is_null($macros)) {
545
                        $macrosCode = $this->getFromZipArchive($zip, 'xl/vbaProject.bin'); //vbaProject.bin always in 'xl' dir and always named vbaProject.bin
546
                        if ($macrosCode !== false) {
547
                            $excel->setMacrosCode($macrosCode);
548
                            $excel->setHasMacros(true);
549
                            //short-circuit : not reading vbaProject.bin.rel to get Signature =>allways vbaProjectSignature.bin in 'xl' dir
550
                            $Certificate = $this->getFromZipArchive($zip, 'xl/vbaProjectSignature.bin');
551
                            if ($Certificate !== false) {
552
                                $excel->setMacrosCertificate($Certificate);
553
                            }
554
                        }
555
                    }
556 8
                    $styles = [];
557 8
                    $cellStyles = [];
558 8
                    $xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles']"));
559 8
                    $xmlStyles = simplexml_load_string(
560
                        //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
561 8
                        $this->securityScan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")),
562 8
                        'SimpleXMLElement',
563 8
                        Settings::getLibXmlLoaderOptions()
564
                    );
565 8
                    $numFmts = null;
566 8
                    if ($xmlStyles && $xmlStyles->numFmts[0]) {
567 5
                        $numFmts = $xmlStyles->numFmts[0];
568
                    }
569 8
                    if (isset($numFmts) && ($numFmts !== null)) {
570 5
                        $numFmts->registerXPathNamespace('sml', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
571
                    }
572 8
                    if (!$this->readDataOnly && $xmlStyles) {
573 8
                        foreach ($xmlStyles->cellXfs->xf as $xf) {
574 8
                            $numFmt = NumberFormat::FORMAT_GENERAL;
575
576 8
                            if ($xf['numFmtId']) {
577 8
                                if (isset($numFmts)) {
578 5
                                    $tmpNumFmt = self::getArrayItem($numFmts->xpath("sml:numFmt[@numFmtId=$xf[numFmtId]]"));
579
580 5
                                    if (isset($tmpNumFmt['formatCode'])) {
581 2
                                        $numFmt = (string) $tmpNumFmt['formatCode'];
582
                                    }
583
                                }
584
585
                                // We shouldn't override any of the built-in MS Excel values (values below id 164)
586
                                //  But there's a lot of naughty homebrew xlsx writers that do use "reserved" id values that aren't actually used
587
                                //  So we make allowance for them rather than lose formatting masks
588 8
                                if ((int) $xf['numFmtId'] < 164 &&
589 8
                                    NumberFormat::builtInFormatCode((int) $xf['numFmtId']) !== '') {
590 8
                                    $numFmt = NumberFormat::builtInFormatCode((int) $xf['numFmtId']);
591
                                }
592
                            }
593 8
                            $quotePrefix = false;
594 8
                            if (isset($xf['quotePrefix'])) {
595
                                $quotePrefix = (bool) $xf['quotePrefix'];
596
                            }
597
598
                            $style = (object) [
599 8
                                'numFmt' => $numFmt,
600 8
                                'font' => $xmlStyles->fonts->font[(int) ($xf['fontId'])],
601 8
                                'fill' => $xmlStyles->fills->fill[(int) ($xf['fillId'])],
602 8
                                'border' => $xmlStyles->borders->border[(int) ($xf['borderId'])],
603 8
                                'alignment' => $xf->alignment,
604 8
                                'protection' => $xf->protection,
605 8
                                'quotePrefix' => $quotePrefix,
606
                            ];
607 8
                            $styles[] = $style;
608
609
                            // add style to cellXf collection
610 8
                            $objStyle = new Style();
611 8
                            self::readStyle($objStyle, $style);
612 8
                            $excel->addCellXf($objStyle);
613
                        }
614
615 8
                        foreach ($xmlStyles->cellStyleXfs->xf as $xf) {
616 8
                            $numFmt = NumberFormat::FORMAT_GENERAL;
617 8
                            if ($numFmts && $xf['numFmtId']) {
618 5
                                $tmpNumFmt = self::getArrayItem($numFmts->xpath("sml:numFmt[@numFmtId=$xf[numFmtId]]"));
619 5
                                if (isset($tmpNumFmt['formatCode'])) {
620
                                    $numFmt = (string) $tmpNumFmt['formatCode'];
621 5
                                } elseif ((int) $xf['numFmtId'] < 165) {
622 5
                                    $numFmt = NumberFormat::builtInFormatCode((int) $xf['numFmtId']);
623
                                }
624
                            }
625
626
                            $cellStyle = (object) [
627 8
                                'numFmt' => $numFmt,
628 8
                                'font' => $xmlStyles->fonts->font[(int) ($xf['fontId'])],
629 8
                                'fill' => $xmlStyles->fills->fill[(int) ($xf['fillId'])],
630 8
                                'border' => $xmlStyles->borders->border[(int) ($xf['borderId'])],
631 8
                                'alignment' => $xf->alignment,
632 8
                                'protection' => $xf->protection,
633 8
                                '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...
634
                            ];
635 8
                            $cellStyles[] = $cellStyle;
636
637
                            // add style to cellStyleXf collection
638 8
                            $objStyle = new Style();
639 8
                            self::readStyle($objStyle, $cellStyle);
640 8
                            $excel->addCellStyleXf($objStyle);
641
                        }
642
                    }
643
644 8
                    $dxfs = [];
645 8
                    if (!$this->readDataOnly && $xmlStyles) {
646
                        //    Conditional Styles
647 8
                        if ($xmlStyles->dxfs) {
648 8
                            foreach ($xmlStyles->dxfs->dxf as $dxf) {
649
                                $style = new Style(false, true);
650
                                self::readStyle($style, $dxf);
651
                                $dxfs[] = $style;
652
                            }
653
                        }
654
                        //    Cell Styles
655 8
                        if ($xmlStyles->cellStyles) {
656 8
                            foreach ($xmlStyles->cellStyles->cellStyle as $cellStyle) {
657 8
                                if ((int) ($cellStyle['builtinId']) == 0) {
658 8
                                    if (isset($cellStyles[(int) ($cellStyle['xfId'])])) {
659
                                        // Set default style
660 8
                                        $style = new Style();
661 8
                                        self::readStyle($style, $cellStyles[(int) ($cellStyle['xfId'])]);
662
663
                                        // normal style, currently not using it for anything
664
                                    }
665
                                }
666
                            }
667
                        }
668
                    }
669
670 8
                    $xmlWorkbook = simplexml_load_string(
671
                        //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
672 8
                        $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")),
673 8
                        'SimpleXMLElement',
674 8
                        Settings::getLibXmlLoaderOptions()
675
                    );
676
677
                    // Set base date
678 8
                    if ($xmlWorkbook->workbookPr) {
679 8
                        Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
680 8
                        if (isset($xmlWorkbook->workbookPr['date1904'])) {
681
                            if (self::boolean((string) $xmlWorkbook->workbookPr['date1904'])) {
682
                                Date::setExcelCalendar(Date::CALENDAR_MAC_1904);
683
                            }
684
                        }
685
                    }
686
687 8
                    $sheetId = 0; // keep track of new sheet id in final workbook
688 8
                    $oldSheetId = -1; // keep track of old sheet id in final workbook
689 8
                    $countSkippedSheets = 0; // keep track of number of skipped sheets
690 8
                    $mapSheetId = []; // mapping of sheet ids from old to new
691
692 8
                    $charts = $chartDetails = [];
693
694 8
                    if ($xmlWorkbook->sheets) {
695
                        /** @var \SimpleXMLElement $eleSheet */
696 8
                        foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
697 8
                            ++$oldSheetId;
698
699
                            // Check if sheet should be skipped
700 8
                            if (isset($this->loadSheetsOnly) && !in_array((string) $eleSheet['name'], $this->loadSheetsOnly)) {
701
                                ++$countSkippedSheets;
702
                                $mapSheetId[$oldSheetId] = null;
703
                                continue;
704
                            }
705
706
                            // Map old sheet id in original workbook to new sheet id.
707
                            // They will differ if loadSheetsOnly() is being used
708 8
                            $mapSheetId[$oldSheetId] = $oldSheetId - $countSkippedSheets;
709
710
                            // Load sheet
711 8
                            $docSheet = $excel->createSheet();
712
                            //    Use false for $updateFormulaCellReferences to prevent adjustment of worksheet
713
                            //        references in formula cells... during the load, all formulae should be correct,
714
                            //        and we're simply bringing the worksheet name in line with the formula, not the
715
                            //        reverse
716 8
                            $docSheet->setTitle((string) $eleSheet['name'], false);
717 8
                            $fileWorksheet = $worksheets[(string) self::getArrayItem($eleSheet->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id')];
718 8
                            $xmlSheet = simplexml_load_string(
719
                                //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
720 8
                                $this->securityScan($this->getFromZipArchive($zip, "$dir/$fileWorksheet")),
721 8
                                'SimpleXMLElement',
722 8
                                Settings::getLibXmlLoaderOptions()
723
                            );
724
725 8
                            $sharedFormulas = [];
726
727 8
                            if (isset($eleSheet['state']) && (string) $eleSheet['state'] != '') {
728
                                $docSheet->setSheetState((string) $eleSheet['state']);
729
                            }
730
731 8
                            if (isset($xmlSheet->sheetViews) && isset($xmlSheet->sheetViews->sheetView)) {
732 8 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...
733
                                    $docSheet->getSheetView()->setZoomScale((int) ($xmlSheet->sheetViews->sheetView['zoomScale']));
734
                                }
735 8 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...
736
                                    $docSheet->getSheetView()->setZoomScaleNormal((int) ($xmlSheet->sheetViews->sheetView['zoomScaleNormal']));
737
                                }
738 8 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...
739
                                    $docSheet->getSheetView()->setView((string) $xmlSheet->sheetViews->sheetView['view']);
740
                                }
741 8 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...
742 5
                                    $docSheet->setShowGridLines(self::boolean((string) $xmlSheet->sheetViews->sheetView['showGridLines']));
743
                                }
744 8 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...
745 5
                                    $docSheet->setShowRowColHeaders(self::boolean((string) $xmlSheet->sheetViews->sheetView['showRowColHeaders']));
746
                                }
747 8 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...
748
                                    $docSheet->setRightToLeft(self::boolean((string) $xmlSheet->sheetViews->sheetView['rightToLeft']));
749
                                }
750 8
                                if (isset($xmlSheet->sheetViews->sheetView->pane)) {
751 1
                                    if (isset($xmlSheet->sheetViews->sheetView->pane['topLeftCell'])) {
752 1
                                        $docSheet->freezePane((string) $xmlSheet->sheetViews->sheetView->pane['topLeftCell']);
753
                                    } else {
754
                                        $xSplit = 0;
755
                                        $ySplit = 0;
756
757
                                        if (isset($xmlSheet->sheetViews->sheetView->pane['xSplit'])) {
758
                                            $xSplit = 1 + (int) ($xmlSheet->sheetViews->sheetView->pane['xSplit']);
759
                                        }
760
761
                                        if (isset($xmlSheet->sheetViews->sheetView->pane['ySplit'])) {
762
                                            $ySplit = 1 + (int) ($xmlSheet->sheetViews->sheetView->pane['ySplit']);
763
                                        }
764
765
                                        $docSheet->freezePaneByColumnAndRow($xSplit, $ySplit);
766
                                    }
767
                                }
768
769 8
                                if (isset($xmlSheet->sheetViews->sheetView->selection)) {
770 8
                                    if (isset($xmlSheet->sheetViews->sheetView->selection['sqref'])) {
771 8
                                        $sqref = (string) $xmlSheet->sheetViews->sheetView->selection['sqref'];
772 8
                                        $sqref = explode(' ', $sqref);
773 8
                                        $sqref = $sqref[0];
774 8
                                        $docSheet->setSelectedCells($sqref);
775
                                    }
776
                                }
777
                            }
778
779 8
                            if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr->tabColor)) {
780 2
                                if (isset($xmlSheet->sheetPr->tabColor['rgb'])) {
781 2
                                    $docSheet->getTabColor()->setARGB((string) $xmlSheet->sheetPr->tabColor['rgb']);
782
                                }
783
                            }
784 8
                            if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr['codeName'])) {
785
                                $docSheet->setCodeName((string) $xmlSheet->sheetPr['codeName']);
786
                            }
787 8
                            if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr->outlinePr)) {
788 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...
789 5
                                    !self::boolean((string) $xmlSheet->sheetPr->outlinePr['summaryRight'])) {
790
                                    $docSheet->setShowSummaryRight(false);
791
                                } else {
792 5
                                    $docSheet->setShowSummaryRight(true);
793
                                }
794
795 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...
796 5
                                    !self::boolean((string) $xmlSheet->sheetPr->outlinePr['summaryBelow'])) {
797
                                    $docSheet->setShowSummaryBelow(false);
798
                                } else {
799 5
                                    $docSheet->setShowSummaryBelow(true);
800
                                }
801
                            }
802
803 8
                            if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr->pageSetUpPr)) {
804
                                if (isset($xmlSheet->sheetPr->pageSetUpPr['fitToPage']) &&
805
                                    !self::boolean((string) $xmlSheet->sheetPr->pageSetUpPr['fitToPage'])) {
806
                                    $docSheet->getPageSetup()->setFitToPage(false);
807
                                } else {
808
                                    $docSheet->getPageSetup()->setFitToPage(true);
809
                                }
810
                            }
811
812 8
                            if (isset($xmlSheet->sheetFormatPr)) {
813 8
                                if (isset($xmlSheet->sheetFormatPr['customHeight']) &&
814 8
                                    self::boolean((string) $xmlSheet->sheetFormatPr['customHeight']) &&
815 8
                                    isset($xmlSheet->sheetFormatPr['defaultRowHeight'])) {
816
                                    $docSheet->getDefaultRowDimension()->setRowHeight((float) $xmlSheet->sheetFormatPr['defaultRowHeight']);
817
                                }
818 8
                                if (isset($xmlSheet->sheetFormatPr['defaultColWidth'])) {
819
                                    $docSheet->getDefaultColumnDimension()->setWidth((float) $xmlSheet->sheetFormatPr['defaultColWidth']);
820
                                }
821 8
                                if (isset($xmlSheet->sheetFormatPr['zeroHeight']) &&
822 8
                                    ((string) $xmlSheet->sheetFormatPr['zeroHeight'] == '1')) {
823
                                    $docSheet->getDefaultRowDimension()->setZeroHeight(true);
824
                                }
825
                            }
826
827 8
                            if (isset($xmlSheet->cols) && !$this->readDataOnly) {
828 5
                                foreach ($xmlSheet->cols->col as $col) {
829 5
                                    for ($i = (int) ($col['min']) - 1; $i < (int) ($col['max']); ++$i) {
830 5
                                        if ($col['style'] && !$this->readDataOnly) {
831 3
                                            $docSheet->getColumnDimension(Cell::stringFromColumnIndex($i))->setXfIndex((int) ($col['style']));
832
                                        }
833 5
                                        if (self::boolean($col['hidden'])) {
834 1
                                            $docSheet->getColumnDimension(Cell::stringFromColumnIndex($i))->setVisible(false);
835
                                        }
836 5
                                        if (self::boolean($col['collapsed'])) {
837 1
                                            $docSheet->getColumnDimension(Cell::stringFromColumnIndex($i))->setCollapsed(true);
838
                                        }
839 5
                                        if ($col['outlineLevel'] > 0) {
840 1
                                            $docSheet->getColumnDimension(Cell::stringFromColumnIndex($i))->setOutlineLevel((int) ($col['outlineLevel']));
841
                                        }
842 5
                                        $docSheet->getColumnDimension(Cell::stringFromColumnIndex($i))->setWidth((float) ($col['width']));
843
844 5
                                        if ((int) ($col['max']) == 16384) {
845
                                            break;
846
                                        }
847
                                    }
848
                                }
849
                            }
850
851 8
                            if (isset($xmlSheet->printOptions) && !$this->readDataOnly) {
852 5
                                if (self::boolean((string) $xmlSheet->printOptions['gridLinesSet'])) {
853 5
                                    $docSheet->setShowGridlines(true);
854
                                }
855 5
                                if (self::boolean((string) $xmlSheet->printOptions['gridLines'])) {
856
                                    $docSheet->setPrintGridlines(true);
857
                                }
858 5
                                if (self::boolean((string) $xmlSheet->printOptions['horizontalCentered'])) {
859
                                    $docSheet->getPageSetup()->setHorizontalCentered(true);
860
                                }
861 5
                                if (self::boolean((string) $xmlSheet->printOptions['verticalCentered'])) {
862
                                    $docSheet->getPageSetup()->setVerticalCentered(true);
863
                                }
864
                            }
865
866 8
                            if ($xmlSheet && $xmlSheet->sheetData && $xmlSheet->sheetData->row) {
867 8
                                foreach ($xmlSheet->sheetData->row as $row) {
868 8
                                    if ($row['ht'] && !$this->readDataOnly) {
869 1
                                        $docSheet->getRowDimension((int) ($row['r']))->setRowHeight((float) ($row['ht']));
870
                                    }
871 8
                                    if (self::boolean($row['hidden']) && !$this->readDataOnly) {
872
                                        $docSheet->getRowDimension((int) ($row['r']))->setVisible(false);
873
                                    }
874 8
                                    if (self::boolean($row['collapsed'])) {
875
                                        $docSheet->getRowDimension((int) ($row['r']))->setCollapsed(true);
876
                                    }
877 8
                                    if ($row['outlineLevel'] > 0) {
878
                                        $docSheet->getRowDimension((int) ($row['r']))->setOutlineLevel((int) ($row['outlineLevel']));
879
                                    }
880 8
                                    if ($row['s'] && !$this->readDataOnly) {
881
                                        $docSheet->getRowDimension((int) ($row['r']))->setXfIndex((int) ($row['s']));
882
                                    }
883
884 8
                                    foreach ($row->c as $c) {
885 8
                                        $r = (string) $c['r'];
886 8
                                        $cellDataType = (string) $c['t'];
887 8
                                        $value = null;
888 8
                                        $calculatedValue = null;
889
890
                                        // Read cell?
891 8
                                        if ($this->getReadFilter() !== null) {
892 8
                                            $coordinates = Cell::coordinateFromString($r);
893
894 8
                                            if (!$this->getReadFilter()->readCell($coordinates[0], $coordinates[1], $docSheet->getTitle())) {
895 1
                                                continue;
896
                                            }
897
                                        }
898
899
                                        // Read cell!
900
                                        switch ($cellDataType) {
901 8
                                            case 's':
902 8
                                                if ((string) $c->v != '') {
903 8
                                                    $value = $sharedStrings[(int) ($c->v)];
904
905 8
                                                    if ($value instanceof RichText) {
906 8
                                                        $value = clone $value;
907
                                                    }
908
                                                } else {
909
                                                    $value = '';
910
                                                }
911 8
                                                break;
912 6
                                            case 'b':
913 1
                                                if (!isset($c->f)) {
914 1
                                                    $value = self::castToBoolean($c);
915
                                                } else {
916
                                                    // Formula
917
                                                    $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToBoolean');
918
                                                    if (isset($c->f['t'])) {
919
                                                        $att = [];
0 ignored issues
show
Unused Code introduced by
$att is not used, you could remove the assignment.

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

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

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

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

Loading history...
920
                                                        $att = $c->f;
921
                                                        $docSheet->getCell($r)->setFormulaAttributes($att);
922
                                                    }
923
                                                }
924 1
                                                break;
925 5 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...
926 2
                                                if (isset($c->f)) {
927
                                                    $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToError');
928
                                                } else {
929 2
                                                    $value = $this->parseRichText($c->is);
930
                                                }
931 2
                                                break;
932 5 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...
933
                                                if (!isset($c->f)) {
934
                                                    $value = self::castToError($c);
935
                                                } else {
936
                                                    // Formula
937
                                                    $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToError');
938
                                                }
939
                                                break;
940
                                            default:
941 5
                                                if (!isset($c->f)) {
942 5
                                                    $value = self::castToString($c);
943
                                                } else {
944
                                                    // Formula
945 3
                                                    $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToString');
946
                                                }
947 5
                                                break;
948
                                        }
949
950
                                        // Check for numeric values
951 8
                                        if (is_numeric($value) && $cellDataType != 's') {
952 5
                                            if ($value == (int) $value) {
953 5
                                                $value = (int) $value;
954
                                            } elseif ($value == (float) $value) {
955
                                                $value = (float) $value;
956
                                            } elseif ($value == (float) $value) {
957
                                                $value = (float) $value;
958
                                            }
959
                                        }
960
961
                                        // Rich text?
962 8
                                        if ($value instanceof RichText && $this->readDataOnly) {
963
                                            $value = $value->getPlainText();
964
                                        }
965
966 8
                                        $cell = $docSheet->getCell($r);
967
                                        // Assign value
968 8
                                        if ($cellDataType != '') {
969 8
                                            $cell->setValueExplicit($value, $cellDataType);
970
                                        } else {
971 5
                                            $cell->setValue($value);
972
                                        }
973 8
                                        if ($calculatedValue !== null) {
974 3
                                            $cell->setCalculatedValue($calculatedValue);
975
                                        }
976
977
                                        // Style information?
978 8
                                        if ($c['s'] && !$this->readDataOnly) {
979
                                            // no style index means 0, it seems
980 5
                                            $cell->setXfIndex(isset($styles[(int) ($c['s'])]) ?
981 8
                                                (int) ($c['s']) : 0);
982
                                        }
983
                                    }
984
                                }
985
                            }
986
987 8
                            $conditionals = [];
988 8
                            if (!$this->readDataOnly && $xmlSheet && $xmlSheet->conditionalFormatting) {
989
                                foreach ($xmlSheet->conditionalFormatting as $conditional) {
990
                                    foreach ($conditional->cfRule as $cfRule) {
991
                                        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'])])) {
992
                                            $conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule;
993
                                        }
994
                                    }
995
                                }
996
997
                                foreach ($conditionals as $ref => $cfRules) {
998
                                    ksort($cfRules);
999
                                    $conditionalStyles = [];
1000
                                    foreach ($cfRules as $cfRule) {
1001
                                        $objConditional = new Style\Conditional();
1002
                                        $objConditional->setConditionType((string) $cfRule['type']);
1003
                                        $objConditional->setOperatorType((string) $cfRule['operator']);
1004
1005
                                        if ((string) $cfRule['text'] != '') {
1006
                                            $objConditional->setText((string) $cfRule['text']);
1007
                                        }
1008
1009
                                        if (count($cfRule->formula) > 1) {
1010
                                            foreach ($cfRule->formula as $formula) {
1011
                                                $objConditional->addCondition((string) $formula);
1012
                                            }
1013
                                        } else {
1014
                                            $objConditional->addCondition((string) $cfRule->formula);
1015
                                        }
1016
                                        $objConditional->setStyle(clone $dxfs[(int) ($cfRule['dxfId'])]);
1017
                                        $conditionalStyles[] = $objConditional;
1018
                                    }
1019
1020
                                    // Extract all cell references in $ref
1021
                                    $cellBlocks = explode(' ', str_replace('$', '', strtoupper($ref)));
1022
                                    foreach ($cellBlocks as $cellBlock) {
1023
                                        $docSheet->getStyle($cellBlock)->setConditionalStyles($conditionalStyles);
1024
                                    }
1025
                                }
1026
                            }
1027
1028 8
                            $aKeys = ['sheet', 'objects', 'scenarios', 'formatCells', 'formatColumns', 'formatRows', 'insertColumns', 'insertRows', 'insertHyperlinks', 'deleteColumns', 'deleteRows', 'selectLockedCells', 'sort', 'autoFilter', 'pivotTables', 'selectUnlockedCells'];
1029 8
                            if (!$this->readDataOnly && $xmlSheet && $xmlSheet->sheetProtection) {
1030 5
                                foreach ($aKeys as $key) {
1031 5
                                    $method = 'set' . ucfirst($key);
1032 5
                                    $docSheet->getProtection()->$method(self::boolean((string) $xmlSheet->sheetProtection[$key]));
1033
                                }
1034
                            }
1035
1036 8
                            if (!$this->readDataOnly && $xmlSheet && $xmlSheet->sheetProtection) {
1037 5
                                $docSheet->getProtection()->setPassword((string) $xmlSheet->sheetProtection['password'], true);
1038 5
                                if ($xmlSheet->protectedRanges->protectedRange) {
1039 2
                                    foreach ($xmlSheet->protectedRanges->protectedRange as $protectedRange) {
1040 2
                                        $docSheet->protectCells((string) $protectedRange['sqref'], (string) $protectedRange['password'], true);
1041
                                    }
1042
                                }
1043
                            }
1044
1045 8
                            if ($xmlSheet && $xmlSheet->autoFilter && !$this->readDataOnly) {
1046
                                $autoFilterRange = (string) $xmlSheet->autoFilter['ref'];
1047
                                if (strpos($autoFilterRange, ':') !== false) {
1048
                                    $autoFilter = $docSheet->getAutoFilter();
1049
                                    $autoFilter->setRange($autoFilterRange);
1050
1051
                                    foreach ($xmlSheet->autoFilter->filterColumn as $filterColumn) {
1052
                                        $column = $autoFilter->getColumnByOffset((int) $filterColumn['colId']);
1053
                                        //    Check for standard filters
1054
                                        if ($filterColumn->filters) {
1055
                                            $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER);
1056
                                            $filters = $filterColumn->filters;
1057
                                            if ((isset($filters['blank'])) && ($filters['blank'] == 1)) {
1058
                                                //    Operator is undefined, but always treated as EQUAL
1059
                                                $column->createRule()->setRule(null, '')->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_FILTER);
1060
                                            }
1061
                                            //    Standard filters are always an OR join, so no join rule needs to be set
1062
                                            //    Entries can be either filter elements
1063 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...
1064
                                                //    Operator is undefined, but always treated as EQUAL
1065
                                                $column->createRule()->setRule(null, (string) $filterRule['val'])->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_FILTER);
1066
                                            }
1067
                                            //    Or Date Group elements
1068
                                            foreach ($filters->dateGroupItem as $dateGroupItem) {
1069
                                                $column->createRule()->setRule(
1070
                                                    //    Operator is undefined, but always treated as EQUAL
1071
                                                    null,
1072
                                                    [
1073
                                                        'year' => (string) $dateGroupItem['year'],
1074
                                                        'month' => (string) $dateGroupItem['month'],
1075
                                                        'day' => (string) $dateGroupItem['day'],
1076
                                                        'hour' => (string) $dateGroupItem['hour'],
1077
                                                        'minute' => (string) $dateGroupItem['minute'],
1078
                                                        'second' => (string) $dateGroupItem['second'],
1079
                                                    ],
1080
                                                    (string) $dateGroupItem['dateTimeGrouping']
1081
                                                )
1082
                                                ->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP);
1083
                                            }
1084
                                        }
1085
                                        //    Check for custom filters
1086
                                        if ($filterColumn->customFilters) {
1087
                                            $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_CUSTOMFILTER);
1088
                                            $customFilters = $filterColumn->customFilters;
1089
                                            //    Custom filters can an AND or an OR join;
1090
                                            //        and there should only ever be one or two entries
1091
                                            if ((isset($customFilters['and'])) && ($customFilters['and'] == 1)) {
1092
                                                $column->setJoin(Column::AUTOFILTER_COLUMN_JOIN_AND);
1093
                                            }
1094 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...
1095
                                                $column->createRule()->setRule(
1096
                                                    (string) $filterRule['operator'],
1097
                                                    (string) $filterRule['val']
1098
                                                )
1099
                                                ->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER);
1100
                                            }
1101
                                        }
1102
                                        //    Check for dynamic filters
1103
                                        if ($filterColumn->dynamicFilter) {
1104
                                            $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER);
1105
                                            //    We should only ever have one dynamic filter
1106
                                            foreach ($filterColumn->dynamicFilter as $filterRule) {
1107
                                                $column->createRule()->setRule(
1108
                                                    //    Operator is undefined, but always treated as EQUAL
1109
                                                    null,
1110
                                                    (string) $filterRule['val'],
1111
                                                    (string) $filterRule['type']
1112
                                                )
1113
                                                ->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER);
1114
                                                if (isset($filterRule['val'])) {
1115
                                                    $column->setAttribute('val', (string) $filterRule['val']);
1116
                                                }
1117
                                                if (isset($filterRule['maxVal'])) {
1118
                                                    $column->setAttribute('maxVal', (string) $filterRule['maxVal']);
1119
                                                }
1120
                                            }
1121
                                        }
1122
                                        //    Check for dynamic filters
1123
                                        if ($filterColumn->top10) {
1124
                                            $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_TOPTENFILTER);
1125
                                            //    We should only ever have one top10 filter
1126
                                            foreach ($filterColumn->top10 as $filterRule) {
1127
                                                $column->createRule()->setRule(
1128
                                                    (((isset($filterRule['percent'])) && ($filterRule['percent'] == 1))
1129
                                                        ? Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT
1130
                                                        : Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE
1131
                                                    ),
1132
                                                    (string) $filterRule['val'],
1133
                                                    (((isset($filterRule['top'])) && ($filterRule['top'] == 1))
1134
                                                        ? Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP
1135
                                                        : Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM
1136
                                                    )
1137
                                                )
1138
                                                ->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_TOPTENFILTER);
1139
                                            }
1140
                                        }
1141
                                    }
1142
                                }
1143
                            }
1144
1145 8
                            if ($xmlSheet && $xmlSheet->mergeCells && $xmlSheet->mergeCells->mergeCell && !$this->readDataOnly) {
1146 4
                                foreach ($xmlSheet->mergeCells->mergeCell as $mergeCell) {
1147 4
                                    $mergeRef = (string) $mergeCell['ref'];
1148 4
                                    if (strpos($mergeRef, ':') !== false) {
1149 4
                                        $docSheet->mergeCells((string) $mergeCell['ref']);
1150
                                    }
1151
                                }
1152
                            }
1153
1154 8
                            if ($xmlSheet && $xmlSheet->pageMargins && !$this->readDataOnly) {
1155 8
                                $docPageMargins = $docSheet->getPageMargins();
1156 8
                                $docPageMargins->setLeft((float) ($xmlSheet->pageMargins['left']));
1157 8
                                $docPageMargins->setRight((float) ($xmlSheet->pageMargins['right']));
1158 8
                                $docPageMargins->setTop((float) ($xmlSheet->pageMargins['top']));
1159 8
                                $docPageMargins->setBottom((float) ($xmlSheet->pageMargins['bottom']));
1160 8
                                $docPageMargins->setHeader((float) ($xmlSheet->pageMargins['header']));
1161 8
                                $docPageMargins->setFooter((float) ($xmlSheet->pageMargins['footer']));
1162
                            }
1163
1164 8
                            if ($xmlSheet && $xmlSheet->pageSetup && !$this->readDataOnly) {
1165 8
                                $docPageSetup = $docSheet->getPageSetup();
1166
1167 8
                                if (isset($xmlSheet->pageSetup['orientation'])) {
1168 8
                                    $docPageSetup->setOrientation((string) $xmlSheet->pageSetup['orientation']);
1169
                                }
1170 8
                                if (isset($xmlSheet->pageSetup['paperSize'])) {
1171 8
                                    $docPageSetup->setPaperSize((int) ($xmlSheet->pageSetup['paperSize']));
1172
                                }
1173 8
                                if (isset($xmlSheet->pageSetup['scale'])) {
1174 5
                                    $docPageSetup->setScale((int) ($xmlSheet->pageSetup['scale']), false);
1175
                                }
1176 8 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...
1177 5
                                    $docPageSetup->setFitToHeight((int) ($xmlSheet->pageSetup['fitToHeight']), false);
1178
                                }
1179 8 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...
1180 5
                                    $docPageSetup->setFitToWidth((int) ($xmlSheet->pageSetup['fitToWidth']), false);
1181
                                }
1182 8
                                if (isset($xmlSheet->pageSetup['firstPageNumber']) && isset($xmlSheet->pageSetup['useFirstPageNumber']) &&
1183 8
                                    self::boolean((string) $xmlSheet->pageSetup['useFirstPageNumber'])) {
1184
                                    $docPageSetup->setFirstPageNumber((int) ($xmlSheet->pageSetup['firstPageNumber']));
1185
                                }
1186
                            }
1187
1188 8
                            if ($xmlSheet && $xmlSheet->headerFooter && !$this->readDataOnly) {
1189 5
                                $docHeaderFooter = $docSheet->getHeaderFooter();
1190
1191 5 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...
1192 5
                                    self::boolean((string) $xmlSheet->headerFooter['differentOddEven'])) {
1193
                                    $docHeaderFooter->setDifferentOddEven(true);
1194
                                } else {
1195 5
                                    $docHeaderFooter->setDifferentOddEven(false);
1196
                                }
1197 5 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...
1198 5
                                    self::boolean((string) $xmlSheet->headerFooter['differentFirst'])) {
1199
                                    $docHeaderFooter->setDifferentFirst(true);
1200
                                } else {
1201 5
                                    $docHeaderFooter->setDifferentFirst(false);
1202
                                }
1203 5 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...
1204 5
                                    !self::boolean((string) $xmlSheet->headerFooter['scaleWithDoc'])) {
1205
                                    $docHeaderFooter->setScaleWithDocument(false);
1206
                                } else {
1207 5
                                    $docHeaderFooter->setScaleWithDocument(true);
1208
                                }
1209 5 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...
1210 5
                                    !self::boolean((string) $xmlSheet->headerFooter['alignWithMargins'])) {
1211 1
                                    $docHeaderFooter->setAlignWithMargins(false);
1212
                                } else {
1213 4
                                    $docHeaderFooter->setAlignWithMargins(true);
1214
                                }
1215
1216 5
                                $docHeaderFooter->setOddHeader((string) $xmlSheet->headerFooter->oddHeader);
1217 5
                                $docHeaderFooter->setOddFooter((string) $xmlSheet->headerFooter->oddFooter);
1218 5
                                $docHeaderFooter->setEvenHeader((string) $xmlSheet->headerFooter->evenHeader);
1219 5
                                $docHeaderFooter->setEvenFooter((string) $xmlSheet->headerFooter->evenFooter);
1220 5
                                $docHeaderFooter->setFirstHeader((string) $xmlSheet->headerFooter->firstHeader);
1221 5
                                $docHeaderFooter->setFirstFooter((string) $xmlSheet->headerFooter->firstFooter);
1222
                            }
1223
1224 8
                            if ($xmlSheet && $xmlSheet->rowBreaks && $xmlSheet->rowBreaks->brk && !$this->readDataOnly) {
1225
                                foreach ($xmlSheet->rowBreaks->brk as $brk) {
1226
                                    if ($brk['man']) {
1227
                                        $docSheet->setBreak("A$brk[id]", Worksheet::BREAK_ROW);
1228
                                    }
1229
                                }
1230
                            }
1231 8
                            if ($xmlSheet && $xmlSheet->colBreaks && $xmlSheet->colBreaks->brk && !$this->readDataOnly) {
1232
                                foreach ($xmlSheet->colBreaks->brk as $brk) {
1233
                                    if ($brk['man']) {
1234
                                        $docSheet->setBreak(Cell::stringFromColumnIndex((string) $brk['id']) . '1', Worksheet::BREAK_COLUMN);
1235
                                    }
1236
                                }
1237
                            }
1238
1239 8
                            if ($xmlSheet && $xmlSheet->dataValidations && !$this->readDataOnly) {
1240
                                foreach ($xmlSheet->dataValidations->dataValidation as $dataValidation) {
1241
                                    // Uppercase coordinate
1242
                                    $range = strtoupper($dataValidation['sqref']);
1243
                                    $rangeSet = explode(' ', $range);
1244
                                    foreach ($rangeSet as $range) {
1245
                                        $stRange = $docSheet->shrinkRangeToFit($range);
1246
1247
                                        // Extract all cell references in $range
1248
                                        foreach (Cell::extractAllCellReferencesInRange($stRange) as $reference) {
1249
                                            // Create validation
1250
                                            $docValidation = $docSheet->getCell($reference)->getDataValidation();
1251
                                            $docValidation->setType((string) $dataValidation['type']);
1252
                                            $docValidation->setErrorStyle((string) $dataValidation['errorStyle']);
1253
                                            $docValidation->setOperator((string) $dataValidation['operator']);
1254
                                            $docValidation->setAllowBlank($dataValidation['allowBlank'] != 0);
1255
                                            $docValidation->setShowDropDown($dataValidation['showDropDown'] == 0);
1256
                                            $docValidation->setShowInputMessage($dataValidation['showInputMessage'] != 0);
1257
                                            $docValidation->setShowErrorMessage($dataValidation['showErrorMessage'] != 0);
1258
                                            $docValidation->setErrorTitle((string) $dataValidation['errorTitle']);
1259
                                            $docValidation->setError((string) $dataValidation['error']);
1260
                                            $docValidation->setPromptTitle((string) $dataValidation['promptTitle']);
1261
                                            $docValidation->setPrompt((string) $dataValidation['prompt']);
1262
                                            $docValidation->setFormula1((string) $dataValidation->formula1);
1263
                                            $docValidation->setFormula2((string) $dataValidation->formula2);
1264
                                        }
1265
                                    }
1266
                                }
1267
                            }
1268
1269
                            // Add hyperlinks
1270 8
                            $hyperlinks = [];
1271 8
                            if (!$this->readDataOnly) {
1272
                                // Locate hyperlink relations
1273 8
                                if ($zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
1274 8
                                    $relsWorksheet = simplexml_load_string(
1275
                                        //~ http://schemas.openxmlformats.org/package/2006/relationships"
1276 8
                                        $this->securityScan(
1277 8
                                            $this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
1278
                                        ),
1279 8
                                        'SimpleXMLElement',
1280 8
                                        Settings::getLibXmlLoaderOptions()
1281
                                    );
1282 8
                                    foreach ($relsWorksheet->Relationship as $ele) {
1283 5
                                        if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink') {
1284 5
                                            $hyperlinks[(string) $ele['Id']] = (string) $ele['Target'];
1285
                                        }
1286
                                    }
1287
                                }
1288
1289
                                // Loop through hyperlinks
1290 8
                                if ($xmlSheet && $xmlSheet->hyperlinks) {
1291
                                    /** @var \SimpleXMLElement $hyperlink */
1292 2
                                    foreach ($xmlSheet->hyperlinks->hyperlink as $hyperlink) {
1293
                                        // Link url
1294 2
                                        $linkRel = $hyperlink->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships');
1295
1296 2
                                        foreach (Cell::extractAllCellReferencesInRange($hyperlink['ref']) as $cellReference) {
1297 2
                                            $cell = $docSheet->getCell($cellReference);
1298 2
                                            if (isset($linkRel['id'])) {
1299 2
                                                $hyperlinkUrl = $hyperlinks[(string) $linkRel['id']];
1300 2
                                                if (isset($hyperlink['location'])) {
1301
                                                    $hyperlinkUrl .= '#' . (string) $hyperlink['location'];
1302
                                                }
1303 2
                                                $cell->getHyperlink()->setUrl($hyperlinkUrl);
1304 2
                                            } elseif (isset($hyperlink['location'])) {
1305 2
                                                $cell->getHyperlink()->setUrl('sheet://' . (string) $hyperlink['location']);
1306
                                            }
1307
1308
                                            // Tooltip
1309 2
                                            if (isset($hyperlink['tooltip'])) {
1310 2
                                                $cell->getHyperlink()->setTooltip((string) $hyperlink['tooltip']);
1311
                                            }
1312
                                        }
1313
                                    }
1314
                                }
1315
                            }
1316
1317
                            // Add comments
1318 8
                            $comments = [];
1319 8
                            $vmlComments = [];
1320 8
                            if (!$this->readDataOnly) {
1321
                                // Locate comment relations
1322 8
                                if ($zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
1323 8
                                    $relsWorksheet = simplexml_load_string(
1324
                                        //~ http://schemas.openxmlformats.org/package/2006/relationships"
1325 8
                                        $this->securityScan(
1326 8
                                            $this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
1327
                                        ),
1328 8
                                        'SimpleXMLElement',
1329 8
                                        Settings::getLibXmlLoaderOptions()
1330
                                    );
1331 8
                                    foreach ($relsWorksheet->Relationship as $ele) {
1332 5
                                        if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments') {
1333 2
                                            $comments[(string) $ele['Id']] = (string) $ele['Target'];
1334
                                        }
1335 5
                                        if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing') {
1336 5
                                            $vmlComments[(string) $ele['Id']] = (string) $ele['Target'];
1337
                                        }
1338
                                    }
1339
                                }
1340
1341
                                // Loop through comments
1342 8
                                foreach ($comments as $relName => $relPath) {
1343
                                    // Load comments file
1344 2
                                    $relPath = File::realpath(dirname("$dir/$fileWorksheet") . '/' . $relPath);
1345 2
                                    $commentsFile = simplexml_load_string(
1346 2
                                        $this->securityScan($this->getFromZipArchive($zip, $relPath)),
1347 2
                                        'SimpleXMLElement',
1348 2
                                        Settings::getLibXmlLoaderOptions()
1349
                                    );
1350
1351
                                    // Utility variables
1352 2
                                    $authors = [];
1353
1354
                                    // Loop through authors
1355 2
                                    foreach ($commentsFile->authors->author as $author) {
1356 2
                                        $authors[] = (string) $author;
1357
                                    }
1358
1359
                                    // Loop through contents
1360 2
                                    foreach ($commentsFile->commentList->comment as $comment) {
1361 2
                                        if (!empty($comment['authorId'])) {
1362
                                            $docSheet->getComment((string) $comment['ref'])->setAuthor($authors[(string) $comment['authorId']]);
1363
                                        }
1364 2
                                        $docSheet->getComment((string) $comment['ref'])->setText($this->parseRichText($comment->text));
1365
                                    }
1366
                                }
1367
1368
                                // Loop through VML comments
1369 8
                                foreach ($vmlComments as $relName => $relPath) {
1370
                                    // Load VML comments file
1371 2
                                    $relPath = File::realpath(dirname("$dir/$fileWorksheet") . '/' . $relPath);
1372 2
                                    $vmlCommentsFile = simplexml_load_string(
1373 2
                                        $this->securityScan($this->getFromZipArchive($zip, $relPath)),
1374 2
                                        'SimpleXMLElement',
1375 2
                                        Settings::getLibXmlLoaderOptions()
1376
                                    );
1377 2
                                    $vmlCommentsFile->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
1378
1379 2
                                    $shapes = $vmlCommentsFile->xpath('//v:shape');
1380 2
                                    foreach ($shapes as $shape) {
1381 2
                                        $shape->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
1382
1383 2
                                        if (isset($shape['style'])) {
1384 2
                                            $style = (string) $shape['style'];
1385 2
                                            $fillColor = strtoupper(substr((string) $shape['fillcolor'], 1));
1386 2
                                            $column = null;
1387 2
                                            $row = null;
1388
1389 2
                                            $clientData = $shape->xpath('.//x:ClientData');
1390 2
                                            if (is_array($clientData) && !empty($clientData)) {
1391 2
                                                $clientData = $clientData[0];
1392
1393 2
                                                if (isset($clientData['ObjectType']) && (string) $clientData['ObjectType'] == 'Note') {
1394 2
                                                    $temp = $clientData->xpath('.//x:Row');
1395 2
                                                    if (is_array($temp)) {
1396 2
                                                        $row = $temp[0];
1397
                                                    }
1398
1399 2
                                                    $temp = $clientData->xpath('.//x:Column');
1400 2
                                                    if (is_array($temp)) {
1401 2
                                                        $column = $temp[0];
1402
                                                    }
1403
                                                }
1404
                                            }
1405
1406 2
                                            if (($column !== null) && ($row !== null)) {
1407
                                                // Set comment properties
1408 2
                                                $comment = $docSheet->getCommentByColumnAndRow((string) $column, $row + 1);
1409 2
                                                $comment->getFillColor()->setRGB($fillColor);
1410
1411
                                                // Parse style
1412 2
                                                $styleArray = explode(';', str_replace(' ', '', $style));
1413 2
                                                foreach ($styleArray as $stylePair) {
1414 2
                                                    $stylePair = explode(':', $stylePair);
1415
1416 2
                                                    if ($stylePair[0] == 'margin-left') {
1417 2
                                                        $comment->setMarginLeft($stylePair[1]);
1418
                                                    }
1419 2
                                                    if ($stylePair[0] == 'margin-top') {
1420 2
                                                        $comment->setMarginTop($stylePair[1]);
1421
                                                    }
1422 2
                                                    if ($stylePair[0] == 'width') {
1423 2
                                                        $comment->setWidth($stylePair[1]);
1424
                                                    }
1425 2
                                                    if ($stylePair[0] == 'height') {
1426 2
                                                        $comment->setHeight($stylePair[1]);
1427
                                                    }
1428 2
                                                    if ($stylePair[0] == 'visibility') {
1429 2
                                                        $comment->setVisible($stylePair[1] == 'visible');
1430
                                                    }
1431
                                                }
1432
                                            }
1433
                                        }
1434
                                    }
1435
                                }
1436
1437
                                // Header/footer images
1438 8
                                if ($xmlSheet && $xmlSheet->legacyDrawingHF && !$this->readDataOnly) {
1439
                                    if ($zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
1440
                                        $relsWorksheet = simplexml_load_string(
1441
                                            //~ http://schemas.openxmlformats.org/package/2006/relationships"
1442
                                            $this->securityScan(
1443
                                                $this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
1444
                                            ),
1445
                                            'SimpleXMLElement',
1446
                                            Settings::getLibXmlLoaderOptions()
1447
                                        );
1448
                                        $vmlRelationship = '';
1449
1450
                                        foreach ($relsWorksheet->Relationship as $ele) {
1451
                                            if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing') {
1452
                                                $vmlRelationship = self::dirAdd("$dir/$fileWorksheet", $ele['Target']);
1453
                                            }
1454
                                        }
1455
1456
                                        if ($vmlRelationship != '') {
1457
                                            // Fetch linked images
1458
                                            $relsVML = simplexml_load_string(
1459
                                                //~ http://schemas.openxmlformats.org/package/2006/relationships"
1460
                                                $this->securityScan(
1461
                                                    $this->getFromZipArchive($zip, dirname($vmlRelationship) . '/_rels/' . basename($vmlRelationship) . '.rels')
1462
                                                ),
1463
                                                'SimpleXMLElement',
1464
                                                Settings::getLibXmlLoaderOptions()
1465
                                            );
1466
                                            $drawings = [];
1467 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...
1468
                                                if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') {
1469
                                                    $drawings[(string) $ele['Id']] = self::dirAdd($vmlRelationship, $ele['Target']);
1470
                                                }
1471
                                            }
1472
1473
                                            // Fetch VML document
1474
                                            $vmlDrawing = simplexml_load_string(
1475
                                                $this->securityScan($this->getFromZipArchive($zip, $vmlRelationship)),
1476
                                                'SimpleXMLElement',
1477
                                                Settings::getLibXmlLoaderOptions()
1478
                                            );
1479
                                            $vmlDrawing->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
1480
1481
                                            $hfImages = [];
1482
1483
                                            $shapes = $vmlDrawing->xpath('//v:shape');
1484
                                            foreach ($shapes as $idx => $shape) {
1485
                                                $shape->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
1486
                                                $imageData = $shape->xpath('//v:imagedata');
1487
1488
                                                if (!$imageData) {
1489
                                                    continue;
1490
                                                }
1491
1492
                                                $imageData = $imageData[$idx];
1493
1494
                                                $imageData = $imageData->attributes('urn:schemas-microsoft-com:office:office');
1495
                                                $style = self::toCSSArray((string) $shape['style']);
1496
1497
                                                $hfImages[(string) $shape['id']] = new Worksheet\HeaderFooterDrawing();
1498
                                                if (isset($imageData['title'])) {
1499
                                                    $hfImages[(string) $shape['id']]->setName((string) $imageData['title']);
1500
                                                }
1501
1502
                                                $hfImages[(string) $shape['id']]->setPath('zip://' . File::realpath($pFilename) . '#' . $drawings[(string) $imageData['relid']], false);
1503
                                                $hfImages[(string) $shape['id']]->setResizeProportional(false);
1504
                                                $hfImages[(string) $shape['id']]->setWidth($style['width']);
1505
                                                $hfImages[(string) $shape['id']]->setHeight($style['height']);
1506
                                                if (isset($style['margin-left'])) {
1507
                                                    $hfImages[(string) $shape['id']]->setOffsetX($style['margin-left']);
1508
                                                }
1509
                                                $hfImages[(string) $shape['id']]->setOffsetY($style['margin-top']);
1510
                                                $hfImages[(string) $shape['id']]->setResizeProportional(true);
1511
                                            }
1512
1513
                                            $docSheet->getHeaderFooter()->setImages($hfImages);
1514
                                        }
1515
                                    }
1516
                                }
1517
                            }
1518
1519
                            // TODO: Autoshapes from twoCellAnchors!
1520 8
                            if ($zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
1521 8
                                $relsWorksheet = simplexml_load_string(
1522
                                    //~ http://schemas.openxmlformats.org/package/2006/relationships"
1523 8
                                    $this->securityScan(
1524 8
                                        $this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
1525
                                    ),
1526 8
                                    'SimpleXMLElement',
1527 8
                                    Settings::getLibXmlLoaderOptions()
1528
                                );
1529 8
                                $drawings = [];
1530 8 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...
1531 5
                                    if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing') {
1532 5
                                        $drawings[(string) $ele['Id']] = self::dirAdd("$dir/$fileWorksheet", $ele['Target']);
1533
                                    }
1534
                                }
1535 8
                                if ($xmlSheet->drawing && !$this->readDataOnly) {
1536 3
                                    foreach ($xmlSheet->drawing as $drawing) {
1537 3
                                        $fileDrawing = $drawings[(string) self::getArrayItem($drawing->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id')];
1538 3
                                        $relsDrawing = simplexml_load_string(
1539
                                            //~ http://schemas.openxmlformats.org/package/2006/relationships"
1540 3
                                            $this->securityScan(
1541 3
                                                $this->getFromZipArchive($zip, dirname($fileDrawing) . '/_rels/' . basename($fileDrawing) . '.rels')
1542
                                            ),
1543 3
                                            'SimpleXMLElement',
1544 3
                                            Settings::getLibXmlLoaderOptions()
1545
                                        );
1546 3
                                        $images = [];
1547
1548 3
                                        if ($relsDrawing && $relsDrawing->Relationship) {
1549 3
                                            foreach ($relsDrawing->Relationship as $ele) {
1550 3
                                                if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') {
1551 3
                                                    $images[(string) $ele['Id']] = self::dirAdd($fileDrawing, $ele['Target']);
1552 1
                                                } elseif ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart') {
1553 1
                                                    if ($this->includeCharts) {
1554 1
                                                        $charts[self::dirAdd($fileDrawing, $ele['Target'])] = [
1555 1
                                                            'id' => (string) $ele['Id'],
1556 3
                                                            'sheet' => $docSheet->getTitle(),
1557
                                                        ];
1558
                                                    }
1559
                                                }
1560
                                            }
1561
                                        }
1562 3
                                        $xmlDrawing = simplexml_load_string(
1563 3
                                            $this->securityScan($this->getFromZipArchive($zip, $fileDrawing)),
1564 3
                                            'SimpleXMLElement',
1565 3
                                            Settings::getLibXmlLoaderOptions()
1566 3
                                        )->children('http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing');
1567
1568 3
                                        if ($xmlDrawing->oneCellAnchor) {
1569 2
                                            foreach ($xmlDrawing->oneCellAnchor as $oneCellAnchor) {
1570 2
                                                if ($oneCellAnchor->pic->blipFill) {
1571
                                                    /** @var \SimpleXMLElement $blip */
1572 2
                                                    $blip = $oneCellAnchor->pic->blipFill->children('http://schemas.openxmlformats.org/drawingml/2006/main')->blip;
1573
                                                    /** @var \SimpleXMLElement $xfrm */
1574 2
                                                    $xfrm = $oneCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->xfrm;
1575
                                                    /** @var \SimpleXMLElement $outerShdw */
1576 2
                                                    $outerShdw = $oneCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->effectLst->outerShdw;
1577 2
                                                    $objDrawing = new Worksheet\Drawing();
1578 2
                                                    $objDrawing->setName((string) self::getArrayItem($oneCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'name'));
1579 2
                                                    $objDrawing->setDescription((string) self::getArrayItem($oneCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'descr'));
1580 2
                                                    $objDrawing->setPath(
1581 2
                                                        'zip://' . File::realpath($pFilename) . '#' .
1582 2
                                                        $images[(string) self::getArrayItem(
1583 2
                                                            $blip->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'),
1584 2
                                                            'embed'
1585
                                                        )],
1586 2
                                                        false
1587
                                                    );
1588 2
                                                    $objDrawing->setCoordinates(Cell::stringFromColumnIndex((string) $oneCellAnchor->from->col) . ($oneCellAnchor->from->row + 1));
1589 2
                                                    $objDrawing->setOffsetX(Drawing::EMUToPixels($oneCellAnchor->from->colOff));
1590 2
                                                    $objDrawing->setOffsetY(Drawing::EMUToPixels($oneCellAnchor->from->rowOff));
1591 2
                                                    $objDrawing->setResizeProportional(false);
1592 2
                                                    $objDrawing->setWidth(Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), 'cx')));
1593 2
                                                    $objDrawing->setHeight(Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), 'cy')));
1594 2
                                                    if ($xfrm) {
1595 2
                                                        $objDrawing->setRotation(Drawing::angleToDegrees(self::getArrayItem($xfrm->attributes(), 'rot')));
1596
                                                    }
1597 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...
1598 2
                                                        $shadow = $objDrawing->getShadow();
1599 2
                                                        $shadow->setVisible(true);
1600 2
                                                        $shadow->setBlurRadius(Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), 'blurRad')));
1601 2
                                                        $shadow->setDistance(Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), 'dist')));
1602 2
                                                        $shadow->setDirection(Drawing::angleToDegrees(self::getArrayItem($outerShdw->attributes(), 'dir')));
1603 2
                                                        $shadow->setAlignment((string) self::getArrayItem($outerShdw->attributes(), 'algn'));
1604 2
                                                        $shadow->getColor()->setRGB(self::getArrayItem($outerShdw->srgbClr->attributes(), 'val'));
1605 2
                                                        $shadow->setAlpha(self::getArrayItem($outerShdw->srgbClr->alpha->attributes(), 'val') / 1000);
1606
                                                    }
1607 2
                                                    $objDrawing->setWorksheet($docSheet);
1608
                                                } else {
1609
                                                    //    ? Can charts be positioned with a oneCellAnchor ?
1610
                                                    $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...
1611
                                                    $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...
1612
                                                    $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...
1613
                                                    $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...
1614 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...
1615
                                                }
1616
                                            }
1617
                                        }
1618 3
                                        if ($xmlDrawing->twoCellAnchor) {
1619 1
                                            foreach ($xmlDrawing->twoCellAnchor as $twoCellAnchor) {
1620 1
                                                if ($twoCellAnchor->pic->blipFill) {
1621 1
                                                    $blip = $twoCellAnchor->pic->blipFill->children('http://schemas.openxmlformats.org/drawingml/2006/main')->blip;
1622 1
                                                    $xfrm = $twoCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->xfrm;
1623 1
                                                    $outerShdw = $twoCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->effectLst->outerShdw;
1624 1
                                                    $objDrawing = new Worksheet\Drawing();
1625 1
                                                    $objDrawing->setName((string) self::getArrayItem($twoCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'name'));
1626 1
                                                    $objDrawing->setDescription((string) self::getArrayItem($twoCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'descr'));
1627 1
                                                    $objDrawing->setPath(
1628 1
                                                        'zip://' . File::realpath($pFilename) . '#' .
1629 1
                                                        $images[(string) self::getArrayItem(
1630 1
                                                            $blip->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'),
1631 1
                                                            'embed'
1632
                                                        )],
1633 1
                                                        false
1634
                                                    );
1635 1
                                                    $objDrawing->setCoordinates(Cell::stringFromColumnIndex((string) $twoCellAnchor->from->col) . ($twoCellAnchor->from->row + 1));
1636 1
                                                    $objDrawing->setOffsetX(Drawing::EMUToPixels($twoCellAnchor->from->colOff));
1637 1
                                                    $objDrawing->setOffsetY(Drawing::EMUToPixels($twoCellAnchor->from->rowOff));
1638 1
                                                    $objDrawing->setResizeProportional(false);
1639
1640 1
                                                    if ($xfrm) {
1641 1
                                                        $objDrawing->setWidth(Drawing::EMUToPixels(self::getArrayItem($xfrm->ext->attributes(), 'cx')));
1642 1
                                                        $objDrawing->setHeight(Drawing::EMUToPixels(self::getArrayItem($xfrm->ext->attributes(), 'cy')));
1643 1
                                                        $objDrawing->setRotation(Drawing::angleToDegrees(self::getArrayItem($xfrm->attributes(), 'rot')));
1644
                                                    }
1645 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...
1646
                                                        $shadow = $objDrawing->getShadow();
1647
                                                        $shadow->setVisible(true);
1648
                                                        $shadow->setBlurRadius(Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), 'blurRad')));
1649
                                                        $shadow->setDistance(Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), 'dist')));
1650
                                                        $shadow->setDirection(Drawing::angleToDegrees(self::getArrayItem($outerShdw->attributes(), 'dir')));
1651
                                                        $shadow->setAlignment((string) self::getArrayItem($outerShdw->attributes(), 'algn'));
1652
                                                        $shadow->getColor()->setRGB(self::getArrayItem($outerShdw->srgbClr->attributes(), 'val'));
1653
                                                        $shadow->setAlpha(self::getArrayItem($outerShdw->srgbClr->alpha->attributes(), 'val') / 1000);
1654
                                                    }
1655 1
                                                    $objDrawing->setWorksheet($docSheet);
1656 1
                                                } elseif (($this->includeCharts) && ($twoCellAnchor->graphicFrame)) {
1657 1
                                                    $fromCoordinate = Cell::stringFromColumnIndex((string) $twoCellAnchor->from->col) . ($twoCellAnchor->from->row + 1);
1658 1
                                                    $fromOffsetX = Drawing::EMUToPixels($twoCellAnchor->from->colOff);
1659 1
                                                    $fromOffsetY = Drawing::EMUToPixels($twoCellAnchor->from->rowOff);
1660 1
                                                    $toCoordinate = Cell::stringFromColumnIndex((string) $twoCellAnchor->to->col) . ($twoCellAnchor->to->row + 1);
1661 1
                                                    $toOffsetX = Drawing::EMUToPixels($twoCellAnchor->to->colOff);
1662 1
                                                    $toOffsetY = Drawing::EMUToPixels($twoCellAnchor->to->rowOff);
1663 1
                                                    $graphic = $twoCellAnchor->graphicFrame->children('http://schemas.openxmlformats.org/drawingml/2006/main')->graphic;
1664
                                                    /** @var \SimpleXMLElement $chartRef */
1665 1
                                                    $chartRef = $graphic->graphicData->children('http://schemas.openxmlformats.org/drawingml/2006/chart')->chart;
1666 1
                                                    $thisChart = (string) $chartRef->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships');
1667
1668 1
                                                    $chartDetails[$docSheet->getTitle() . '!' . $thisChart] = [
1669 1
                                                        'fromCoordinate' => $fromCoordinate,
1670 1
                                                        'fromOffsetX' => $fromOffsetX,
1671 1
                                                        'fromOffsetY' => $fromOffsetY,
1672 1
                                                        'toCoordinate' => $toCoordinate,
1673 1
                                                        'toOffsetX' => $toOffsetX,
1674 1
                                                        'toOffsetY' => $toOffsetY,
1675 3
                                                        'worksheetTitle' => $docSheet->getTitle(),
1676
                                                    ];
1677
                                                }
1678
                                            }
1679
                                        }
1680
                                    }
1681
                                }
1682
                            }
1683
1684
                            // Loop through definedNames
1685 8
                            if ($xmlWorkbook->definedNames) {
1686 5
                                foreach ($xmlWorkbook->definedNames->definedName as $definedName) {
1687
                                    // Extract range
1688 1
                                    $extractedRange = (string) $definedName;
1689 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...
1690 1
                                        $extractedRange = substr($extractedRange, 0, $spos) . str_replace('$', '', substr($extractedRange, $spos));
1691
                                    } else {
1692
                                        $extractedRange = str_replace('$', '', $extractedRange);
1693
                                    }
1694
1695
                                    // Valid range?
1696 1
                                    if (stripos((string) $definedName, '#REF!') !== false || $extractedRange == '') {
1697
                                        continue;
1698
                                    }
1699
1700
                                    // Some definedNames are only applicable if we are on the same sheet...
1701 1
                                    if ((string) $definedName['localSheetId'] != '' && (string) $definedName['localSheetId'] == $sheetId) {
1702
                                        // Switch on type
1703 1
                                        switch ((string) $definedName['name']) {
1704 1
                                            case '_xlnm._FilterDatabase':
1705
                                                if ((string) $definedName['hidden'] !== '1') {
1706
                                                    $extractedRange = explode(',', $extractedRange);
1707
                                                    foreach ($extractedRange as $range) {
1708
                                                        $autoFilterRange = $range;
1709
                                                        if (strpos($autoFilterRange, ':') !== false) {
1710
                                                            $docSheet->getAutoFilter()->setRange($autoFilterRange);
1711
                                                        }
1712
                                                    }
1713
                                                }
1714
                                                break;
1715 1
                                            case '_xlnm.Print_Titles':
1716
                                                // Split $extractedRange
1717 1
                                                $extractedRange = explode(',', $extractedRange);
1718
1719
                                                // Set print titles
1720 1
                                                foreach ($extractedRange as $range) {
1721 1
                                                    $matches = [];
1722 1
                                                    $range = str_replace('$', '', $range);
1723
1724
                                                    // check for repeating columns, e g. 'A:A' or 'A:D'
1725 1
                                                    if (preg_match('/!?([A-Z]+)\:([A-Z]+)$/', $range, $matches)) {
1726
                                                        $docSheet->getPageSetup()->setColumnsToRepeatAtLeft([$matches[1], $matches[2]]);
1727 1
                                                    } elseif (preg_match('/!?(\d+)\:(\d+)$/', $range, $matches)) {
1728
                                                        // check for repeating rows, e.g. '1:1' or '1:5'
1729 1
                                                        $docSheet->getPageSetup()->setRowsToRepeatAtTop([$matches[1], $matches[2]]);
1730
                                                    }
1731
                                                }
1732 1
                                                break;
1733
                                            case '_xlnm.Print_Area':
1734
                                                $rangeSets = preg_split("/'(.*?)'(?:![A-Z0-9]+:[A-Z0-9]+,?)/", $extractedRange, PREG_SPLIT_NO_EMPTY);
1735
                                                $newRangeSets = [];
1736
                                                foreach ($rangeSets as $rangeSet) {
1737
                                                    $range = explode('!', $rangeSet); // FIXME: what if sheetname contains exclamation mark?
1738
                                                    $rangeSet = isset($range[1]) ? $range[1] : $range[0];
1739
                                                    if (strpos($rangeSet, ':') === false) {
1740
                                                        $rangeSet = $rangeSet . ':' . $rangeSet;
1741
                                                    }
1742
                                                    $newRangeSets[] = str_replace('$', '', $rangeSet);
1743
                                                }
1744
                                                $docSheet->getPageSetup()->setPrintArea(implode(',', $newRangeSets));
1745
                                                break;
1746
                                            default:
1747 1
                                                break;
1748
                                        }
1749
                                    }
1750
                                }
1751
                            }
1752
1753
                            // Next sheet id
1754 8
                            ++$sheetId;
1755
                        }
1756
1757
                        // Loop through definedNames
1758 8
                        if ($xmlWorkbook->definedNames) {
1759 5
                            foreach ($xmlWorkbook->definedNames->definedName as $definedName) {
1760
                                // Extract range
1761 1
                                $extractedRange = (string) $definedName;
1762 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...
1763 1
                                    $extractedRange = substr($extractedRange, 0, $spos) . str_replace('$', '', substr($extractedRange, $spos));
1764
                                } else {
1765
                                    $extractedRange = str_replace('$', '', $extractedRange);
1766
                                }
1767
1768
                                // Valid range?
1769 1
                                if (stripos((string) $definedName, '#REF!') !== false || $extractedRange == '') {
1770
                                    continue;
1771
                                }
1772
1773
                                // Some definedNames are only applicable if we are on the same sheet...
1774 1
                                if ((string) $definedName['localSheetId'] != '') {
1775
                                    // Local defined name
1776
                                    // Switch on type
1777 1
                                    switch ((string) $definedName['name']) {
1778 1
                                        case '_xlnm._FilterDatabase':
1779 1
                                        case '_xlnm.Print_Titles':
1780
                                        case '_xlnm.Print_Area':
1781 1
                                            break;
1782
                                        default:
1783
                                            if ($mapSheetId[(int) $definedName['localSheetId']] !== null) {
1784
                                                $range = explode('!', (string) $definedName);
1785
                                                if (count($range) == 2) {
1786
                                                    $range[0] = str_replace("''", "'", $range[0]);
1787
                                                    $range[0] = str_replace("'", '', $range[0]);
1788
                                                    if ($worksheet = $docSheet->getParent()->getSheetByName($range[0])) {
1789
                                                        $extractedRange = str_replace('$', '', $range[1]);
1790
                                                        $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...
1791
                                                        $excel->addNamedRange(new NamedRange((string) $definedName['name'], $worksheet, $extractedRange, true, $scope));
1792
                                                    }
1793
                                                }
1794
                                            }
1795 1
                                            break;
1796
                                    }
1797
                                } elseif (!isset($definedName['localSheetId'])) {
1798
                                    // "Global" definedNames
1799
                                    $locatedSheet = null;
1800
                                    $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...
1801
                                    if (strpos((string) $definedName, '!') !== false) {
1802
                                        // Extract sheet name
1803
                                        $extractedSheetName = Worksheet::extractSheetTitle((string) $definedName, true);
1804
                                        $extractedSheetName = $extractedSheetName[0];
1805
1806
                                        // Locate sheet
1807
                                        $locatedSheet = $excel->getSheetByName($extractedSheetName);
1808
1809
                                        // Modify range
1810
                                        $range = explode('!', $extractedRange);
1811
                                        $extractedRange = isset($range[1]) ? $range[1] : $range[0];
1812
                                    }
1813
1814
                                    if ($locatedSheet !== null) {
1815 1
                                        $excel->addNamedRange(new NamedRange((string) $definedName['name'], $locatedSheet, $extractedRange, false));
1816
                                    }
1817
                                }
1818
                            }
1819
                        }
1820
                    }
1821
1822 8
                    if ((!$this->readDataOnly) || (!empty($this->loadSheetsOnly))) {
1823
                        // active sheet index
1824 8
                        $activeTab = (int) ($xmlWorkbook->bookViews->workbookView['activeTab']); // refers to old sheet index
1825
1826
                        // keep active sheet index if sheet is still loaded, else first sheet is set as the active
1827 8
                        if (isset($mapSheetId[$activeTab]) && $mapSheetId[$activeTab] !== null) {
1828 8
                            $excel->setActiveSheetIndex($mapSheetId[$activeTab]);
1829
                        } else {
1830
                            if ($excel->getSheetCount() == 0) {
1831
                                $excel->createSheet();
1832
                            }
1833
                            $excel->setActiveSheetIndex(0);
1834
                        }
1835
                    }
1836 8
                    break;
1837
            }
1838
        }
1839
1840 8
        if (!$this->readDataOnly) {
1841 8
            $contentTypes = simplexml_load_string(
1842 8
                $this->securityScan(
1843 8
                    $this->getFromZipArchive($zip, '[Content_Types].xml')
1844
                ),
1845 8
                'SimpleXMLElement',
1846 8
                Settings::getLibXmlLoaderOptions()
1847
            );
1848 8
            foreach ($contentTypes->Override as $contentType) {
1849 8
                switch ($contentType['ContentType']) {
1850 8
                    case 'application/vnd.openxmlformats-officedocument.drawingml.chart+xml':
1851 1
                        if ($this->includeCharts) {
1852 1
                            $chartEntryRef = ltrim($contentType['PartName'], '/');
1853 1
                            $chartElements = simplexml_load_string(
1854 1
                                $this->securityScan(
1855 1
                                    $this->getFromZipArchive($zip, $chartEntryRef)
1856
                                ),
1857 1
                                'SimpleXMLElement',
1858 1
                                Settings::getLibXmlLoaderOptions()
1859
                            );
1860 1
                            $objChart = Chart::readChart($chartElements, basename($chartEntryRef, '.xml'));
1861
1862 1
                            if (isset($charts[$chartEntryRef])) {
1863 1
                                $chartPositionRef = $charts[$chartEntryRef]['sheet'] . '!' . $charts[$chartEntryRef]['id'];
1864 1
                                if (isset($chartDetails[$chartPositionRef])) {
1865 1
                                    $excel->getSheetByName($charts[$chartEntryRef]['sheet'])->addChart($objChart);
1866 1
                                    $objChart->setWorksheet($excel->getSheetByName($charts[$chartEntryRef]['sheet']));
1867 1
                                    $objChart->setTopLeftPosition($chartDetails[$chartPositionRef]['fromCoordinate'], $chartDetails[$chartPositionRef]['fromOffsetX'], $chartDetails[$chartPositionRef]['fromOffsetY']);
1868 8
                                    $objChart->setBottomRightPosition($chartDetails[$chartPositionRef]['toCoordinate'], $chartDetails[$chartPositionRef]['toOffsetX'], $chartDetails[$chartPositionRef]['toOffsetY']);
1869
                                }
1870
                            }
1871
                        }
1872
                }
1873
            }
1874
        }
1875
1876 8
        $zip->close();
1877
1878 8
        return $excel;
1879
    }
1880
1881 8
    private static function readColor($color, $background = false)
1882
    {
1883 8
        if (isset($color['rgb'])) {
1884 7
            return (string) $color['rgb'];
1885 4
        } elseif (isset($color['indexed'])) {
1886 3
            return Style\Color::indexedColor($color['indexed'] - 7, $background)->getARGB();
1887 3
        } elseif (isset($color['theme'])) {
1888 3
            if (self::$theme !== null) {
1889 3
                $returnColour = self::$theme->getColourByIndex((int) $color['theme']);
1890 3
                if (isset($color['tint'])) {
1891
                    $tintAdjust = (float) $color['tint'];
1892
                    $returnColour = Style\Color::changeBrightness($returnColour, $tintAdjust);
1893
                }
1894
1895 3
                return 'FF' . $returnColour;
1896
            }
1897
        }
1898
1899
        if ($background) {
1900
            return 'FFFFFFFF';
1901
        }
1902
1903
        return 'FF000000';
1904
    }
1905
1906
    /**
1907
     * @param Style $docStyle
1908
     * @param \stdClass|\SimpleXMLElement $style
1909
     */
1910 8
    private static function readStyle(Style $docStyle, $style)
1911
    {
1912 8
        $docStyle->getNumberFormat()->setFormatCode($style->numFmt);
1913
1914
        // font
1915 8
        if (isset($style->font)) {
1916 8
            $docStyle->getFont()->setName((string) $style->font->name['val']);
1917 8
            $docStyle->getFont()->setSize((string) $style->font->sz['val']);
1918 8 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...
1919 7
                $docStyle->getFont()->setBold(!isset($style->font->b['val']) || self::boolean((string) $style->font->b['val']));
1920
            }
1921 8 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...
1922 5
                $docStyle->getFont()->setItalic(!isset($style->font->i['val']) || self::boolean((string) $style->font->i['val']));
1923
            }
1924 8 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...
1925 5
                $docStyle->getFont()->setStrikethrough(!isset($style->font->strike['val']) || self::boolean((string) $style->font->strike['val']));
1926
            }
1927 8
            $docStyle->getFont()->getColor()->setARGB(self::readColor($style->font->color));
1928
1929 8 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...
1930
                $docStyle->getFont()->setUnderline(Style\Font::UNDERLINE_SINGLE);
1931 8
            } elseif (isset($style->font->u) && isset($style->font->u['val'])) {
1932 5
                $docStyle->getFont()->setUnderline((string) $style->font->u['val']);
1933
            }
1934
1935 8 View Code Duplication
            if (isset($style->font->vertAlign) && isset($style->font->vertAlign['val'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1936
                $vertAlign = strtolower((string) $style->font->vertAlign['val']);
1937
                if ($vertAlign == 'superscript') {
1938
                    $docStyle->getFont()->setSuperScript(true);
1939
                }
1940
                if ($vertAlign == 'subscript') {
1941
                    $docStyle->getFont()->setSubScript(true);
1942
                }
1943
            }
1944
        }
1945
1946
        // fill
1947 8
        if (isset($style->fill)) {
1948 8
            if ($style->fill->gradientFill) {
1949
                /** @var \SimpleXMLElement $gradientFill */
1950 2
                $gradientFill = $style->fill->gradientFill[0];
1951 2
                if (!empty($gradientFill['type'])) {
1952 2
                    $docStyle->getFill()->setFillType((string) $gradientFill['type']);
1953
                }
1954 2
                $docStyle->getFill()->setRotation((float) ($gradientFill['degree']));
1955 2
                $gradientFill->registerXPathNamespace('sml', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
1956 2
                $docStyle->getFill()->getStartColor()->setARGB(self::readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=0]'))->color));
1957 2
                $docStyle->getFill()->getEndColor()->setARGB(self::readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=1]'))->color));
1958 8
            } elseif ($style->fill->patternFill) {
1959 8
                $patternType = (string) $style->fill->patternFill['patternType'] != '' ? (string) $style->fill->patternFill['patternType'] : 'solid';
1960 8
                $docStyle->getFill()->setFillType($patternType);
1961 8
                if ($style->fill->patternFill->fgColor) {
1962 3
                    $docStyle->getFill()->getStartColor()->setARGB(self::readColor($style->fill->patternFill->fgColor, true));
1963
                } else {
1964 8
                    $docStyle->getFill()->getStartColor()->setARGB('FF000000');
1965
                }
1966 8
                if ($style->fill->patternFill->bgColor) {
1967 3
                    $docStyle->getFill()->getEndColor()->setARGB(self::readColor($style->fill->patternFill->bgColor, true));
1968
                }
1969
            }
1970
        }
1971
1972
        // border
1973 8
        if (isset($style->border)) {
1974 8
            $diagonalUp = self::boolean((string) $style->border['diagonalUp']);
1975 8
            $diagonalDown = self::boolean((string) $style->border['diagonalDown']);
1976 8
            if (!$diagonalUp && !$diagonalDown) {
1977 8
                $docStyle->getBorders()->setDiagonalDirection(Style\Borders::DIAGONAL_NONE);
1978
            } elseif ($diagonalUp && !$diagonalDown) {
1979
                $docStyle->getBorders()->setDiagonalDirection(Style\Borders::DIAGONAL_UP);
1980
            } elseif (!$diagonalUp && $diagonalDown) {
1981
                $docStyle->getBorders()->setDiagonalDirection(Style\Borders::DIAGONAL_DOWN);
1982
            } else {
1983
                $docStyle->getBorders()->setDiagonalDirection(Style\Borders::DIAGONAL_BOTH);
1984
            }
1985 8
            self::readBorder($docStyle->getBorders()->getLeft(), $style->border->left);
1986 8
            self::readBorder($docStyle->getBorders()->getRight(), $style->border->right);
1987 8
            self::readBorder($docStyle->getBorders()->getTop(), $style->border->top);
1988 8
            self::readBorder($docStyle->getBorders()->getBottom(), $style->border->bottom);
1989 8
            self::readBorder($docStyle->getBorders()->getDiagonal(), $style->border->diagonal);
1990
        }
1991
1992
        // alignment
1993 8
        if (isset($style->alignment)) {
1994 8
            $docStyle->getAlignment()->setHorizontal((string) $style->alignment['horizontal']);
1995 8
            $docStyle->getAlignment()->setVertical((string) $style->alignment['vertical']);
1996
1997 8
            $textRotation = 0;
1998 8
            if ((int) $style->alignment['textRotation'] <= 90) {
1999 8
                $textRotation = (int) $style->alignment['textRotation'];
2000
            } elseif ((int) $style->alignment['textRotation'] > 90) {
2001
                $textRotation = 90 - (int) $style->alignment['textRotation'];
2002
            }
2003
2004 8
            $docStyle->getAlignment()->setTextRotation((int) $textRotation);
2005 8
            $docStyle->getAlignment()->setWrapText(self::boolean((string) $style->alignment['wrapText']));
2006 8
            $docStyle->getAlignment()->setShrinkToFit(self::boolean((string) $style->alignment['shrinkToFit']));
2007 8
            $docStyle->getAlignment()->setIndent((int) ((string) $style->alignment['indent']) > 0 ? (int) ((string) $style->alignment['indent']) : 0);
2008 8
            $docStyle->getAlignment()->setReadorder((int) ((string) $style->alignment['readingOrder']) > 0 ? (int) ((string) $style->alignment['readingOrder']) : 0);
2009
        }
2010
2011
        // protection
2012 8
        if (isset($style->protection)) {
2013 8 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...
2014 2
                if (self::boolean((string) $style->protection['locked'])) {
2015
                    $docStyle->getProtection()->setLocked(Style\Protection::PROTECTION_PROTECTED);
2016
                } else {
2017 2
                    $docStyle->getProtection()->setLocked(Style\Protection::PROTECTION_UNPROTECTED);
2018
                }
2019
            }
2020
2021 8 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...
2022
                if (self::boolean((string) $style->protection['hidden'])) {
2023
                    $docStyle->getProtection()->setHidden(Style\Protection::PROTECTION_PROTECTED);
2024
                } else {
2025
                    $docStyle->getProtection()->setHidden(Style\Protection::PROTECTION_UNPROTECTED);
2026
                }
2027
            }
2028
        }
2029
2030
        // top-level style settings
2031 8
        if (isset($style->quotePrefix)) {
2032 8
            $docStyle->setQuotePrefix($style->quotePrefix);
2033
        }
2034 8
    }
2035
2036
    /**
2037
     * @param Style\Border $docBorder
2038
     * @param \SimpleXMLElement $eleBorder
2039
     */
2040 8
    private static function readBorder($docBorder, $eleBorder)
2041
    {
2042 8
        if (isset($eleBorder['style'])) {
2043 2
            $docBorder->setBorderStyle((string) $eleBorder['style']);
2044
        }
2045 8
        if (isset($eleBorder->color)) {
2046 2
            $docBorder->getColor()->setARGB(self::readColor($eleBorder->color));
2047
        }
2048 8
    }
2049
2050
    /**
2051
     * @param \SimpleXMLElement | null $is
2052
     *
2053
     * @return RichText
2054
     */
2055 3
    private function parseRichText($is = null)
2056
    {
2057 3
        $value = new RichText();
2058
2059 3
        if (isset($is->t)) {
2060
            $value->createText(StringHelper::controlCharacterOOXML2PHP((string) $is->t));
2061
        } else {
2062 3
            if (is_object($is->r)) {
2063 3
                foreach ($is->r as $run) {
2064 3
                    if (!isset($run->rPr)) {
2065 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...
2066
                    } else {
2067 3
                        $objText = $value->createTextRun(StringHelper::controlCharacterOOXML2PHP((string) $run->t));
2068
2069 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...
2070 3
                            $objText->getFont()->setName((string) $run->rPr->rFont['val']);
2071
                        }
2072 3
                        if (isset($run->rPr->sz['val'])) {
2073 3
                            $objText->getFont()->setSize((string) $run->rPr->sz['val']);
2074
                        }
2075 3
                        if (isset($run->rPr->color)) {
2076 3
                            $objText->getFont()->setColor(new Style\Color(self::readColor($run->rPr->color)));
2077
                        }
2078 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...
2079 3
                            (isset($run->rPr->b) && !isset($run->rPr->b['val']))) {
2080 3
                            $objText->getFont()->setBold(true);
2081
                        }
2082 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...
2083 3
                            (isset($run->rPr->i) && !isset($run->rPr->i['val']))) {
2084 2
                            $objText->getFont()->setItalic(true);
2085
                        }
2086 3 View Code Duplication
                        if (isset($run->rPr->vertAlign) && isset($run->rPr->vertAlign['val'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
2087
                            $vertAlign = strtolower((string) $run->rPr->vertAlign['val']);
2088
                            if ($vertAlign == 'superscript') {
2089
                                $objText->getFont()->setSuperScript(true);
2090
                            }
2091
                            if ($vertAlign == 'subscript') {
2092
                                $objText->getFont()->setSubScript(true);
2093
                            }
2094
                        }
2095 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...
2096
                            $objText->getFont()->setUnderline(Style\Font::UNDERLINE_SINGLE);
2097 3
                        } elseif (isset($run->rPr->u) && isset($run->rPr->u['val'])) {
2098 2
                            $objText->getFont()->setUnderline((string) $run->rPr->u['val']);
2099
                        }
2100 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...
2101 3
                            (isset($run->rPr->strike) && !isset($run->rPr->strike['val']))) {
2102 3
                            $objText->getFont()->setStrikethrough(true);
2103
                        }
2104
                    }
2105
                }
2106
            }
2107
        }
2108
2109 3
        return $value;
2110
    }
2111
2112
    /**
2113
     * @param Spreadsheet $excel
2114
     * @param mixed $customUITarget
2115
     * @param mixed $zip
2116
     */
2117
    private function readRibbon(Spreadsheet $excel, $customUITarget, $zip)
2118
    {
2119
        $baseDir = dirname($customUITarget);
2120
        $nameCustomUI = basename($customUITarget);
2121
        // get the xml file (ribbon)
2122
        $localRibbon = $this->getFromZipArchive($zip, $customUITarget);
2123
        $customUIImagesNames = [];
2124
        $customUIImagesBinaries = [];
2125
        // something like customUI/_rels/customUI.xml.rels
2126
        $pathRels = $baseDir . '/_rels/' . $nameCustomUI . '.rels';
2127
        $dataRels = $this->getFromZipArchive($zip, $pathRels);
2128
        if ($dataRels) {
2129
            // exists and not empty if the ribbon have some pictures (other than internal MSO)
2130
            $UIRels = simplexml_load_string(
2131
                $this->securityScan($dataRels),
2132
                'SimpleXMLElement',
2133
                Settings::getLibXmlLoaderOptions()
2134
            );
2135
            if ($UIRels) {
2136
                // we need to save id and target to avoid parsing customUI.xml and "guess" if it's a pseudo callback who load the image
2137
                foreach ($UIRels->Relationship as $ele) {
2138
                    if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') {
2139
                        // an image ?
2140
                        $customUIImagesNames[(string) $ele['Id']] = (string) $ele['Target'];
2141
                        $customUIImagesBinaries[(string) $ele['Target']] = $this->getFromZipArchive($zip, $baseDir . '/' . (string) $ele['Target']);
2142
                    }
2143
                }
2144
            }
2145
        }
2146
        if ($localRibbon) {
2147
            $excel->setRibbonXMLData($customUITarget, $localRibbon);
2148
            if (count($customUIImagesNames) > 0 && count($customUIImagesBinaries) > 0) {
2149
                $excel->setRibbonBinObjects($customUIImagesNames, $customUIImagesBinaries);
2150
            } else {
2151
                $excel->setRibbonBinObjects(null);
2152
            }
2153
        } else {
2154
            $excel->setRibbonXMLData(null);
2155
            $excel->setRibbonBinObjects(null);
2156
        }
2157
    }
2158
2159 9
    private static function getArrayItem($array, $key = 0)
2160
    {
2161 9
        return isset($array[$key]) ? $array[$key] : null;
2162
    }
2163
2164 3
    private static function dirAdd($base, $add)
2165
    {
2166 3
        return preg_replace('~[^/]+/\.\./~', '', dirname($base) . "/$add");
2167
    }
2168
2169
    private static function toCSSArray($style)
2170
    {
2171
        $style = str_replace(["\r", "\n"], '', $style);
2172
2173
        $temp = explode(';', $style);
2174
        $style = [];
2175
        foreach ($temp as $item) {
2176
            $item = explode(':', $item);
2177
2178
            if (strpos($item[1], 'px') !== false) {
2179
                $item[1] = str_replace('px', '', $item[1]);
2180
            }
2181 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...
2182
                $item[1] = str_replace('pt', '', $item[1]);
2183
                $item[1] = Font::fontSizeToPixels($item[1]);
2184
            }
2185 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...
2186
                $item[1] = str_replace('in', '', $item[1]);
2187
                $item[1] = Font::inchSizeToPixels($item[1]);
2188
            }
2189 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...
2190
                $item[1] = str_replace('cm', '', $item[1]);
2191
                $item[1] = Font::centimeterSizeToPixels($item[1]);
2192
            }
2193
2194
            $style[$item[0]] = $item[1];
2195
        }
2196
2197
        return $style;
2198
    }
2199
2200 8
    private static function boolean($value = null)
2201
    {
2202 8
        if (is_object($value)) {
2203 1
            $value = (string) $value;
2204
        }
2205 8
        if (is_numeric($value)) {
2206 6
            return (bool) $value;
2207
        }
2208
2209 8
        return $value === 'true' || $value === 'TRUE';
2210
    }
2211
}
2212