Completed
Push — develop ( 3ee9cc...870d86 )
by Adrien
29:45
created

Xlsx::getArrayItem()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

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

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

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

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
432 7
                        $docProps->setTitle((string) self::getArrayItem($xmlCore->xpath('dc:title')));
433 7
                        $docProps->setDescription((string) self::getArrayItem($xmlCore->xpath('dc:description')));
434 7
                        $docProps->setSubject((string) self::getArrayItem($xmlCore->xpath('dc:subject')));
435 7
                        $docProps->setKeywords((string) self::getArrayItem($xmlCore->xpath('cp:keywords')));
436 7
                        $docProps->setCategory((string) self::getArrayItem($xmlCore->xpath('cp:category')));
437
                    }
438 7
                    break;
439 7
                case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties':
440 7
                    $xmlCore = simplexml_load_string(
441 7
                        $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")),
442 7
                        'SimpleXMLElement',
443 7
                        Settings::getLibXmlLoaderOptions()
444
                    );
445 7
                    if (is_object($xmlCore)) {
446 7
                        $docProps = $excel->getProperties();
447 7
                        if (isset($xmlCore->Company)) {
448 6
                            $docProps->setCompany((string) $xmlCore->Company);
449
                        }
450 7
                        if (isset($xmlCore->Manager)) {
451 4
                            $docProps->setManager((string) $xmlCore->Manager);
452
                        }
453
                    }
454 7
                    break;
455 7
                case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties':
456
                    $xmlCore = simplexml_load_string(
457
                        $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")),
458
                        'SimpleXMLElement',
459
                        Settings::getLibXmlLoaderOptions()
460
                    );
461
                    if (is_object($xmlCore)) {
462
                        $docProps = $excel->getProperties();
463
                        /** @var \SimpleXMLElement $xmlProperty */
464
                        foreach ($xmlCore as $xmlProperty) {
465
                            $cellDataOfficeAttributes = $xmlProperty->attributes();
466
                            if (isset($cellDataOfficeAttributes['name'])) {
467
                                $propertyName = (string) $cellDataOfficeAttributes['name'];
468
                                $cellDataOfficeChildren = $xmlProperty->children('http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes');
469
                                $attributeType = $cellDataOfficeChildren->getName();
470
                                $attributeValue = (string) $cellDataOfficeChildren->{$attributeType};
471
                                $attributeValue = Properties::convertProperty($attributeValue, $attributeType);
472
                                $attributeType = Properties::convertPropertyType($attributeType);
473
                                $docProps->setCustomProperty($propertyName, $attributeValue, $attributeType);
474
                            }
475
                        }
476
                    }
477
                    break;
478
                //Ribbon
479 7
                case 'http://schemas.microsoft.com/office/2006/relationships/ui/extensibility':
480
                    $customUI = $rel['Target'];
481
                    if (!is_null($customUI)) {
482
                        $this->readRibbon($excel, $customUI, $zip);
483
                    }
484
                    break;
485 7
                case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument':
486 7
                    $dir = dirname($rel['Target']);
487 7
                    $relsWorkbook = simplexml_load_string(
488
                        //~ http://schemas.openxmlformats.org/package/2006/relationships"
489 7
                        $this->securityScan($this->getFromZipArchive($zip, "$dir/_rels/" . basename($rel['Target']) . '.rels')),
490 7
                        'SimpleXMLElement',
491 7
                        Settings::getLibXmlLoaderOptions()
492
                    );
493 7
                    $relsWorkbook->registerXPathNamespace('rel', 'http://schemas.openxmlformats.org/package/2006/relationships');
494
495 7
                    $sharedStrings = [];
496 7
                    $xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings']"));
497 7
                    $xmlStrings = simplexml_load_string(
498
                        //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
499 7
                        $this->securityScan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")),
500 7
                        'SimpleXMLElement',
501 7
                        Settings::getLibXmlLoaderOptions()
502
                    );
503 7
                    if (isset($xmlStrings) && isset($xmlStrings->si)) {
504 7
                        foreach ($xmlStrings->si as $val) {
505 7
                            if (isset($val->t)) {
506 7
                                $sharedStrings[] = StringHelper::controlCharacterOOXML2PHP((string) $val->t);
507
                            } elseif (isset($val->r)) {
508 3
                                $sharedStrings[] = $this->parseRichText($val);
509
                            }
510
                        }
511
                    }
512
513 7
                    $worksheets = [];
514 7
                    $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...
515 7
                    foreach ($relsWorkbook->Relationship as $ele) {
516 7
                        switch ($ele['Type']) {
517 7
                            case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet':
518 7
                                $worksheets[(string) $ele['Id']] = $ele['Target'];
519 7
                                break;
520
                            // a vbaProject ? (: some macros)
521 7
                            case 'http://schemas.microsoft.com/office/2006/relationships/vbaProject':
522
                                $macros = $ele['Target'];
523 7
                                break;
524
                        }
525
                    }
526
527 7
                    if (!is_null($macros)) {
528
                        $macrosCode = $this->getFromZipArchive($zip, 'xl/vbaProject.bin'); //vbaProject.bin always in 'xl' dir and always named vbaProject.bin
529
                        if ($macrosCode !== false) {
530
                            $excel->setMacrosCode($macrosCode);
531
                            $excel->setHasMacros(true);
532
                            //short-circuit : not reading vbaProject.bin.rel to get Signature =>allways vbaProjectSignature.bin in 'xl' dir
533
                            $Certificate = $this->getFromZipArchive($zip, 'xl/vbaProjectSignature.bin');
534
                            if ($Certificate !== false) {
535
                                $excel->setMacrosCertificate($Certificate);
536
                            }
537
                        }
538
                    }
539 7
                    $styles = [];
540 7
                    $cellStyles = [];
541 7
                    $xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles']"));
542 7
                    $xmlStyles = simplexml_load_string(
543
                        //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
544 7
                        $this->securityScan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")),
545 7
                        'SimpleXMLElement',
546 7
                        Settings::getLibXmlLoaderOptions()
547
                    );
548 7
                    $numFmts = null;
549 7
                    if ($xmlStyles && $xmlStyles->numFmts[0]) {
550 4
                        $numFmts = $xmlStyles->numFmts[0];
551
                    }
552 7
                    if (isset($numFmts) && ($numFmts !== null)) {
553 4
                        $numFmts->registerXPathNamespace('sml', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
554
                    }
555 7
                    if (!$this->readDataOnly && $xmlStyles) {
556 7
                        foreach ($xmlStyles->cellXfs->xf as $xf) {
557 7
                            $numFmt = NumberFormat::FORMAT_GENERAL;
558
559 7
                            if ($xf['numFmtId']) {
560 7
                                if (isset($numFmts)) {
561 4
                                    $tmpNumFmt = self::getArrayItem($numFmts->xpath("sml:numFmt[@numFmtId=$xf[numFmtId]]"));
562
563 4
                                    if (isset($tmpNumFmt['formatCode'])) {
564 2
                                        $numFmt = (string) $tmpNumFmt['formatCode'];
565
                                    }
566
                                }
567
568
                                // We shouldn't override any of the built-in MS Excel values (values below id 164)
569
                                //  But there's a lot of naughty homebrew xlsx writers that do use "reserved" id values that aren't actually used
570
                                //  So we make allowance for them rather than lose formatting masks
571 7
                                if ((int) $xf['numFmtId'] < 164 &&
572 7
                                    NumberFormat::builtInFormatCode((int) $xf['numFmtId']) !== '') {
573 7
                                    $numFmt = NumberFormat::builtInFormatCode((int) $xf['numFmtId']);
574
                                }
575
                            }
576 7
                            $quotePrefix = false;
577 7
                            if (isset($xf['quotePrefix'])) {
578
                                $quotePrefix = (bool) $xf['quotePrefix'];
579
                            }
580
581
                            $style = (object) [
582 7
                                'numFmt' => $numFmt,
583 7
                                'font' => $xmlStyles->fonts->font[(int) ($xf['fontId'])],
584 7
                                'fill' => $xmlStyles->fills->fill[(int) ($xf['fillId'])],
585 7
                                'border' => $xmlStyles->borders->border[(int) ($xf['borderId'])],
586 7
                                'alignment' => $xf->alignment,
587 7
                                'protection' => $xf->protection,
588 7
                                'quotePrefix' => $quotePrefix,
589
                            ];
590 7
                            $styles[] = $style;
591
592
                            // add style to cellXf collection
593 7
                            $objStyle = new Style();
594 7
                            self::readStyle($objStyle, $style);
595 7
                            $excel->addCellXf($objStyle);
596
                        }
597
598 7
                        foreach ($xmlStyles->cellStyleXfs->xf as $xf) {
599 7
                            $numFmt = NumberFormat::FORMAT_GENERAL;
600 7
                            if ($numFmts && $xf['numFmtId']) {
601 4
                                $tmpNumFmt = self::getArrayItem($numFmts->xpath("sml:numFmt[@numFmtId=$xf[numFmtId]]"));
602 4
                                if (isset($tmpNumFmt['formatCode'])) {
603
                                    $numFmt = (string) $tmpNumFmt['formatCode'];
604 4
                                } elseif ((int) $xf['numFmtId'] < 165) {
605 4
                                    $numFmt = NumberFormat::builtInFormatCode((int) $xf['numFmtId']);
606
                                }
607
                            }
608
609
                            $cellStyle = (object) [
610 7
                                'numFmt' => $numFmt,
611 7
                                'font' => $xmlStyles->fonts->font[(int) ($xf['fontId'])],
612 7
                                'fill' => $xmlStyles->fills->fill[(int) ($xf['fillId'])],
613 7
                                'border' => $xmlStyles->borders->border[(int) ($xf['borderId'])],
614 7
                                'alignment' => $xf->alignment,
615 7
                                'protection' => $xf->protection,
616 7
                                '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...
617
                            ];
618 7
                            $cellStyles[] = $cellStyle;
619
620
                            // add style to cellStyleXf collection
621 7
                            $objStyle = new Style();
622 7
                            self::readStyle($objStyle, $cellStyle);
623 7
                            $excel->addCellStyleXf($objStyle);
624
                        }
625
                    }
626
627 7
                    $dxfs = [];
628 7
                    if (!$this->readDataOnly && $xmlStyles) {
629
                        //    Conditional Styles
630 7
                        if ($xmlStyles->dxfs) {
631 7
                            foreach ($xmlStyles->dxfs->dxf as $dxf) {
632
                                $style = new Style(false, true);
633
                                self::readStyle($style, $dxf);
634
                                $dxfs[] = $style;
635
                            }
636
                        }
637
                        //    Cell Styles
638 7
                        if ($xmlStyles->cellStyles) {
639 7
                            foreach ($xmlStyles->cellStyles->cellStyle as $cellStyle) {
640 7
                                if ((int) ($cellStyle['builtinId']) == 0) {
641 7
                                    if (isset($cellStyles[(int) ($cellStyle['xfId'])])) {
642
                                        // Set default style
643 7
                                        $style = new Style();
644 7
                                        self::readStyle($style, $cellStyles[(int) ($cellStyle['xfId'])]);
645
646
                                        // normal style, currently not using it for anything
647
                                    }
648
                                }
649
                            }
650
                        }
651
                    }
652
653 7
                    $xmlWorkbook = simplexml_load_string(
654
                        //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
655 7
                        $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")),
656 7
                        'SimpleXMLElement',
657 7
                        Settings::getLibXmlLoaderOptions()
658
                    );
659
660
                    // Set base date
661 7
                    if ($xmlWorkbook->workbookPr) {
662 7
                        Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
663 7
                        if (isset($xmlWorkbook->workbookPr['date1904'])) {
664
                            if (self::boolean((string) $xmlWorkbook->workbookPr['date1904'])) {
665
                                Date::setExcelCalendar(Date::CALENDAR_MAC_1904);
666
                            }
667
                        }
668
                    }
669
670 7
                    $sheetId = 0; // keep track of new sheet id in final workbook
671 7
                    $oldSheetId = -1; // keep track of old sheet id in final workbook
672 7
                    $countSkippedSheets = 0; // keep track of number of skipped sheets
673 7
                    $mapSheetId = []; // mapping of sheet ids from old to new
674
675 7
                    $charts = $chartDetails = [];
676
677 7
                    if ($xmlWorkbook->sheets) {
678
                        /** @var \SimpleXMLElement $eleSheet */
679 7
                        foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
680 7
                            ++$oldSheetId;
681
682
                            // Check if sheet should be skipped
683 7
                            if (isset($this->loadSheetsOnly) && !in_array((string) $eleSheet['name'], $this->loadSheetsOnly)) {
684
                                ++$countSkippedSheets;
685
                                $mapSheetId[$oldSheetId] = null;
686
                                continue;
687
                            }
688
689
                            // Map old sheet id in original workbook to new sheet id.
690
                            // They will differ if loadSheetsOnly() is being used
691 7
                            $mapSheetId[$oldSheetId] = $oldSheetId - $countSkippedSheets;
692
693
                            // Load sheet
694 7
                            $docSheet = $excel->createSheet();
695
                            //    Use false for $updateFormulaCellReferences to prevent adjustment of worksheet
696
                            //        references in formula cells... during the load, all formulae should be correct,
697
                            //        and we're simply bringing the worksheet name in line with the formula, not the
698
                            //        reverse
699 7
                            $docSheet->setTitle((string) $eleSheet['name'], false);
700 7
                            $fileWorksheet = $worksheets[(string) self::getArrayItem($eleSheet->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id')];
701 7
                            $xmlSheet = simplexml_load_string(
702
                                //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
703 7
                                $this->securityScan($this->getFromZipArchive($zip, "$dir/$fileWorksheet")),
704 7
                                'SimpleXMLElement',
705 7
                                Settings::getLibXmlLoaderOptions()
706
                            );
707
708 7
                            $sharedFormulas = [];
709
710 7
                            if (isset($eleSheet['state']) && (string) $eleSheet['state'] != '') {
711
                                $docSheet->setSheetState((string) $eleSheet['state']);
712
                            }
713
714 7
                            if (isset($xmlSheet->sheetViews) && isset($xmlSheet->sheetViews->sheetView)) {
715 7 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...
716
                                    $docSheet->getSheetView()->setZoomScale((int) ($xmlSheet->sheetViews->sheetView['zoomScale']));
717
                                }
718 7 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...
719
                                    $docSheet->getSheetView()->setZoomScaleNormal((int) ($xmlSheet->sheetViews->sheetView['zoomScaleNormal']));
720
                                }
721 7 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...
722
                                    $docSheet->getSheetView()->setView((string) $xmlSheet->sheetViews->sheetView['view']);
723
                                }
724 7 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...
725 4
                                    $docSheet->setShowGridLines(self::boolean((string) $xmlSheet->sheetViews->sheetView['showGridLines']));
726
                                }
727 7 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...
728 4
                                    $docSheet->setShowRowColHeaders(self::boolean((string) $xmlSheet->sheetViews->sheetView['showRowColHeaders']));
729
                                }
730 7 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...
731
                                    $docSheet->setRightToLeft(self::boolean((string) $xmlSheet->sheetViews->sheetView['rightToLeft']));
732
                                }
733 7
                                if (isset($xmlSheet->sheetViews->sheetView->pane)) {
734 1
                                    if (isset($xmlSheet->sheetViews->sheetView->pane['topLeftCell'])) {
735 1
                                        $docSheet->freezePane((string) $xmlSheet->sheetViews->sheetView->pane['topLeftCell']);
736
                                    } else {
737
                                        $xSplit = 0;
738
                                        $ySplit = 0;
739
740
                                        if (isset($xmlSheet->sheetViews->sheetView->pane['xSplit'])) {
741
                                            $xSplit = 1 + (int) ($xmlSheet->sheetViews->sheetView->pane['xSplit']);
742
                                        }
743
744
                                        if (isset($xmlSheet->sheetViews->sheetView->pane['ySplit'])) {
745
                                            $ySplit = 1 + (int) ($xmlSheet->sheetViews->sheetView->pane['ySplit']);
746
                                        }
747
748
                                        $docSheet->freezePaneByColumnAndRow($xSplit, $ySplit);
749
                                    }
750
                                }
751
752 7
                                if (isset($xmlSheet->sheetViews->sheetView->selection)) {
753 7
                                    if (isset($xmlSheet->sheetViews->sheetView->selection['sqref'])) {
754 7
                                        $sqref = (string) $xmlSheet->sheetViews->sheetView->selection['sqref'];
755 7
                                        $sqref = explode(' ', $sqref);
756 7
                                        $sqref = $sqref[0];
757 7
                                        $docSheet->setSelectedCells($sqref);
758
                                    }
759
                                }
760
                            }
761
762 7
                            if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr->tabColor)) {
763 2
                                if (isset($xmlSheet->sheetPr->tabColor['rgb'])) {
764 2
                                    $docSheet->getTabColor()->setARGB((string) $xmlSheet->sheetPr->tabColor['rgb']);
765
                                }
766
                            }
767 7
                            if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr['codeName'])) {
768
                                $docSheet->setCodeName((string) $xmlSheet->sheetPr['codeName']);
769
                            }
770 7
                            if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr->outlinePr)) {
771 4 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...
772 4
                                    !self::boolean((string) $xmlSheet->sheetPr->outlinePr['summaryRight'])) {
773
                                    $docSheet->setShowSummaryRight(false);
774
                                } else {
775 4
                                    $docSheet->setShowSummaryRight(true);
776
                                }
777
778 4 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...
779 4
                                    !self::boolean((string) $xmlSheet->sheetPr->outlinePr['summaryBelow'])) {
780
                                    $docSheet->setShowSummaryBelow(false);
781
                                } else {
782 4
                                    $docSheet->setShowSummaryBelow(true);
783
                                }
784
                            }
785
786 7
                            if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr->pageSetUpPr)) {
787
                                if (isset($xmlSheet->sheetPr->pageSetUpPr['fitToPage']) &&
788
                                    !self::boolean((string) $xmlSheet->sheetPr->pageSetUpPr['fitToPage'])) {
789
                                    $docSheet->getPageSetup()->setFitToPage(false);
790
                                } else {
791
                                    $docSheet->getPageSetup()->setFitToPage(true);
792
                                }
793
                            }
794
795 7
                            if (isset($xmlSheet->sheetFormatPr)) {
796 7
                                if (isset($xmlSheet->sheetFormatPr['customHeight']) &&
797
                                    self::boolean((string) $xmlSheet->sheetFormatPr['customHeight']) &&
798
                                    isset($xmlSheet->sheetFormatPr['defaultRowHeight'])) {
799
                                    $docSheet->getDefaultRowDimension()->setRowHeight((float) $xmlSheet->sheetFormatPr['defaultRowHeight']);
800
                                }
801 7
                                if (isset($xmlSheet->sheetFormatPr['defaultColWidth'])) {
802
                                    $docSheet->getDefaultColumnDimension()->setWidth((float) $xmlSheet->sheetFormatPr['defaultColWidth']);
803
                                }
804 7
                                if (isset($xmlSheet->sheetFormatPr['zeroHeight']) &&
805
                                    ((string) $xmlSheet->sheetFormatPr['zeroHeight'] == '1')) {
806
                                    $docSheet->getDefaultRowDimension()->setZeroHeight(true);
807
                                }
808
                            }
809
810 7
                            if (isset($xmlSheet->cols) && !$this->readDataOnly) {
811 5
                                foreach ($xmlSheet->cols->col as $col) {
812 5
                                    for ($i = (int) ($col['min']) - 1; $i < (int) ($col['max']); ++$i) {
813 5
                                        if ($col['style'] && !$this->readDataOnly) {
814 3
                                            $docSheet->getColumnDimension(Cell::stringFromColumnIndex($i))->setXfIndex((int) ($col['style']));
815
                                        }
816 5
                                        if (self::boolean($col['hidden'])) {
817 1
                                            $docSheet->getColumnDimension(Cell::stringFromColumnIndex($i))->setVisible(false);
818
                                        }
819 5
                                        if (self::boolean($col['collapsed'])) {
820 1
                                            $docSheet->getColumnDimension(Cell::stringFromColumnIndex($i))->setCollapsed(true);
821
                                        }
822 5
                                        if ($col['outlineLevel'] > 0) {
823 1
                                            $docSheet->getColumnDimension(Cell::stringFromColumnIndex($i))->setOutlineLevel((int) ($col['outlineLevel']));
824
                                        }
825 5
                                        $docSheet->getColumnDimension(Cell::stringFromColumnIndex($i))->setWidth((float) ($col['width']));
826
827 5
                                        if ((int) ($col['max']) == 16384) {
828
                                            break;
829
                                        }
830
                                    }
831
                                }
832
                            }
833
834 7
                            if (isset($xmlSheet->printOptions) && !$this->readDataOnly) {
835 4
                                if (self::boolean((string) $xmlSheet->printOptions['gridLinesSet'])) {
836 4
                                    $docSheet->setShowGridlines(true);
837
                                }
838 4
                                if (self::boolean((string) $xmlSheet->printOptions['gridLines'])) {
839
                                    $docSheet->setPrintGridlines(true);
840
                                }
841 4
                                if (self::boolean((string) $xmlSheet->printOptions['horizontalCentered'])) {
842
                                    $docSheet->getPageSetup()->setHorizontalCentered(true);
843
                                }
844 4
                                if (self::boolean((string) $xmlSheet->printOptions['verticalCentered'])) {
845
                                    $docSheet->getPageSetup()->setVerticalCentered(true);
846
                                }
847
                            }
848
849 7
                            if ($xmlSheet && $xmlSheet->sheetData && $xmlSheet->sheetData->row) {
850 7
                                foreach ($xmlSheet->sheetData->row as $row) {
851 7
                                    if ($row['ht'] && !$this->readDataOnly) {
852 1
                                        $docSheet->getRowDimension((int) ($row['r']))->setRowHeight((float) ($row['ht']));
853
                                    }
854 7
                                    if (self::boolean($row['hidden']) && !$this->readDataOnly) {
855
                                        $docSheet->getRowDimension((int) ($row['r']))->setVisible(false);
856
                                    }
857 7
                                    if (self::boolean($row['collapsed'])) {
858
                                        $docSheet->getRowDimension((int) ($row['r']))->setCollapsed(true);
859
                                    }
860 7
                                    if ($row['outlineLevel'] > 0) {
861
                                        $docSheet->getRowDimension((int) ($row['r']))->setOutlineLevel((int) ($row['outlineLevel']));
862
                                    }
863 7
                                    if ($row['s'] && !$this->readDataOnly) {
864
                                        $docSheet->getRowDimension((int) ($row['r']))->setXfIndex((int) ($row['s']));
865
                                    }
866
867 7
                                    foreach ($row->c as $c) {
868 7
                                        $r = (string) $c['r'];
869 7
                                        $cellDataType = (string) $c['t'];
870 7
                                        $value = null;
871 7
                                        $calculatedValue = null;
872
873
                                        // Read cell?
874 7
                                        if ($this->getReadFilter() !== null) {
875 7
                                            $coordinates = Cell::coordinateFromString($r);
876
877 7
                                            if (!$this->getReadFilter()->readCell($coordinates[0], $coordinates[1], $docSheet->getTitle())) {
878 1
                                                continue;
879
                                            }
880
                                        }
881
882
                                        // Read cell!
883
                                        switch ($cellDataType) {
884 7
                                            case 's':
885 7
                                                if ((string) $c->v != '') {
886 7
                                                    $value = $sharedStrings[(int) ($c->v)];
887
888 7
                                                    if ($value instanceof RichText) {
889 1
                                                        $value = clone $value;
890
                                                    }
891
                                                } else {
892
                                                    $value = '';
893
                                                }
894 7
                                                break;
895 6
                                            case 'b':
896 1
                                                if (!isset($c->f)) {
897 1
                                                    $value = self::castToBoolean($c);
898
                                                } else {
899
                                                    // Formula
900
                                                    $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToBoolean');
901
                                                    if (isset($c->f['t'])) {
902
                                                        $att = $c->f;
903
                                                        $docSheet->getCell($r)->setFormulaAttributes($att);
904
                                                    }
905
                                                }
906 1
                                                break;
907 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...
908 2
                                                if (isset($c->f)) {
909
                                                    $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToError');
910
                                                } else {
911 2
                                                    $value = $this->parseRichText($c->is);
912
                                                }
913 2
                                                break;
914 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...
915
                                                if (!isset($c->f)) {
916
                                                    $value = self::castToError($c);
917
                                                } else {
918
                                                    // Formula
919
                                                    $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToError');
920
                                                }
921
                                                break;
922
                                            default:
923 5
                                                if (!isset($c->f)) {
924 5
                                                    $value = self::castToString($c);
925
                                                } else {
926
                                                    // Formula
927 3
                                                    $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToString');
928
                                                }
929 5
                                                break;
930
                                        }
931
932
                                        // Check for numeric values
933 7
                                        if (is_numeric($value) && $cellDataType != 's') {
934 5
                                            if ($value == (int) $value) {
935 5
                                                $value = (int) $value;
936
                                            } elseif ($value == (float) $value) {
937
                                                $value = (float) $value;
938
                                            } elseif ($value == (float) $value) {
939
                                                $value = (float) $value;
940
                                            }
941
                                        }
942
943
                                        // Rich text?
944 7
                                        if ($value instanceof RichText && $this->readDataOnly) {
945
                                            $value = $value->getPlainText();
946
                                        }
947
948 7
                                        $cell = $docSheet->getCell($r);
949
                                        // Assign value
950 7
                                        if ($cellDataType != '') {
951 7
                                            $cell->setValueExplicit($value, $cellDataType);
952
                                        } else {
953 5
                                            $cell->setValue($value);
954
                                        }
955 7
                                        if ($calculatedValue !== null) {
956 3
                                            $cell->setCalculatedValue($calculatedValue);
957
                                        }
958
959
                                        // Style information?
960 7
                                        if ($c['s'] && !$this->readDataOnly) {
961
                                            // no style index means 0, it seems
962 5
                                            $cell->setXfIndex(isset($styles[(int) ($c['s'])]) ?
963 7
                                                (int) ($c['s']) : 0);
964
                                        }
965
                                    }
966
                                }
967
                            }
968
969 7
                            $conditionals = [];
970 7
                            if (!$this->readDataOnly && $xmlSheet && $xmlSheet->conditionalFormatting) {
971
                                foreach ($xmlSheet->conditionalFormatting as $conditional) {
972
                                    foreach ($conditional->cfRule as $cfRule) {
973
                                        if (((string) $cfRule['type'] == Style\Conditional::CONDITION_NONE || (string) $cfRule['type'] == Style\Conditional::CONDITION_CELLIS || (string) $cfRule['type'] == Style\Conditional::CONDITION_CONTAINSTEXT || (string) $cfRule['type'] == Style\Conditional::CONDITION_EXPRESSION) && isset($dxfs[(int) ($cfRule['dxfId'])])) {
974
                                            $conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule;
975
                                        }
976
                                    }
977
                                }
978
979
                                foreach ($conditionals as $ref => $cfRules) {
980
                                    ksort($cfRules);
981
                                    $conditionalStyles = [];
982
                                    foreach ($cfRules as $cfRule) {
983
                                        $objConditional = new Style\Conditional();
984
                                        $objConditional->setConditionType((string) $cfRule['type']);
985
                                        $objConditional->setOperatorType((string) $cfRule['operator']);
986
987
                                        if ((string) $cfRule['text'] != '') {
988
                                            $objConditional->setText((string) $cfRule['text']);
989
                                        }
990
991
                                        if (count($cfRule->formula) > 1) {
992
                                            foreach ($cfRule->formula as $formula) {
993
                                                $objConditional->addCondition((string) $formula);
994
                                            }
995
                                        } else {
996
                                            $objConditional->addCondition((string) $cfRule->formula);
997
                                        }
998
                                        $objConditional->setStyle(clone $dxfs[(int) ($cfRule['dxfId'])]);
999
                                        $conditionalStyles[] = $objConditional;
1000
                                    }
1001
1002
                                    // Extract all cell references in $ref
1003
                                    $cellBlocks = explode(' ', str_replace('$', '', strtoupper($ref)));
1004
                                    foreach ($cellBlocks as $cellBlock) {
1005
                                        $docSheet->getStyle($cellBlock)->setConditionalStyles($conditionalStyles);
1006
                                    }
1007
                                }
1008
                            }
1009
1010 7
                            $aKeys = ['sheet', 'objects', 'scenarios', 'formatCells', 'formatColumns', 'formatRows', 'insertColumns', 'insertRows', 'insertHyperlinks', 'deleteColumns', 'deleteRows', 'selectLockedCells', 'sort', 'autoFilter', 'pivotTables', 'selectUnlockedCells'];
1011 7
                            if (!$this->readDataOnly && $xmlSheet && $xmlSheet->sheetProtection) {
1012 4
                                foreach ($aKeys as $key) {
1013 4
                                    $method = 'set' . ucfirst($key);
1014 4
                                    $docSheet->getProtection()->$method(self::boolean((string) $xmlSheet->sheetProtection[$key]));
1015
                                }
1016
                            }
1017
1018 7
                            if (!$this->readDataOnly && $xmlSheet && $xmlSheet->sheetProtection) {
1019 4
                                $docSheet->getProtection()->setPassword((string) $xmlSheet->sheetProtection['password'], true);
1020 4
                                if ($xmlSheet->protectedRanges->protectedRange) {
1021 2
                                    foreach ($xmlSheet->protectedRanges->protectedRange as $protectedRange) {
1022 2
                                        $docSheet->protectCells((string) $protectedRange['sqref'], (string) $protectedRange['password'], true);
1023
                                    }
1024
                                }
1025
                            }
1026
1027 7
                            if ($xmlSheet && $xmlSheet->autoFilter && !$this->readDataOnly) {
1028
                                $autoFilterRange = (string) $xmlSheet->autoFilter['ref'];
1029
                                if (strpos($autoFilterRange, ':') !== false) {
1030
                                    $autoFilter = $docSheet->getAutoFilter();
1031
                                    $autoFilter->setRange($autoFilterRange);
1032
1033
                                    foreach ($xmlSheet->autoFilter->filterColumn as $filterColumn) {
1034
                                        $column = $autoFilter->getColumnByOffset((int) $filterColumn['colId']);
1035
                                        //    Check for standard filters
1036
                                        if ($filterColumn->filters) {
1037
                                            $column->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER);
1038
                                            $filters = $filterColumn->filters;
1039
                                            if ((isset($filters['blank'])) && ($filters['blank'] == 1)) {
1040
                                                //    Operator is undefined, but always treated as EQUAL
1041
                                                $column->createRule()->setRule(null, '')->setRuleType(Column\Rule::AUTOFILTER_RULETYPE_FILTER);
1042
                                            }
1043
                                            //    Standard filters are always an OR join, so no join rule needs to be set
1044
                                            //    Entries can be either filter elements
1045 View Code Duplication
                                            foreach ($filters->filter as $filterRule) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading history...
1580 2
                                                        $shadow = $objDrawing->getShadow();
1581 2
                                                        $shadow->setVisible(true);
1582 2
                                                        $shadow->setBlurRadius(Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), 'blurRad')));
1583 2
                                                        $shadow->setDistance(Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), 'dist')));
1584 2
                                                        $shadow->setDirection(Drawing::angleToDegrees(self::getArrayItem($outerShdw->attributes(), 'dir')));
1585 2
                                                        $shadow->setAlignment((string) self::getArrayItem($outerShdw->attributes(), 'algn'));
1586 2
                                                        $shadow->getColor()->setRGB(self::getArrayItem($outerShdw->srgbClr->attributes(), 'val'));
1587 2
                                                        $shadow->setAlpha(self::getArrayItem($outerShdw->srgbClr->alpha->attributes(), 'val') / 1000);
1588
                                                    }
1589 2
                                                    $objDrawing->setWorksheet($docSheet);
1590
                                                } else {
1591
                                                    //    ? Can charts be positioned with a oneCellAnchor ?
1592
                                                    $coordinates = Cell::stringFromColumnIndex((string) $oneCellAnchor->from->col) . ($oneCellAnchor->from->row + 1);
0 ignored issues
show
Unused Code introduced by
$coordinates is not used, you could remove the assignment.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading history...
1672 1
                                        $extractedRange = substr($extractedRange, 0, $spos) . str_replace('$', '', substr($extractedRange, $spos));
1673
                                    } else {
1674
                                        $extractedRange = str_replace('$', '', $extractedRange);
1675
                                    }
1676
1677
                                    // Valid range?
1678 1
                                    if (stripos((string) $definedName, '#REF!') !== false || $extractedRange == '') {
1679
                                        continue;
1680
                                    }
1681
1682
                                    // Some definedNames are only applicable if we are on the same sheet...
1683 1
                                    if ((string) $definedName['localSheetId'] != '' && (string) $definedName['localSheetId'] == $sheetId) {
1684
                                        // Switch on type
1685 1
                                        switch ((string) $definedName['name']) {
1686 1
                                            case '_xlnm._FilterDatabase':
1687
                                                if ((string) $definedName['hidden'] !== '1') {
1688
                                                    $extractedRange = explode(',', $extractedRange);
1689
                                                    foreach ($extractedRange as $range) {
1690
                                                        $autoFilterRange = $range;
1691
                                                        if (strpos($autoFilterRange, ':') !== false) {
1692
                                                            $docSheet->getAutoFilter()->setRange($autoFilterRange);
1693
                                                        }
1694
                                                    }
1695
                                                }
1696
                                                break;
1697 1
                                            case '_xlnm.Print_Titles':
1698
                                                // Split $extractedRange
1699 1
                                                $extractedRange = explode(',', $extractedRange);
1700
1701
                                                // Set print titles
1702 1
                                                foreach ($extractedRange as $range) {
1703 1
                                                    $matches = [];
1704 1
                                                    $range = str_replace('$', '', $range);
1705
1706
                                                    // check for repeating columns, e g. 'A:A' or 'A:D'
1707 1
                                                    if (preg_match('/!?([A-Z]+)\:([A-Z]+)$/', $range, $matches)) {
1708
                                                        $docSheet->getPageSetup()->setColumnsToRepeatAtLeft([$matches[1], $matches[2]]);
1709 1
                                                    } elseif (preg_match('/!?(\d+)\:(\d+)$/', $range, $matches)) {
1710
                                                        // check for repeating rows, e.g. '1:1' or '1:5'
1711 1
                                                        $docSheet->getPageSetup()->setRowsToRepeatAtTop([$matches[1], $matches[2]]);
1712
                                                    }
1713
                                                }
1714 1
                                                break;
1715
                                            case '_xlnm.Print_Area':
1716
                                                $rangeSets = preg_split("/'(.*?)'(?:![A-Z0-9]+:[A-Z0-9]+,?)/", $extractedRange, PREG_SPLIT_NO_EMPTY);
1717
                                                $newRangeSets = [];
1718
                                                foreach ($rangeSets as $rangeSet) {
1719
                                                    $range = explode('!', $rangeSet); // FIXME: what if sheetname contains exclamation mark?
1720
                                                    $rangeSet = isset($range[1]) ? $range[1] : $range[0];
1721
                                                    if (strpos($rangeSet, ':') === false) {
1722
                                                        $rangeSet = $rangeSet . ':' . $rangeSet;
1723
                                                    }
1724
                                                    $newRangeSets[] = str_replace('$', '', $rangeSet);
1725
                                                }
1726
                                                $docSheet->getPageSetup()->setPrintArea(implode(',', $newRangeSets));
1727
                                                break;
1728
                                            default:
1729 1
                                                break;
1730
                                        }
1731
                                    }
1732
                                }
1733
                            }
1734
1735
                            // Next sheet id
1736 7
                            ++$sheetId;
1737
                        }
1738
1739
                        // Loop through definedNames
1740 7
                        if ($xmlWorkbook->definedNames) {
1741 4
                            foreach ($xmlWorkbook->definedNames->definedName as $definedName) {
1742
                                // Extract range
1743 1
                                $extractedRange = (string) $definedName;
1744 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...
1745 1
                                    $extractedRange = substr($extractedRange, 0, $spos) . str_replace('$', '', substr($extractedRange, $spos));
1746
                                } else {
1747
                                    $extractedRange = str_replace('$', '', $extractedRange);
1748
                                }
1749
1750
                                // Valid range?
1751 1
                                if (stripos((string) $definedName, '#REF!') !== false || $extractedRange == '') {
1752
                                    continue;
1753
                                }
1754
1755
                                // Some definedNames are only applicable if we are on the same sheet...
1756 1
                                if ((string) $definedName['localSheetId'] != '') {
1757
                                    // Local defined name
1758
                                    // Switch on type
1759 1
                                    switch ((string) $definedName['name']) {
1760 1
                                        case '_xlnm._FilterDatabase':
1761 1
                                        case '_xlnm.Print_Titles':
1762
                                        case '_xlnm.Print_Area':
1763 1
                                            break;
1764
                                        default:
1765
                                            if ($mapSheetId[(int) $definedName['localSheetId']] !== null) {
1766
                                                $range = explode('!', (string) $definedName);
1767
                                                if (count($range) == 2) {
1768
                                                    $range[0] = str_replace("''", "'", $range[0]);
1769
                                                    $range[0] = str_replace("'", '', $range[0]);
1770
                                                    if ($worksheet = $docSheet->getParent()->getSheetByName($range[0])) {
1771
                                                        $extractedRange = str_replace('$', '', $range[1]);
1772
                                                        $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...
1773
                                                        $excel->addNamedRange(new NamedRange((string) $definedName['name'], $worksheet, $extractedRange, true, $scope));
1774
                                                    }
1775
                                                }
1776
                                            }
1777 1
                                            break;
1778
                                    }
1779
                                } elseif (!isset($definedName['localSheetId'])) {
1780
                                    // "Global" definedNames
1781
                                    $locatedSheet = null;
1782
                                    $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...
1783
                                    if (strpos((string) $definedName, '!') !== false) {
1784
                                        // Extract sheet name
1785
                                        $extractedSheetName = Worksheet::extractSheetTitle((string) $definedName, true);
1786
                                        $extractedSheetName = $extractedSheetName[0];
1787
1788
                                        // Locate sheet
1789
                                        $locatedSheet = $excel->getSheetByName($extractedSheetName);
1790
1791
                                        // Modify range
1792
                                        $range = explode('!', $extractedRange);
1793
                                        $extractedRange = isset($range[1]) ? $range[1] : $range[0];
1794
                                    }
1795
1796
                                    if ($locatedSheet !== null) {
1797
                                        $excel->addNamedRange(new NamedRange((string) $definedName['name'], $locatedSheet, $extractedRange, false));
1798
                                    }
1799
                                }
1800
                            }
1801
                        }
1802
                    }
1803
1804 7
                    if ((!$this->readDataOnly) || (!empty($this->loadSheetsOnly))) {
1805
                        // active sheet index
1806 7
                        $activeTab = (int) ($xmlWorkbook->bookViews->workbookView['activeTab']); // refers to old sheet index
1807
1808
                        // keep active sheet index if sheet is still loaded, else first sheet is set as the active
1809 7
                        if (isset($mapSheetId[$activeTab]) && $mapSheetId[$activeTab] !== null) {
1810 7
                            $excel->setActiveSheetIndex($mapSheetId[$activeTab]);
1811
                        } else {
1812
                            if ($excel->getSheetCount() == 0) {
1813
                                $excel->createSheet();
1814
                            }
1815
                            $excel->setActiveSheetIndex(0);
1816
                        }
1817
                    }
1818 7
                    break;
1819
            }
1820
        }
1821
1822 7
        if (!$this->readDataOnly) {
1823 7
            $contentTypes = simplexml_load_string(
1824 7
                $this->securityScan(
1825 7
                    $this->getFromZipArchive($zip, '[Content_Types].xml')
1826
                ),
1827 7
                'SimpleXMLElement',
1828 7
                Settings::getLibXmlLoaderOptions()
1829
            );
1830 7
            foreach ($contentTypes->Override as $contentType) {
1831 7
                switch ($contentType['ContentType']) {
1832 7
                    case 'application/vnd.openxmlformats-officedocument.drawingml.chart+xml':
1833 1
                        if ($this->includeCharts) {
1834 1
                            $chartEntryRef = ltrim($contentType['PartName'], '/');
1835 1
                            $chartElements = simplexml_load_string(
1836 1
                                $this->securityScan(
1837 1
                                    $this->getFromZipArchive($zip, $chartEntryRef)
1838
                                ),
1839 1
                                'SimpleXMLElement',
1840 1
                                Settings::getLibXmlLoaderOptions()
1841
                            );
1842 1
                            $objChart = Chart::readChart($chartElements, basename($chartEntryRef, '.xml'));
1843
1844 1
                            if (isset($charts[$chartEntryRef])) {
1845 1
                                $chartPositionRef = $charts[$chartEntryRef]['sheet'] . '!' . $charts[$chartEntryRef]['id'];
1846 1
                                if (isset($chartDetails[$chartPositionRef])) {
1847 1
                                    $excel->getSheetByName($charts[$chartEntryRef]['sheet'])->addChart($objChart);
1848 1
                                    $objChart->setWorksheet($excel->getSheetByName($charts[$chartEntryRef]['sheet']));
1849 1
                                    $objChart->setTopLeftPosition($chartDetails[$chartPositionRef]['fromCoordinate'], $chartDetails[$chartPositionRef]['fromOffsetX'], $chartDetails[$chartPositionRef]['fromOffsetY']);
1850 7
                                    $objChart->setBottomRightPosition($chartDetails[$chartPositionRef]['toCoordinate'], $chartDetails[$chartPositionRef]['toOffsetX'], $chartDetails[$chartPositionRef]['toOffsetY']);
1851
                                }
1852
                            }
1853
                        }
1854
                }
1855
            }
1856
        }
1857
1858 7
        $zip->close();
1859
1860 7
        return $excel;
1861
    }
1862
1863 7
    private static function readColor($color, $background = false)
1864
    {
1865 7
        if (isset($color['rgb'])) {
1866 6
            return (string) $color['rgb'];
1867 3
        } elseif (isset($color['indexed'])) {
1868 2
            return Style\Color::indexedColor($color['indexed'] - 7, $background)->getARGB();
1869 3
        } elseif (isset($color['theme'])) {
1870 3
            if (self::$theme !== null) {
1871 3
                $returnColour = self::$theme->getColourByIndex((int) $color['theme']);
1872 3
                if (isset($color['tint'])) {
1873
                    $tintAdjust = (float) $color['tint'];
1874
                    $returnColour = Style\Color::changeBrightness($returnColour, $tintAdjust);
1875
                }
1876
1877 3
                return 'FF' . $returnColour;
1878
            }
1879
        }
1880
1881
        if ($background) {
1882
            return 'FFFFFFFF';
1883
        }
1884
1885
        return 'FF000000';
1886
    }
1887
1888
    /**
1889
     * @param Style $docStyle
1890
     * @param \stdClass|\SimpleXMLElement $style
1891
     */
1892 7
    private static function readStyle(Style $docStyle, $style)
1893
    {
1894 7
        $docStyle->getNumberFormat()->setFormatCode($style->numFmt);
1895
1896
        // font
1897 7
        if (isset($style->font)) {
1898 7
            $docStyle->getFont()->setName((string) $style->font->name['val']);
1899 7
            $docStyle->getFont()->setSize((string) $style->font->sz['val']);
1900 7 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...
1901 6
                $docStyle->getFont()->setBold(!isset($style->font->b['val']) || self::boolean((string) $style->font->b['val']));
1902
            }
1903 7 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...
1904 4
                $docStyle->getFont()->setItalic(!isset($style->font->i['val']) || self::boolean((string) $style->font->i['val']));
1905
            }
1906 7 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...
1907 4
                $docStyle->getFont()->setStrikethrough(!isset($style->font->strike['val']) || self::boolean((string) $style->font->strike['val']));
1908
            }
1909 7
            $docStyle->getFont()->getColor()->setARGB(self::readColor($style->font->color));
1910
1911 7 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...
1912
                $docStyle->getFont()->setUnderline(Style\Font::UNDERLINE_SINGLE);
1913 4
            } elseif (isset($style->font->u) && isset($style->font->u['val'])) {
1914 4
                $docStyle->getFont()->setUnderline((string) $style->font->u['val']);
1915
            }
1916
1917 7 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...
1918
                $vertAlign = strtolower((string) $style->font->vertAlign['val']);
1919
                if ($vertAlign == 'superscript') {
1920
                    $docStyle->getFont()->setSuperScript(true);
1921
                }
1922
                if ($vertAlign == 'subscript') {
1923
                    $docStyle->getFont()->setSubScript(true);
1924
                }
1925
            }
1926
        }
1927
1928
        // fill
1929 7
        if (isset($style->fill)) {
1930 7
            if ($style->fill->gradientFill) {
1931
                /** @var \SimpleXMLElement $gradientFill */
1932 2
                $gradientFill = $style->fill->gradientFill[0];
1933 2
                if (!empty($gradientFill['type'])) {
1934 2
                    $docStyle->getFill()->setFillType((string) $gradientFill['type']);
1935
                }
1936 2
                $docStyle->getFill()->setRotation((float) ($gradientFill['degree']));
1937 2
                $gradientFill->registerXPathNamespace('sml', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
1938 2
                $docStyle->getFill()->getStartColor()->setARGB(self::readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=0]'))->color));
1939 2
                $docStyle->getFill()->getEndColor()->setARGB(self::readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=1]'))->color));
1940 7
            } elseif ($style->fill->patternFill) {
1941 7
                $patternType = (string) $style->fill->patternFill['patternType'] != '' ? (string) $style->fill->patternFill['patternType'] : 'solid';
1942 7
                $docStyle->getFill()->setFillType($patternType);
1943 7
                if ($style->fill->patternFill->fgColor) {
1944 3
                    $docStyle->getFill()->getStartColor()->setARGB(self::readColor($style->fill->patternFill->fgColor, true));
1945
                } else {
1946 7
                    $docStyle->getFill()->getStartColor()->setARGB('FF000000');
1947
                }
1948 7
                if ($style->fill->patternFill->bgColor) {
1949 3
                    $docStyle->getFill()->getEndColor()->setARGB(self::readColor($style->fill->patternFill->bgColor, true));
1950
                }
1951
            }
1952
        }
1953
1954
        // border
1955 7
        if (isset($style->border)) {
1956 7
            $diagonalUp = self::boolean((string) $style->border['diagonalUp']);
1957 7
            $diagonalDown = self::boolean((string) $style->border['diagonalDown']);
1958 7
            if (!$diagonalUp && !$diagonalDown) {
1959 7
                $docStyle->getBorders()->setDiagonalDirection(Style\Borders::DIAGONAL_NONE);
1960
            } elseif ($diagonalUp && !$diagonalDown) {
1961
                $docStyle->getBorders()->setDiagonalDirection(Style\Borders::DIAGONAL_UP);
1962
            } elseif (!$diagonalUp && $diagonalDown) {
1963
                $docStyle->getBorders()->setDiagonalDirection(Style\Borders::DIAGONAL_DOWN);
1964
            } else {
1965
                $docStyle->getBorders()->setDiagonalDirection(Style\Borders::DIAGONAL_BOTH);
1966
            }
1967 7
            self::readBorder($docStyle->getBorders()->getLeft(), $style->border->left);
1968 7
            self::readBorder($docStyle->getBorders()->getRight(), $style->border->right);
1969 7
            self::readBorder($docStyle->getBorders()->getTop(), $style->border->top);
1970 7
            self::readBorder($docStyle->getBorders()->getBottom(), $style->border->bottom);
1971 7
            self::readBorder($docStyle->getBorders()->getDiagonal(), $style->border->diagonal);
1972
        }
1973
1974
        // alignment
1975 7
        if (isset($style->alignment)) {
1976 7
            $docStyle->getAlignment()->setHorizontal((string) $style->alignment['horizontal']);
1977 7
            $docStyle->getAlignment()->setVertical((string) $style->alignment['vertical']);
1978
1979 7
            $textRotation = 0;
1980 7
            if ((int) $style->alignment['textRotation'] <= 90) {
1981 7
                $textRotation = (int) $style->alignment['textRotation'];
1982
            } elseif ((int) $style->alignment['textRotation'] > 90) {
1983
                $textRotation = 90 - (int) $style->alignment['textRotation'];
1984
            }
1985
1986 7
            $docStyle->getAlignment()->setTextRotation((int) $textRotation);
1987 7
            $docStyle->getAlignment()->setWrapText(self::boolean((string) $style->alignment['wrapText']));
1988 7
            $docStyle->getAlignment()->setShrinkToFit(self::boolean((string) $style->alignment['shrinkToFit']));
1989 7
            $docStyle->getAlignment()->setIndent((int) ((string) $style->alignment['indent']) > 0 ? (int) ((string) $style->alignment['indent']) : 0);
1990 7
            $docStyle->getAlignment()->setReadorder((int) ((string) $style->alignment['readingOrder']) > 0 ? (int) ((string) $style->alignment['readingOrder']) : 0);
1991
        }
1992
1993
        // protection
1994 7
        if (isset($style->protection)) {
1995 7 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...
1996 2
                if (self::boolean((string) $style->protection['locked'])) {
1997
                    $docStyle->getProtection()->setLocked(Style\Protection::PROTECTION_PROTECTED);
1998
                } else {
1999 2
                    $docStyle->getProtection()->setLocked(Style\Protection::PROTECTION_UNPROTECTED);
2000
                }
2001
            }
2002
2003 7 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...
2004
                if (self::boolean((string) $style->protection['hidden'])) {
2005
                    $docStyle->getProtection()->setHidden(Style\Protection::PROTECTION_PROTECTED);
2006
                } else {
2007
                    $docStyle->getProtection()->setHidden(Style\Protection::PROTECTION_UNPROTECTED);
2008
                }
2009
            }
2010
        }
2011
2012
        // top-level style settings
2013 7
        if (isset($style->quotePrefix)) {
2014 7
            $docStyle->setQuotePrefix($style->quotePrefix);
2015
        }
2016 7
    }
2017
2018
    /**
2019
     * @param Style\Border $docBorder
2020
     * @param \SimpleXMLElement $eleBorder
2021
     */
2022 7
    private static function readBorder($docBorder, $eleBorder)
2023
    {
2024 7
        if (isset($eleBorder['style'])) {
2025 2
            $docBorder->setBorderStyle((string) $eleBorder['style']);
2026
        }
2027 7
        if (isset($eleBorder->color)) {
2028 2
            $docBorder->getColor()->setARGB(self::readColor($eleBorder->color));
2029
        }
2030 7
    }
2031
2032
    /**
2033
     * @param \SimpleXMLElement | null $is
2034
     *
2035
     * @return RichText
2036
     */
2037 3
    private function parseRichText($is)
2038
    {
2039 3
        $value = new RichText();
2040
2041 3
        if (isset($is->t)) {
2042
            $value->createText(StringHelper::controlCharacterOOXML2PHP((string) $is->t));
2043
        } else {
2044 3
            if (is_object($is->r)) {
2045 3
                foreach ($is->r as $run) {
2046 3
                    if (!isset($run->rPr)) {
2047 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...
2048
                    } else {
2049 3
                        $objText = $value->createTextRun(StringHelper::controlCharacterOOXML2PHP((string) $run->t));
2050
2051 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...
2052 3
                            $objText->getFont()->setName((string) $run->rPr->rFont['val']);
2053
                        }
2054 3
                        if (isset($run->rPr->sz['val'])) {
2055 3
                            $objText->getFont()->setSize((string) $run->rPr->sz['val']);
2056
                        }
2057 3
                        if (isset($run->rPr->color)) {
2058 3
                            $objText->getFont()->setColor(new Style\Color(self::readColor($run->rPr->color)));
2059
                        }
2060 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...
2061 3
                            (isset($run->rPr->b) && !isset($run->rPr->b['val']))) {
2062 3
                            $objText->getFont()->setBold(true);
2063
                        }
2064 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...
2065 2
                            (isset($run->rPr->i) && !isset($run->rPr->i['val']))) {
2066 2
                            $objText->getFont()->setItalic(true);
2067
                        }
2068 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...
2069
                            $vertAlign = strtolower((string) $run->rPr->vertAlign['val']);
2070
                            if ($vertAlign == 'superscript') {
2071
                                $objText->getFont()->setSuperScript(true);
2072
                            }
2073
                            if ($vertAlign == 'subscript') {
2074
                                $objText->getFont()->setSubScript(true);
2075
                            }
2076
                        }
2077 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...
2078
                            $objText->getFont()->setUnderline(Style\Font::UNDERLINE_SINGLE);
2079 2
                        } elseif (isset($run->rPr->u) && isset($run->rPr->u['val'])) {
2080 2
                            $objText->getFont()->setUnderline((string) $run->rPr->u['val']);
2081
                        }
2082 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...
2083 2
                            (isset($run->rPr->strike) && !isset($run->rPr->strike['val']))) {
2084
                            $objText->getFont()->setStrikethrough(true);
2085
                        }
2086
                    }
2087
                }
2088
            }
2089
        }
2090
2091 3
        return $value;
2092
    }
2093
2094
    /**
2095
     * @param Spreadsheet $excel
2096
     * @param mixed $customUITarget
2097
     * @param mixed $zip
2098
     */
2099
    private function readRibbon(Spreadsheet $excel, $customUITarget, $zip)
2100
    {
2101
        $baseDir = dirname($customUITarget);
2102
        $nameCustomUI = basename($customUITarget);
2103
        // get the xml file (ribbon)
2104
        $localRibbon = $this->getFromZipArchive($zip, $customUITarget);
2105
        $customUIImagesNames = [];
2106
        $customUIImagesBinaries = [];
2107
        // something like customUI/_rels/customUI.xml.rels
2108
        $pathRels = $baseDir . '/_rels/' . $nameCustomUI . '.rels';
2109
        $dataRels = $this->getFromZipArchive($zip, $pathRels);
2110
        if ($dataRels) {
2111
            // exists and not empty if the ribbon have some pictures (other than internal MSO)
2112
            $UIRels = simplexml_load_string(
2113
                $this->securityScan($dataRels),
2114
                'SimpleXMLElement',
2115
                Settings::getLibXmlLoaderOptions()
2116
            );
2117
            if ($UIRels) {
2118
                // we need to save id and target to avoid parsing customUI.xml and "guess" if it's a pseudo callback who load the image
2119
                foreach ($UIRels->Relationship as $ele) {
2120
                    if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') {
2121
                        // an image ?
2122
                        $customUIImagesNames[(string) $ele['Id']] = (string) $ele['Target'];
2123
                        $customUIImagesBinaries[(string) $ele['Target']] = $this->getFromZipArchive($zip, $baseDir . '/' . (string) $ele['Target']);
2124
                    }
2125
                }
2126
            }
2127
        }
2128
        if ($localRibbon) {
2129
            $excel->setRibbonXMLData($customUITarget, $localRibbon);
2130
            if (count($customUIImagesNames) > 0 && count($customUIImagesBinaries) > 0) {
2131
                $excel->setRibbonBinObjects($customUIImagesNames, $customUIImagesBinaries);
2132
            } else {
2133
                $excel->setRibbonBinObjects(null);
0 ignored issues
show
Bug introduced by
The call to setRibbonBinObjects() misses a required argument $BinObjectsData.

This check looks for function calls that miss required arguments.

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

This check looks for function calls that miss required arguments.

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

This check looks for function calls that miss required arguments.

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