Completed
Pull Request — develop (#208)
by Franck
09:10
created

fileSupportsUnserializePhpPresentation()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 26
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 6.0208

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 11
cts 12
cp 0.9167
rs 8.439
c 0
b 0
f 0
cc 6
eloc 14
nc 5
nop 1
crap 6.0208
1
<?php
2
/**
3
 * This file is part of PHPPresentation - A pure PHP library for reading and writing
4
 * presentations documents.
5
 *
6
 * PHPPresentation is free software distributed under the terms of the GNU Lesser
7
 * General Public License version 3 as published by the Free Software Foundation.
8
 *
9
 * For the full copyright and license information, please read the LICENSE
10
 * file that was distributed with this source code. For the full list of
11
 * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors.
12
 *
13
 * @link        https://github.com/PHPOffice/PHPPresentation
14
 * @copyright   2009-2015 PHPPresentation contributors
15
 * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
16
 */
17
18
namespace PhpOffice\PhpPresentation\Reader;
19
20
use PhpOffice\Common\XMLReader;
21
use PhpOffice\Common\Drawing as CommonDrawing;
22
use PhpOffice\Common\Microsoft\OLERead;
23
use PhpOffice\PhpPresentation\DocumentLayout;
24
use PhpOffice\PhpPresentation\PhpPresentation;
25
use PhpOffice\PhpPresentation\Shape\Placeholder;
26
use PhpOffice\PhpPresentation\Shape\RichText;
27
use PhpOffice\PhpPresentation\Shape\RichText\Paragraph;
28
use PhpOffice\PhpPresentation\Shape\Table\Cell;
29
use PhpOffice\PhpPresentation\Slide;
30
use PhpOffice\PhpPresentation\Slide\AbstractSlide;
31
use PhpOffice\PhpPresentation\Slide\SlideLayout;
32
use PhpOffice\PhpPresentation\Slide\SlideMaster;
33
use PhpOffice\PhpPresentation\Shape\Drawing\Gd;
34
use PhpOffice\PhpPresentation\Style\Bullet;
35
use PhpOffice\PhpPresentation\Style\Border;
36
use PhpOffice\PhpPresentation\Style\Borders;
37
use PhpOffice\PhpPresentation\Style\Color;
38
use PhpOffice\PhpPresentation\Style\Fill;
39
use PhpOffice\PhpPresentation\Style\SchemeColor;
40
use PhpOffice\PhpPresentation\Style\TextStyle;
41
use ZipArchive;
42
43
/**
44
 * Serialized format reader
45
 */
46
class PowerPoint2007 extends AbstractReader implements ReaderInterface
47
{
48
    /**
49
     * Output Object
50
     * @var PhpPresentation
51
     */
52
    protected $oPhpPresentation;
53
    /**
54
     * Output Object
55
     * @var \ZipArchive
56
     */
57
    protected $oZip;
58
    /**
59
     * @var array[]
60
     */
61
    protected $arrayRels = array();
62
    /**
63
     * @var SlideLayout[]
64
     */
65
    protected $arraySlideLayouts = array();
66
    /*
67
     * @var string
68
     */
69
    protected $filename;
70
    /*
71
     * @var string
72
     */
73
    protected $fileRels;
74
75
    /**
76
     * Can the current \PhpOffice\PhpPresentation\Reader\ReaderInterface read the file?
77
     *
78
     * @param  string $pFilename
79
     * @throws \Exception
80
     * @return boolean
81
     */
82 2
    public function canRead($pFilename)
83
    {
84 2
        return $this->fileSupportsUnserializePhpPresentation($pFilename);
85
    }
86
87
    /**
88
     * Does a file support UnserializePhpPresentation ?
89
     *
90
     * @param  string $pFilename
91
     * @throws \Exception
92
     * @return boolean
93
     */
94 9
    public function fileSupportsUnserializePhpPresentation($pFilename = '')
95
    {
96
        // Check if file exists
97 9
        if (!file_exists($pFilename)) {
98 2
            throw new \Exception("Could not open " . $pFilename . " for reading! File does not exist.");
99
        }
100
101 7
        $oZip = new ZipArchive();
102
        // Is it a zip ?
103 7
        if ($oZip->open($pFilename) === true) {
104
            // Is it an OpenXML Document ?
105
            // Is it a Presentation ?
106 4
            if (is_array($oZip->statName('[Content_Types].xml')) && is_array($oZip->statName('ppt/presentation.xml'))) {
107 4
                return true;
108
            }
109
        } else {
110 3
            $oOLE = new OLERead();
111
            try {
112 3
                $oOLE->read($pFilename);
113 2
                return true;
114 1
            } catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
Bug introduced by
The class PhpOffice\PhpPresentation\Reader\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
115
            }
116
        }
117
118
        return false;
119
    }
120
121
    /**
122
     * Loads PhpPresentation Serialized file
123
     *
124
     * @param  string $pFilename
125
     * @return \PhpOffice\PhpPresentation\PhpPresentation
126
     * @throws \Exception
127
     */
128 6
    public function load($pFilename)
129
    {
130
        // Unserialize... First make sure the file supports it!
131 6
        if (!$this->fileSupportsUnserializePhpPresentation($pFilename)) {
132
            throw new \Exception("Invalid file format for PhpOffice\PhpPresentation\Reader\PowerPoint2007: " . $pFilename . ".");
133
        }
134
135 5
        return $this->loadFile($pFilename);
136
    }
137
138
    /**
139
     * Load PhpPresentation Serialized file
140
     *
141
     * @param  string $pFilename
142
     * @return \PhpOffice\PhpPresentation\PhpPresentation
143
     */
144 5
    protected function loadFile($pFilename)
145
    {
146 5
        $this->oPhpPresentation = new PhpPresentation();
147 5
        $this->oPhpPresentation->removeSlideByIndex();
148 5
        $this->oPhpPresentation->setAllMasterSlides(array());
149 5
        $this->filename = $pFilename;
150
151 5
        $this->oZip = new ZipArchive();
152
153 5
        if ($this->oZip->open($this->filename) == ZipArchive::ER_NOZIP) {
154 5
            $this->loadEncryptedFile();
155
            return $this->oPhpPresentation;
156
        }
157
158
        $docPropsCore = $this->oZip->getFromName('docProps/core.xml');
159
        if ($docPropsCore !== false) {
160
            $this->loadDocumentProperties($docPropsCore);
161
        }
162
163
        $docPropsCustom = $this->oZip->getFromName('docProps/custom.xml');
164
        if ($docPropsCustom !== false) {
165
            $this->loadCustomProperties($docPropsCustom);
166
        }
167
168
        $pptViewProps = $this->oZip->getFromName('ppt/viewProps.xml');
169
        if ($pptViewProps !== false) {
170
            $this->loadViewProperties($pptViewProps);
171
        }
172
173
        $pptPresentation = $this->oZip->getFromName('ppt/presentation.xml');
174
        if ($pptPresentation !== false) {
175
            $this->loadDocumentLayout($pptPresentation);
176
            $this->loadSlides($pptPresentation);
177
        }
178
179
        return $this->oPhpPresentation;
180
    }
181
182
    /**
183
     * Read Document Layout
184
     * @param $sPart
185
     */
186
    protected function loadDocumentLayout($sPart)
187
    {
188
        $xmlReader = new XMLReader();
189
        if ($xmlReader->getDomFromString($sPart)) {
190
            foreach ($xmlReader->getElements('/p:presentation/p:sldSz') as $oElement) {
191
                if (!($oElement instanceof \DOMElement)) {
192
                    continue;
193
                }
194
                $type = $oElement->getAttribute('type');
195
                $oLayout = $this->oPhpPresentation->getLayout();
196
                if ($type == DocumentLayout::LAYOUT_CUSTOM) {
197
                    $oLayout->setCX($oElement->getAttribute('cx'));
198
                    $oLayout->setCY($oElement->getAttribute('cy'));
199
                } else {
200
                    $oLayout->setDocumentLayout($type, true);
201
                    if ($oElement->getAttribute('cx') < $oElement->getAttribute('cy')) {
202
                        $oLayout->setDocumentLayout($type, false);
203
                    }
204
                }
205
            }
206
        }
207
    }
208
209
    /**
210
     * Read Document Properties
211
     * @param string $sPart
212
     */
213
    protected function loadDocumentProperties($sPart)
214
    {
215
        $xmlReader = new XMLReader();
216
        if ($xmlReader->getDomFromString($sPart)) {
217
            $arrayProperties = array(
218
                '/cp:coreProperties/dc:creator' => 'setCreator',
219
                '/cp:coreProperties/cp:lastModifiedBy' => 'setLastModifiedBy',
220
                '/cp:coreProperties/dc:title' => 'setTitle',
221
                '/cp:coreProperties/dc:description' => 'setDescription',
222
                '/cp:coreProperties/dc:subject' => 'setSubject',
223
                '/cp:coreProperties/cp:keywords' => 'setKeywords',
224
                '/cp:coreProperties/cp:category' => 'setCategory',
225
                '/cp:coreProperties/dcterms:created' => 'setCreated',
226
                '/cp:coreProperties/dcterms:modified' => 'setModified',
227
            );
228
            $oProperties = $this->oPhpPresentation->getDocumentProperties();
229
            foreach ($arrayProperties as $path => $property) {
230
                $oElement = $xmlReader->getElement($path);
231
                if ($oElement instanceof \DOMElement) {
232
                    if ($oElement->hasAttribute('xsi:type') && $oElement->getAttribute('xsi:type') == 'dcterms:W3CDTF') {
233
                        $oDateTime = new \DateTime();
234
                        $oDateTime->createFromFormat(\DateTime::W3C, $oElement->nodeValue);
235
                        $oProperties->{$property}($oDateTime->getTimestamp());
236
                    } else {
237
                        $oProperties->{$property}($oElement->nodeValue);
238
                    }
239
                }
240
            }
241
        }
242
    }
243
244
    /**
245
     * Read Custom Properties
246
     * @param string $sPart
247
     */
248
    protected function loadCustomProperties($sPart)
249
    {
250
        $xmlReader = new XMLReader();
251
        $sPart = str_replace(' xmlns="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"', '', $sPart);
252
        if ($xmlReader->getDomFromString($sPart)) {
253
            $pathMarkAsFinal = '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="_MarkAsFinal"]/vt:bool';
254
            if (is_object($oElement = $xmlReader->getElement($pathMarkAsFinal))) {
255
                if ($oElement->nodeValue == 'true') {
256
                    $this->oPhpPresentation->getPresentationProperties()->markAsFinal(true);
257
                }
258
            }
259
        }
260
    }
261
262
    /**
263
     * Read View Properties
264
     * @param string $sPart
265
     */
266
    protected function loadViewProperties($sPart)
267
    {
268
        $xmlReader = new XMLReader();
269
        if ($xmlReader->getDomFromString($sPart)) {
270
            $pathZoom = '/p:viewPr/p:slideViewPr/p:cSldViewPr/p:cViewPr/p:scale/a:sx';
271
            $oElement = $xmlReader->getElement($pathZoom);
272
            if ($oElement instanceof \DOMElement) {
273
                if ($oElement->hasAttribute('d') && $oElement->hasAttribute('n')) {
274
                    $this->oPhpPresentation->getPresentationProperties()->setZoom($oElement->getAttribute('n') / $oElement->getAttribute('d'));
275
                }
276
            }
277
        }
278
    }
279
280
    /**
281
     * Extract all slides
282
     */
283
    protected function loadSlides($sPart)
284
    {
285
        $xmlReader = new XMLReader();
286
        if ($xmlReader->getDomFromString($sPart)) {
287
            $fileRels = 'ppt/_rels/presentation.xml.rels';
288
            $this->loadRels($fileRels);
289
            // Load the Masterslides
290
            $this->loadMasterSlides($xmlReader, $fileRels);
291
            // Continue with loading the slides
292
            foreach ($xmlReader->getElements('/p:presentation/p:sldIdLst/p:sldId') as $oElement) {
293
                if (!($oElement instanceof \DOMElement)) {
294
                    continue;
295
                }
296
                $rId = $oElement->getAttribute('r:id');
297
                $pathSlide = isset($this->arrayRels[$fileRels][$rId]) ? $this->arrayRels[$fileRels][$rId]['Target'] : '';
298
                if (!empty($pathSlide)) {
299
                    $pptSlide = $this->oZip->getFromName('ppt/' . $pathSlide);
300
                    if ($pptSlide !== false) {
301
                        $slideRels = 'ppt/slides/_rels/' . basename($pathSlide) . '.rels';
302
                        $this->loadRels($slideRels);
303
                        $this->loadSlide($pptSlide, basename($pathSlide));
304
                        foreach ($this->arrayRels[$slideRels] as $rel) {
305
                            if ($rel['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide') {
306
                                $this->loadSlideNote(basename($rel['Target']), $this->oPhpPresentation->getActiveSlide());
307
                            }
308
                        }
309
                    }
310
                }
311
            }
312
        }
313
    }
314
315
    /**
316
     * Extract all MasterSlides
317
     * @param XMLReader $xmlReader
318
     * @param string $fileRels
319
     */
320
    protected function loadMasterSlides(XMLReader $xmlReader, $fileRels)
321
    {
322
        // Get all the MasterSlide Id's from the presentation.xml file
323
        foreach ($xmlReader->getElements('/p:presentation/p:sldMasterIdLst/p:sldMasterId') as $oElement) {
324
            if (!($oElement instanceof \DOMElement)) {
325
                continue;
326
            }
327
            $rId = $oElement->getAttribute('r:id');
328
            // Get the path to the masterslide from the array with _rels files
329
            $pathMasterSlide = isset($this->arrayRels[$fileRels][$rId]) ?
330
                $this->arrayRels[$fileRels][$rId]['Target'] : '';
331
            if (!empty($pathMasterSlide)) {
332
                $pptMasterSlide = $this->oZip->getFromName('ppt/' . $pathMasterSlide);
333
                if ($pptMasterSlide !== false) {
334
                    $this->loadRels('ppt/slideMasters/_rels/' . basename($pathMasterSlide) . '.rels');
335
                    $this->loadMasterSlide($pptMasterSlide, basename($pathMasterSlide));
336
                }
337
            }
338
        }
339
    }
340
341
    /**
342
     * Extract data from slide
343
     * @param string $sPart
344
     * @param string $baseFile
345
     */
346
    protected function loadSlide($sPart, $baseFile)
347
    {
348
        $xmlReader = new XMLReader();
349
        if ($xmlReader->getDomFromString($sPart)) {
350
            // Core
351
            $oSlide = $this->oPhpPresentation->createSlide();
352
            $this->oPhpPresentation->setActiveSlideIndex($this->oPhpPresentation->getSlideCount() - 1);
353
            $oSlide->setRelsIndex('ppt/slides/_rels/' . $baseFile . '.rels');
354
355
            // Background
356
            $oElement = $xmlReader->getElement('/p:sld/p:cSld/p:bg/p:bgPr');
357
            if ($oElement instanceof \DOMElement) {
358
                $oElementColor = $xmlReader->getElement('a:solidFill/a:srgbClr', $oElement);
359
                if ($oElementColor instanceof \DOMElement) {
360
                    // Color
361
                    $oColor = new Color();
362
                    $oColor->setRGB($oElementColor->hasAttribute('val') ? $oElementColor->getAttribute('val') : null);
363
                    // Background
364
                    $oBackground = new Slide\Background\Color();
365
                    $oBackground->setColor($oColor);
366
                    // Slide Background
367
                    $oSlide = $this->oPhpPresentation->getActiveSlide();
368
                    $oSlide->setBackground($oBackground);
369
                }
370
                $oElementColor = $xmlReader->getElement('a:solidFill/a:schemeClr', $oElement);
371
                if ($oElementColor instanceof \DOMElement) {
372
                    // Color
373
                    $oColor = new SchemeColor();
374
                    $oColor->setValue($oElementColor->hasAttribute('val') ? $oElementColor->getAttribute('val') : null);
375
                    // Background
376
                    $oBackground = new Slide\Background\SchemeColor();
377
                    $oBackground->setSchemeColor($oColor);
378
                    // Slide Background
379
                    $oSlide = $this->oPhpPresentation->getActiveSlide();
380
                    $oSlide->setBackground($oBackground);
381
                }
382
                $oElementImage = $xmlReader->getElement('a:blipFill/a:blip', $oElement);
383
                if ($oElementImage instanceof \DOMElement) {
384
                    $relImg = $this->arrayRels['ppt/slides/_rels/' . $baseFile . '.rels'][$oElementImage->getAttribute('r:embed')];
385
                    if (is_array($relImg)) {
386
                        // File
387
                        $pathImage = 'ppt/slides/' . $relImg['Target'];
388
                        $pathImage = explode('/', $pathImage);
389
                        foreach ($pathImage as $key => $partPath) {
390
                            if ($partPath == '..') {
391
                                unset($pathImage[$key - 1]);
392
                                unset($pathImage[$key]);
393
                            }
394
                        }
395
                        $pathImage = implode('/', $pathImage);
396
                        $contentImg = $this->oZip->getFromName($pathImage);
397
398
                        $tmpBkgImg = tempnam(sys_get_temp_dir(), 'PhpPresentationReaderPpt2007Bkg');
399
                        file_put_contents($tmpBkgImg, $contentImg);
400
                        // Background
401
                        $oBackground = new Slide\Background\Image();
402
                        $oBackground->setPath($tmpBkgImg);
403
                        // Slide Background
404
                        $oSlide = $this->oPhpPresentation->getActiveSlide();
405
                        $oSlide->setBackground($oBackground);
406
                    }
407
                }
408
            }
409
410
            // Shapes
411
            $arrayElements = $xmlReader->getElements('/p:sld/p:cSld/p:spTree/*');
412
            if ($arrayElements) {
413
                $this->loadSlideShapes($oSlide, $arrayElements, $xmlReader);
414
            }
415
416
            // Layout
417
            $oSlide = $this->oPhpPresentation->getActiveSlide();
418
            foreach ($this->arrayRels['ppt/slides/_rels/' . $baseFile . '.rels'] as $valueRel) {
419
                if ($valueRel['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout') {
420
                    $layoutBasename = basename($valueRel['Target']);
421
                    if (array_key_exists($layoutBasename, $this->arraySlideLayouts)) {
422
                        $oSlide->setSlideLayout($this->arraySlideLayouts[$layoutBasename]);
423
                    }
424
                    break;
425
                }
426
            }
427
        }
428
    }
429
430
    /**
431
     * @param string $sPart
432
     * @param string $baseFile
433
     */
434
    protected function loadMasterSlide($sPart, $baseFile)
435
    {
436
        $xmlReader = new XMLReader();
437
        if ($xmlReader->getDomFromString($sPart)) {
438
            // Core
439
            $oSlideMaster = $this->oPhpPresentation->createMasterSlide();
440
            $oSlideMaster->setTextStyles(new TextStyle(false));
441
            $oSlideMaster->setRelsIndex('ppt/slideMasters/_rels/' . $baseFile . '.rels');
442
443
            // Background
444
            $oElement = $xmlReader->getElement('/p:sldMaster/p:cSld/p:bg');
445
            if ($oElement instanceof \DOMElement) {
446
                $this->loadSlideBackground($xmlReader, $oElement, $oSlideMaster);
447
            }
448
449
            // Shapes
450
            $arrayElements = $xmlReader->getElements('/p:sldMaster/p:cSld/p:spTree/*');
451
            if ($arrayElements) {
452
                $this->loadSlideShapes($oSlideMaster, $arrayElements, $xmlReader);
453
            }
454
            // Header & Footer
455
456
            // ColorMapping
457
            $colorMap = array();
458
            $oElement = $xmlReader->getElement('/p:sldMaster/p:clrMap');
459
            if ($oElement->hasAttributes()) {
460
                foreach ($oElement->attributes as $attr) {
461
                    $colorMap[$attr->nodeName] = $attr->nodeValue;
462
                }
463
                $oSlideMaster->colorMap->setMapping($colorMap);
464
            }
465
466
            // TextStyles
467
            $arrayElementTxStyles = $xmlReader->getElements('/p:sldMaster/p:txStyles/*');
468
            if ($arrayElementTxStyles) {
469
                foreach ($arrayElementTxStyles as $oElementTxStyle) {
470
                    $arrayElementsLvl = $xmlReader->getElements('/p:sldMaster/p:txStyles/' . $oElementTxStyle->nodeName . '/*');
471
                    foreach ($arrayElementsLvl as $oElementLvl) {
472
                        if (!($oElementLvl instanceof \DOMElement) || $oElementLvl->nodeName == 'a:extLst') {
473
                            continue;
474
                        }
475
                        $oRTParagraph = new Paragraph();
476
477
                        if ($oElementLvl->nodeName == 'a:defPPr') {
478
                            $level = 0;
479
                        } else {
480
                            $level = str_replace('a:lvl', '', $oElementLvl->nodeName);
481
                            $level = str_replace('pPr', '', $level);
482
                        }
483
484
                        if ($oElementLvl->hasAttribute('algn')) {
485
                            $oRTParagraph->getAlignment()->setHorizontal($oElementLvl->getAttribute('algn'));
486
                        }
487
                        if ($oElementLvl->hasAttribute('marL')) {
488
                            $val = $oElementLvl->getAttribute('marL');
489
                            $val = CommonDrawing::emuToPixels($val);
490
                            $oRTParagraph->getAlignment()->setMarginLeft($val);
491
                        }
492
                        if ($oElementLvl->hasAttribute('marR')) {
493
                            $val = $oElementLvl->getAttribute('marR');
494
                            $val = CommonDrawing::emuToPixels($val);
495
                            $oRTParagraph->getAlignment()->setMarginRight($val);
496
                        }
497
                        if ($oElementLvl->hasAttribute('indent')) {
498
                            $val = $oElementLvl->getAttribute('indent');
499
                            $val = CommonDrawing::emuToPixels($val);
500
                            $oRTParagraph->getAlignment()->setIndent($val);
501
                        }
502
                        $oElementLvlDefRPR = $xmlReader->getElement('a:defRPr', $oElementLvl);
503
                        if ($oElementLvlDefRPR instanceof \DOMElement) {
504
                            if ($oElementLvlDefRPR->hasAttribute('sz')) {
505
                                $oRTParagraph->getFont()->setSize($oElementLvlDefRPR->getAttribute('sz') / 100);
506
                            }
507
                            if ($oElementLvlDefRPR->hasAttribute('b') && $oElementLvlDefRPR->getAttribute('b') == 1) {
508
                                $oRTParagraph->getFont()->setBold(true);
509
                            }
510
                            if ($oElementLvlDefRPR->hasAttribute('i') && $oElementLvlDefRPR->getAttribute('i') == 1) {
511
                                $oRTParagraph->getFont()->setItalic(true);
512
                            }
513
                        }
514
                        $oElementSchemeColor = $xmlReader->getElement('a:defRPr/a:solidFill/a:schemeClr', $oElementLvl);
515
                        if ($oElementSchemeColor instanceof \DOMElement) {
516
                            if ($oElementSchemeColor->hasAttribute('val')) {
517
                                $oSchemeColor = new SchemeColor();
518
                                $oSchemeColor->setValue($oElementSchemeColor->getAttribute('val'));
519
                                $oRTParagraph->getFont()->setColor($oSchemeColor);
520
                            }
521
                        }
522
523
                        switch ($oElementTxStyle->nodeName) {
524
                            case 'p:bodyStyle':
525
                                $oSlideMaster->getTextStyles()->setBodyStyleAtLvl($oRTParagraph, $level);
526
                                break;
527
                            case 'p:otherStyle':
528
                                $oSlideMaster->getTextStyles()->setOtherStyleAtLvl($oRTParagraph, $level);
529
                                break;
530
                            case 'p:titleStyle':
531
                                $oSlideMaster->getTextStyles()->setTitleStyleAtLvl($oRTParagraph, $level);
532
                                break;
533
                        }
534
                    }
535
                }
536
            }
537
538
            // Load the theme
539
            foreach ($this->arrayRels[$oSlideMaster->getRelsIndex()] as $arrayRel) {
540
                if ($arrayRel['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme') {
541
                    $pptTheme = $this->oZip->getFromName('ppt/' . substr($arrayRel['Target'], strrpos($arrayRel['Target'], '../') + 3));
542
                    if ($pptTheme !== false) {
543
                        $this->loadTheme($pptTheme, $oSlideMaster);
544
                    }
545
                    break;
546
                }
547
            }
548
549
            // Load the Layoutslide
550
            foreach ($xmlReader->getElements('/p:sldMaster/p:sldLayoutIdLst/p:sldLayoutId') as $oElement) {
551
                if (!($oElement instanceof \DOMElement)) {
552
                    continue;
553
                }
554
                $rId = $oElement->getAttribute('r:id');
555
                // Get the path to the masterslide from the array with _rels files
556
                $pathLayoutSlide = isset($this->arrayRels[$oSlideMaster->getRelsIndex()][$rId]) ?
557
                    $this->arrayRels[$oSlideMaster->getRelsIndex()][$rId]['Target'] : '';
558
                if (!empty($pathLayoutSlide)) {
559
                    $pptLayoutSlide = $this->oZip->getFromName('ppt/' . substr($pathLayoutSlide, strrpos($pathLayoutSlide, '../') + 3));
560
                    if ($pptLayoutSlide !== false) {
561
                        $this->loadRels('ppt/slideLayouts/_rels/' . basename($pathLayoutSlide) . '.rels');
562
                        $oSlideMaster->addSlideLayout(
563
                            $this->loadLayoutSlide($pptLayoutSlide, basename($pathLayoutSlide), $oSlideMaster)
564
                        );
565
                    }
566
                }
567
            }
568
        }
569
    }
570
571
    /**
572
     * @param string $sPart
573
     * @param string $baseFile
574
     * @param SlideMaster $oSlideMaster
575
     * @return SlideLayout|null
576
     */
577
    protected function loadLayoutSlide($sPart, $baseFile, SlideMaster $oSlideMaster)
578
    {
579
        $xmlReader = new XMLReader();
580
        if ($xmlReader->getDomFromString($sPart)) {
581
            // Core
582
            $oSlideLayout = new SlideLayout($oSlideMaster);
583
            $oSlideLayout->setRelsIndex('ppt/slideLayouts/_rels/' . $baseFile . '.rels');
584
585
            // Name
586
            $oElement = $xmlReader->getElement('/p:sldLayout/p:cSld');
587
            if ($oElement instanceof \DOMElement && $oElement->hasAttribute('name')) {
588
                $oSlideLayout->setLayoutName($oElement->getAttribute('name'));
589
            }
590
591
            // Background
592
            $oElement = $xmlReader->getElement('/p:sldLayout/p:cSld/p:bg');
593
            if ($oElement instanceof \DOMElement) {
594
                $this->loadSlideBackground($xmlReader, $oElement, $oSlideLayout);
595
            }
596
597
            // ColorMapping
598
            $oElement = $xmlReader->getElement('/p:sldLayout/p:clrMapOvr/a:overrideClrMapping');
599
            if ($oElement instanceof \DOMElement && $oElement->hasAttributes()) {
600
                $colorMap = array();
601
                foreach ($oElement->attributes as $attr) {
602
                    $colorMap[$attr->nodeName] = $attr->nodeValue;
603
                }
604
                $oSlideLayout->colorMap->setMapping($colorMap);
605
            }
606
607
            // Shapes
608
            $oElements = $xmlReader->getElements('/p:sldLayout/p:cSld/p:spTree/*');
609
            if ($oElements) {
610
                $this->loadSlideShapes($oSlideLayout, $oElements, $xmlReader);
611
            }
612
            $this->arraySlideLayouts[$baseFile] = &$oSlideLayout;
613
            return $oSlideLayout;
614
        }
615
        return null;
616
    }
617
618
    /**
619
     * @param string $sPart
620
     * @param SlideMaster $oSlideMaster
621
     */
622
    protected function loadTheme($sPart, SlideMaster $oSlideMaster)
623
    {
624
        $xmlReader = new XMLReader();
625
        if ($xmlReader->getDomFromString($sPart)) {
626
            $oElements = $xmlReader->getElements('/a:theme/a:themeElements/a:clrScheme/*');
627
            if ($oElements) {
628
                foreach ($oElements as $oElement) {
629
                    $oSchemeColor = new SchemeColor();
630
                    $oSchemeColor->setValue(str_replace('a:', '', $oElement->tagName));
631
                    $colorElement = $xmlReader->getElement('*', $oElement);
632
                    if ($colorElement instanceof \DOMElement) {
633
                        if ($colorElement->hasAttribute('lastClr')) {
634
                            $oSchemeColor->setRGB($colorElement->getAttribute('lastClr'));
635
                        } elseif ($colorElement->hasAttribute('val')) {
636
                            $oSchemeColor->setRGB($colorElement->getAttribute('val'));
637
                        }
638
                    }
639
                    $oSlideMaster->addSchemeColor($oSchemeColor);
640
                }
641
            }
642
        }
643
    }
644
645
    /**
646
     * @param XMLReader $xmlReader
647
     * @param \DOMElement $oElement
648
     * @param AbstractSlide $oSlide
649
     */
650
    protected function loadSlideBackground(XMLReader $xmlReader, \DOMElement $oElement, AbstractSlide $oSlide)
651
    {
652
        // Background color
653
        $oElementColor = $xmlReader->getElement('p:bgPr/a:solidFill/a:srgbClr', $oElement);
654
        if ($oElementColor instanceof \DOMElement) {
655
            // Color
656
            $oColor = new Color();
657
            $oColor->setRGB($oElementColor->hasAttribute('val') ? $oElementColor->getAttribute('val') : null);
658
            // Background
659
            $oBackground = new Slide\Background\Color();
660
            $oBackground->setColor($oColor);
661
            // Slide Background
662
            $oSlide->setBackground($oBackground);
663
        }
664
665
        // Background scheme color
666
        $oElementSchemeColor = $xmlReader->getElement('p:bgRef/a:schemeClr', $oElement);
667
        if ($oElementSchemeColor instanceof \DOMElement) {
668
            // Color
669
            $oColor = new SchemeColor();
670
            $oColor->setValue($oElementSchemeColor->hasAttribute('val') ? $oElementSchemeColor->getAttribute('val') : null);
671
            // Background
672
            $oBackground = new Slide\Background\SchemeColor();
673
            $oBackground->setSchemeColor($oColor);
674
            // Slide Background
675
            $oSlide->setBackground($oBackground);
676
        }
677
678
        // Background image
679
        $oElementImage = $xmlReader->getElement('p:bgPr/a:blipFill/a:blip', $oElement);
680
        if ($oElementImage instanceof \DOMElement) {
681
            $relImg = $this->arrayRels[$oSlide->getRelsIndex()][$oElementImage->getAttribute('r:embed')];
682
            if (is_array($relImg)) {
683
                // File
684
                $pathImage = 'ppt/slides/' . $relImg['Target'];
685
                $pathImage = explode('/', $pathImage);
686
                foreach ($pathImage as $key => $partPath) {
687
                    if ($partPath == '..') {
688
                        unset($pathImage[$key - 1]);
689
                        unset($pathImage[$key]);
690
                    }
691
                }
692
                $pathImage = implode('/', $pathImage);
693
                $contentImg = $this->oZip->getFromName($pathImage);
694
695
                $tmpBkgImg = tempnam(sys_get_temp_dir(), 'PhpPresentationReaderPpt2007Bkg');
696
                file_put_contents($tmpBkgImg, $contentImg);
697
                // Background
698
                $oBackground = new Slide\Background\Image();
699
                $oBackground->setPath($tmpBkgImg);
700
                // Slide Background
701
                $oSlide->setBackground($oBackground);
702
            }
703
        }
704
    }
705
706
    /**
707
     * @param string $baseFile
708
     * @param Slide $oSlide
709
     */
710
    protected function loadSlideNote($baseFile, Slide $oSlide)
711
    {
712
        $sPart = $this->oZip->getFromName('ppt/notesSlides/' . $baseFile);
713
        $xmlReader = new XMLReader();
714
        if ($xmlReader->getDomFromString($sPart)) {
715
            $oNote = $oSlide->getNote();
716
717
            $arrayElements = $xmlReader->getElements('/p:notes/p:cSld/p:spTree/*');
718
            if ($arrayElements) {
719
                $this->loadSlideShapes($oNote, $arrayElements, $xmlReader);
720
            }
721
        }
722
    }
723
724
    /**
725
     * @param XMLReader $document
726
     * @param \DOMElement $node
727
     * @param AbstractSlide $oSlide
728
     */
729
    protected function loadShapeDrawing(XMLReader $document, \DOMElement $node, AbstractSlide $oSlide)
730
    {
731
        // Core
732
        $oShape = new Gd();
733
        $oShape->getShadow()->setVisible(false);
734
        // Variables
735
        $fileRels = $oSlide->getRelsIndex();
736
737
        $oElement = $document->getElement('p:nvPicPr/p:cNvPr', $node);
738
        if ($oElement instanceof \DOMElement) {
739
            $oShape->setName($oElement->hasAttribute('name') ? $oElement->getAttribute('name') : '');
740
            $oShape->setDescription($oElement->hasAttribute('descr') ? $oElement->getAttribute('descr') : '');
741
        }
742
743
        $oElement = $document->getElement('p:blipFill/a:blip', $node);
744
        if ($oElement instanceof \DOMElement) {
745
            if ($oElement->hasAttribute('r:embed') && isset($this->arrayRels[$fileRels][$oElement->getAttribute('r:embed')]['Target'])) {
746
                $pathImage = 'ppt/slides/' . $this->arrayRels[$fileRels][$oElement->getAttribute('r:embed')]['Target'];
747
                $pathImage = explode('/', $pathImage);
748
                foreach ($pathImage as $key => $partPath) {
749
                    if ($partPath == '..') {
750
                        unset($pathImage[$key - 1]);
751
                        unset($pathImage[$key]);
752
                    }
753
                }
754
                $pathImage = implode('/', $pathImage);
755
                $imageFile = $this->oZip->getFromName($pathImage);
756
                if (!empty($imageFile)) {
757
                    $oShape->setImageResource(imagecreatefromstring($imageFile));
758
                }
759
            }
760
        }
761
762
        $oElement = $document->getElement('p:spPr', $node);
763
        if ($oElement instanceof \DOMElement) {
764
            $oFill = $this->loadStyleFill($document, $oElement);
765
            $oShape->setFill($oFill);
766
        }
767
768
        $oElement = $document->getElement('p:spPr/a:xfrm', $node);
769
        if ($oElement instanceof \DOMElement) {
770
            if ($oElement->hasAttribute('rot')) {
771
                $oShape->setRotation(CommonDrawing::angleToDegrees($oElement->getAttribute('rot')));
772
            }
773
        }
774
775
        $oElement = $document->getElement('p:spPr/a:xfrm/a:off', $node);
776
        if ($oElement instanceof \DOMElement) {
777
            if ($oElement->hasAttribute('x')) {
778
                $oShape->setOffsetX(CommonDrawing::emuToPixels($oElement->getAttribute('x')));
779
            }
780
            if ($oElement->hasAttribute('y')) {
781
                $oShape->setOffsetY(CommonDrawing::emuToPixels($oElement->getAttribute('y')));
782
            }
783
        }
784
785
        $oElement = $document->getElement('p:spPr/a:xfrm/a:ext', $node);
786
        if ($oElement instanceof \DOMElement) {
787
            if ($oElement->hasAttribute('cx')) {
788
                $oShape->setWidth(CommonDrawing::emuToPixels($oElement->getAttribute('cx')));
789
            }
790
            if ($oElement->hasAttribute('cy')) {
791
                $oShape->setHeight(CommonDrawing::emuToPixels($oElement->getAttribute('cy')));
792
            }
793
        }
794
795
        $oElement = $document->getElement('p:spPr/a:effectLst', $node);
796
        if ($oElement instanceof \DOMElement) {
797
            $oShape->getShadow()->setVisible(true);
798
799
            $oSubElement = $document->getElement('a:outerShdw', $oElement);
800
            if ($oSubElement instanceof \DOMElement) {
801
                if ($oSubElement->hasAttribute('blurRad')) {
802
                    $oShape->getShadow()->setBlurRadius(CommonDrawing::emuToPixels($oSubElement->getAttribute('blurRad')));
803
                }
804
                if ($oSubElement->hasAttribute('dist')) {
805
                    $oShape->getShadow()->setDistance(CommonDrawing::emuToPixels($oSubElement->getAttribute('dist')));
806
                }
807
                if ($oSubElement->hasAttribute('dir')) {
808
                    $oShape->getShadow()->setDirection(CommonDrawing::angleToDegrees($oSubElement->getAttribute('dir')));
809
                }
810
                if ($oSubElement->hasAttribute('algn')) {
811
                    $oShape->getShadow()->setAlignment($oSubElement->getAttribute('algn'));
812
                }
813
            }
814
815
            $oSubElement = $document->getElement('a:outerShdw/a:srgbClr', $oElement);
816
            if ($oSubElement instanceof \DOMElement) {
817
                if ($oSubElement->hasAttribute('val')) {
818
                    $oColor = new Color();
819
                    $oColor->setRGB($oSubElement->getAttribute('val'));
820
                    $oShape->getShadow()->setColor($oColor);
821
                }
822
            }
823
824
            $oSubElement = $document->getElement('a:outerShdw/a:srgbClr/a:alpha', $oElement);
825
            if ($oSubElement instanceof \DOMElement) {
826
                if ($oSubElement->hasAttribute('val')) {
827
                    $oShape->getShadow()->setAlpha((int)$oSubElement->getAttribute('val') / 1000);
828
                }
829
            }
830
        }
831
832
        $oSlide->addShape($oShape);
833
    }
834
835
    /**
836
     * @param XMLReader $document
837
     * @param \DOMElement $node
838
     * @param AbstractSlide $oSlide
839
     * @throws \Exception
840
     */
841
    protected function loadShapeRichText(XMLReader $document, \DOMElement $node, $oSlide)
842
    {
843
        if (!$document->elementExists('p:txBody/a:p/a:r', $node)) {
844
            return;
845
        }
846
        // Core
847
        $oShape = $oSlide->createRichTextShape();
848
        $oShape->setParagraphs(array());
849
        // Variables
850
        if ($oSlide instanceof AbstractSlide) {
851
            $this->fileRels = $oSlide->getRelsIndex();
852
        }
853
854
        $oElement = $document->getElement('p:spPr/a:xfrm', $node);
855
        if ($oElement instanceof \DOMElement && $oElement->hasAttribute('rot')) {
856
            $oShape->setRotation(CommonDrawing::angleToDegrees($oElement->getAttribute('rot')));
857
        }
858
859
        $oElement = $document->getElement('p:spPr/a:xfrm/a:off', $node);
860
        if ($oElement instanceof \DOMElement) {
861
            if ($oElement->hasAttribute('x')) {
862
                $oShape->setOffsetX(CommonDrawing::emuToPixels($oElement->getAttribute('x')));
863
            }
864
            if ($oElement->hasAttribute('y')) {
865
                $oShape->setOffsetY(CommonDrawing::emuToPixels($oElement->getAttribute('y')));
866
            }
867
        }
868
869
        $oElement = $document->getElement('p:spPr/a:xfrm/a:ext', $node);
870
        if ($oElement instanceof \DOMElement) {
871
            if ($oElement->hasAttribute('cx')) {
872
                $oShape->setWidth(CommonDrawing::emuToPixels($oElement->getAttribute('cx')));
873
            }
874
            if ($oElement->hasAttribute('cy')) {
875
                $oShape->setHeight(CommonDrawing::emuToPixels($oElement->getAttribute('cy')));
876
            }
877
        }
878
879
        $oElement = $document->getElement('p:nvSpPr/p:nvPr/p:ph', $node);
880
        if ($oElement instanceof \DOMElement) {
881
            if ($oElement->hasAttribute('type')) {
882
                $placeholder = new Placeholder($oElement->getAttribute('type'));
883
                $oShape->setPlaceHolder($placeholder);
884
            }
885
        }
886
887
        $arrayElements = $document->getElements('p:txBody/a:p', $node);
888
        foreach ($arrayElements as $oElement) {
889
            $this->loadParagraph($document, $oElement, $oShape);
890
        }
891
892
        if (count($oShape->getParagraphs()) > 0) {
893
            $oShape->setActiveParagraph(0);
894
        }
895
    }
896
897
    /**
898
     * @param XMLReader $document
899
     * @param \DOMElement $node
900
     * @param AbstractSlide $oSlide
901
     * @throws \Exception
902
     */
903
    protected function loadShapeTable(XMLReader $document, \DOMElement $node, AbstractSlide $oSlide)
904
    {
905
        $this->fileRels = $oSlide->getRelsIndex();
906
907
        $oShape = $oSlide->createTableShape();
908
909
        $oElement = $document->getElement('p:cNvPr', $node);
910
        if ($oElement instanceof \DOMElement) {
911
            if ($oElement->hasAttribute('name')) {
912
                $oShape->setName($oElement->getAttribute('name'));
913
            }
914
            if ($oElement->hasAttribute('descr')) {
915
                $oShape->setDescription($oElement->getAttribute('descr'));
916
            }
917
        }
918
919
        $oElement = $document->getElement('p:xfrm/a:off', $node);
920
        if ($oElement instanceof \DOMElement) {
921
            if ($oElement->hasAttribute('x')) {
922
                $oShape->setOffsetX(CommonDrawing::emuToPixels($oElement->getAttribute('x')));
923
            }
924
            if ($oElement->hasAttribute('y')) {
925
                $oShape->setOffsetY(CommonDrawing::emuToPixels($oElement->getAttribute('y')));
926
            }
927
        }
928
929
        $oElement = $document->getElement('p:xfrm/a:ext', $node);
930
        if ($oElement instanceof \DOMElement) {
931
            if ($oElement->hasAttribute('cx')) {
932
                $oShape->setWidth(CommonDrawing::emuToPixels($oElement->getAttribute('cx')));
933
            }
934
            if ($oElement->hasAttribute('cy')) {
935
                $oShape->setHeight(CommonDrawing::emuToPixels($oElement->getAttribute('cy')));
936
            }
937
        }
938
939
        $arrayElements = $document->getElements('a:graphic/a:graphicData/a:tbl/a:tblGrid/a:gridCol', $node);
940
        $oShape->setNumColumns($arrayElements->length);
941
        $oShape->createRow();
942
        foreach ($arrayElements as $key => $oElement) {
943
            if ($oElement instanceof \DOMElement && $oElement->getAttribute('w')) {
944
                $oShape->getRow(0)->getCell($key)->setWidth(CommonDrawing::emuToPixels($oElement->getAttribute('w')));
945
            }
946
        }
947
948
        $arrayElements = $document->getElements('a:graphic/a:graphicData/a:tbl/a:tr', $node);
949
        foreach ($arrayElements as $keyRow => $oElementRow) {
950
            if (!($oElementRow instanceof \DOMElement)) {
951
                continue;
952
            }
953
            $oRow = $oShape->getRow($keyRow, true);
954
            if (is_null($oRow)) {
955
                $oRow = $oShape->createRow();
956
            }
957
            if ($oElementRow->hasAttribute('h')) {
958
                $oRow->setHeight(CommonDrawing::emuToPixels($oElementRow->getAttribute('h')));
959
            }
960
            $arrayElementsCell = $document->getElements('a:tc', $oElementRow);
961
            foreach ($arrayElementsCell as $keyCell => $oElementCell) {
962
                if (!($oElementCell instanceof \DOMElement)) {
963
                    continue;
964
                }
965
                $oCell = $oRow->getCell($keyCell);
966
                $oCell->setParagraphs(array());
967
                if ($oElementCell->hasAttribute('gridSpan')) {
968
                    $oCell->setColSpan($oElementCell->getAttribute('gridSpan'));
969
                }
970
                if ($oElementCell->hasAttribute('rowSpan')) {
971
                    $oCell->setRowSpan($oElementCell->getAttribute('rowSpan'));
972
                }
973
974
                foreach ($document->getElements('a:txBody/a:p', $oElementCell) as $oElementPara) {
975
                    $this->loadParagraph($document, $oElementPara, $oCell);
0 ignored issues
show
Bug introduced by
It seems like $oCell defined by $oRow->getCell($keyCell) on line 965 can be null; however, PhpOffice\PhpPresentatio...nt2007::loadParagraph() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
976
                }
977
978
                $oElementTcPr = $document->getElement('a:tcPr', $oElementCell);
979
                if ($oElementTcPr instanceof \DOMElement) {
980
                    $numParagraphs = count($oCell->getParagraphs());
981
                    if ($numParagraphs > 0) {
982
                        if ($oElementTcPr->hasAttribute('vert')) {
983
                            $oCell->getParagraph(0)->getAlignment()->setTextDirection($oElementTcPr->getAttribute('vert'));
984
                        }
985
                        if ($oElementTcPr->hasAttribute('anchor')) {
986
                            $oCell->getParagraph(0)->getAlignment()->setVertical($oElementTcPr->getAttribute('anchor'));
987
                        }
988
                        if ($oElementTcPr->hasAttribute('marB')) {
989
                            $oCell->getParagraph(0)->getAlignment()->setMarginBottom($oElementTcPr->getAttribute('marB'));
990
                        }
991
                        if ($oElementTcPr->hasAttribute('marL')) {
992
                            $oCell->getParagraph(0)->getAlignment()->setMarginLeft($oElementTcPr->getAttribute('marL'));
993
                        }
994
                        if ($oElementTcPr->hasAttribute('marR')) {
995
                            $oCell->getParagraph(0)->getAlignment()->setMarginRight($oElementTcPr->getAttribute('marR'));
996
                        }
997
                        if ($oElementTcPr->hasAttribute('marT')) {
998
                            $oCell->getParagraph(0)->getAlignment()->setMarginTop($oElementTcPr->getAttribute('marT'));
999
                        }
1000
                    }
1001
1002
                    $oFill = $this->loadStyleFill($document, $oElementTcPr);
1003
                    if ($oFill instanceof Fill) {
1004
                        $oCell->setFill($oFill);
1005
                    }
1006
1007
                    $oBorders = new Borders();
1008
                    $oElementBorderL = $document->getElement('a:lnL', $oElementTcPr);
1009
                    if ($oElementBorderL instanceof \DOMElement) {
1010
                        $this->loadStyleBorder($document, $oElementBorderL, $oBorders->getLeft());
1011
                    }
1012
                    $oElementBorderR = $document->getElement('a:lnR', $oElementTcPr);
1013
                    if ($oElementBorderR instanceof \DOMElement) {
1014
                        $this->loadStyleBorder($document, $oElementBorderR, $oBorders->getRight());
1015
                    }
1016
                    $oElementBorderT = $document->getElement('a:lnT', $oElementTcPr);
1017
                    if ($oElementBorderT instanceof \DOMElement) {
1018
                        $this->loadStyleBorder($document, $oElementBorderT, $oBorders->getTop());
1019
                    }
1020
                    $oElementBorderB = $document->getElement('a:lnB', $oElementTcPr);
1021
                    if ($oElementBorderB instanceof \DOMElement) {
1022
                        $this->loadStyleBorder($document, $oElementBorderB, $oBorders->getBottom());
1023
                    }
1024
                    $oElementBorderDiagDown = $document->getElement('a:lnTlToBr', $oElementTcPr);
1025
                    if ($oElementBorderDiagDown instanceof \DOMElement) {
1026
                        $this->loadStyleBorder($document, $oElementBorderDiagDown, $oBorders->getDiagonalDown());
1027
                    }
1028
                    $oElementBorderDiagUp = $document->getElement('a:lnBlToTr', $oElementTcPr);
1029
                    if ($oElementBorderDiagUp instanceof \DOMElement) {
1030
                        $this->loadStyleBorder($document, $oElementBorderDiagUp, $oBorders->getDiagonalUp());
1031
                    }
1032
                    $oCell->setBorders($oBorders);
1033
                }
1034
            }
1035
        }
1036
    }
1037
1038
    /**
1039
     * @param XMLReader $document
1040
     * @param \DOMElement $oElement
1041
     * @param Cell|RichText $oShape
1042
     * @throws \Exception
1043
     */
1044
    protected function loadParagraph(XMLReader $document, \DOMElement $oElement, $oShape)
1045
    {
1046
        // Core
1047
        $oParagraph = $oShape->createParagraph();
1048
        $oParagraph->setRichTextElements(array());
1049
1050
        $oSubElement = $document->getElement('a:pPr', $oElement);
1051
        if ($oSubElement instanceof \DOMElement) {
1052
            if ($oSubElement->hasAttribute('algn')) {
1053
                $oParagraph->getAlignment()->setHorizontal($oSubElement->getAttribute('algn'));
1054
            }
1055
            if ($oSubElement->hasAttribute('fontAlgn')) {
1056
                $oParagraph->getAlignment()->setVertical($oSubElement->getAttribute('fontAlgn'));
1057
            }
1058
            if ($oSubElement->hasAttribute('marL')) {
1059
                $oParagraph->getAlignment()->setMarginLeft(CommonDrawing::emuToPixels($oSubElement->getAttribute('marL')));
1060
            }
1061
            if ($oSubElement->hasAttribute('marR')) {
1062
                $oParagraph->getAlignment()->setMarginRight(CommonDrawing::emuToPixels($oSubElement->getAttribute('marR')));
1063
            }
1064
            if ($oSubElement->hasAttribute('indent')) {
1065
                $oParagraph->getAlignment()->setIndent(CommonDrawing::emuToPixels($oSubElement->getAttribute('indent')));
1066
            }
1067
            if ($oSubElement->hasAttribute('lvl')) {
1068
                $oParagraph->getAlignment()->setLevel($oSubElement->getAttribute('lvl'));
1069
            }
1070
1071
            $oParagraph->getBulletStyle()->setBulletType(Bullet::TYPE_NONE);
1072
1073
            $oElementBuFont = $document->getElement('a:buFont', $oSubElement);
1074
            if ($oElementBuFont instanceof \DOMElement) {
1075
                if ($oElementBuFont->hasAttribute('typeface')) {
1076
                    $oParagraph->getBulletStyle()->setBulletFont($oElementBuFont->getAttribute('typeface'));
1077
                }
1078
            }
1079
            $oElementBuChar = $document->getElement('a:buChar', $oSubElement);
1080
            if ($oElementBuChar instanceof \DOMElement) {
1081
                $oParagraph->getBulletStyle()->setBulletType(Bullet::TYPE_BULLET);
1082
                if ($oElementBuChar->hasAttribute('char')) {
1083
                    $oParagraph->getBulletStyle()->setBulletChar($oElementBuChar->getAttribute('char'));
1084
                }
1085
            }
1086
            $oElementBuAutoNum = $document->getElement('a:buAutoNum', $oSubElement);
1087
            if ($oElementBuAutoNum instanceof \DOMElement) {
1088
                $oParagraph->getBulletStyle()->setBulletType(Bullet::TYPE_NUMERIC);
1089
                if ($oElementBuAutoNum->hasAttribute('type')) {
1090
                    $oParagraph->getBulletStyle()->setBulletNumericStyle($oElementBuAutoNum->getAttribute('type'));
1091
                }
1092
                if ($oElementBuAutoNum->hasAttribute('startAt') && $oElementBuAutoNum->getAttribute('startAt') != 1) {
1093
                    $oParagraph->getBulletStyle()->setBulletNumericStartAt($oElementBuAutoNum->getAttribute('startAt'));
1094
                }
1095
            }
1096
            $oElementBuClr = $document->getElement('a:buClr', $oSubElement);
1097
            if ($oElementBuClr instanceof \DOMElement) {
1098
                $oColor = new Color();
1099
                /**
1100
                 * @todo Create protected for reading Color
1101
                 */
1102
                $oElementColor = $document->getElement('a:srgbClr', $oElementBuClr);
1103
                if ($oElementColor instanceof \DOMElement) {
1104
                    $oColor->setRGB($oElementColor->hasAttribute('val') ? $oElementColor->getAttribute('val') : null);
1105
                }
1106
                $oParagraph->getBulletStyle()->setBulletColor($oColor);
1107
            }
1108
        }
1109
        $arraySubElements = $document->getElements('(a:r|a:br)', $oElement);
1110
        foreach ($arraySubElements as $oSubElement) {
1111
            if ($oSubElement->tagName == 'a:br') {
1112
                $oParagraph->createBreak();
1113
            }
1114
            if ($oSubElement->tagName == 'a:r') {
1115
                $oElementrPr = $document->getElement('a:rPr', $oSubElement);
1116
                if (is_object($oElementrPr)) {
1117
                    $oText = $oParagraph->createTextRun();
1118
1119
                    if ($oElementrPr->hasAttribute('b')) {
0 ignored issues
show
Bug introduced by
The method hasAttribute() does not exist on DOMNode. Did you maybe mean hasAttributes()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1120
                        $att = $oElementrPr->getAttribute('b');
1121
                        $oText->getFont()->setBold($att == 'true' || $att == '1' ? true : false);
1122
                    }
1123
                    if ($oElementrPr->hasAttribute('i')) {
0 ignored issues
show
Bug introduced by
The method hasAttribute() does not exist on DOMNode. Did you maybe mean hasAttributes()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1124
                        $att = $oElementrPr->getAttribute('i');
1125
                        $oText->getFont()->setItalic($att == 'true' || $att == '1' ? true : false);
1126
                    }
1127
                    if ($oElementrPr->hasAttribute('strike')) {
0 ignored issues
show
Bug introduced by
The method hasAttribute() does not exist on DOMNode. Did you maybe mean hasAttributes()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1128
                        $oText->getFont()->setStrikethrough($oElementrPr->getAttribute('strike') == 'noStrike' ? false : true);
1129
                    }
1130
                    if ($oElementrPr->hasAttribute('sz')) {
0 ignored issues
show
Bug introduced by
The method hasAttribute() does not exist on DOMNode. Did you maybe mean hasAttributes()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1131
                        $oText->getFont()->setSize((int)($oElementrPr->getAttribute('sz') / 100));
1132
                    }
1133
                    if ($oElementrPr->hasAttribute('u')) {
0 ignored issues
show
Bug introduced by
The method hasAttribute() does not exist on DOMNode. Did you maybe mean hasAttributes()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1134
                        $oText->getFont()->setUnderline($oElementrPr->getAttribute('u'));
1135
                    }
1136
                    // Color
1137
                    $oElementSrgbClr = $document->getElement('a:solidFill/a:srgbClr', $oElementrPr);
0 ignored issues
show
Documentation introduced by
$oElementrPr is of type object<DOMNode>, but the function expects a null|object<DOMElement>.

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...
1138
                    if (is_object($oElementSrgbClr) && $oElementSrgbClr->hasAttribute('val')) {
0 ignored issues
show
Bug introduced by
The method hasAttribute() does not exist on DOMNode. Did you maybe mean hasAttributes()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1139
                        $oColor = new Color();
1140
                        $oColor->setRGB($oElementSrgbClr->getAttribute('val'));
1141
                        $oText->getFont()->setColor($oColor);
1142
                    }
1143
                    // Hyperlink
1144
                    $oElementHlinkClick = $document->getElement('a:hlinkClick', $oElementrPr);
0 ignored issues
show
Documentation introduced by
$oElementrPr is of type object<DOMNode>, but the function expects a null|object<DOMElement>.

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...
1145
                    if (is_object($oElementHlinkClick)) {
1146
                        if ($oElementHlinkClick->hasAttribute('tooltip')) {
0 ignored issues
show
Bug introduced by
The method hasAttribute() does not exist on DOMNode. Did you maybe mean hasAttributes()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1147
                            $oText->getHyperlink()->setTooltip($oElementHlinkClick->getAttribute('tooltip'));
1148
                        }
1149
                        if ($oElementHlinkClick->hasAttribute('r:id') && isset($this->arrayRels[$this->fileRels][$oElementHlinkClick->getAttribute('r:id')]['Target'])) {
0 ignored issues
show
Bug introduced by
The method hasAttribute() does not exist on DOMNode. Did you maybe mean hasAttributes()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1150
                            $oText->getHyperlink()->setUrl($this->arrayRels[$this->fileRels][$oElementHlinkClick->getAttribute('r:id')]['Target']);
1151
                        }
1152
                    }
1153
                    //} else {
1154
                    // $oText = $oParagraph->createText();
1155
1156
                    $oSubSubElement = $document->getElement('a:t', $oSubElement);
1157
                    $oText->setText($oSubSubElement->nodeValue);
1158
                }
1159
            }
1160
        }
1161
    }
1162
1163
    /**
1164
     * @param XMLReader $xmlReader
1165
     * @param \DOMElement $oElement
1166
     * @param Border $oBorder
1167
     */
1168
    protected function loadStyleBorder(XMLReader $xmlReader, \DOMElement $oElement, Border $oBorder)
1169
    {
1170
        if ($oElement->hasAttribute('w')) {
1171
            $oBorder->setLineWidth($oElement->getAttribute('w') / 12700);
1172
        }
1173
        if ($oElement->hasAttribute('cmpd')) {
1174
            $oBorder->setLineStyle($oElement->getAttribute('cmpd'));
1175
        }
1176
1177
        $oElementNoFill = $xmlReader->getElement('a:noFill', $oElement);
1178
        if ($oElementNoFill instanceof \DOMElement && $oBorder->getLineStyle() == Border::LINE_SINGLE) {
1179
            $oBorder->setLineStyle(Border::LINE_NONE);
1180
        }
1181
1182
        $oElementColor = $xmlReader->getElement('a:solidFill/a:srgbClr', $oElement);
1183
        if ($oElementColor instanceof \DOMElement) {
1184
            $oBorder->setColor($this->loadStyleColor($xmlReader, $oElementColor));
1185
        }
1186
1187
        $oElementDashStyle = $xmlReader->getElement('a:prstDash', $oElement);
1188
        if ($oElementDashStyle instanceof \DOMElement && $oElementDashStyle->hasAttribute('val')) {
1189
            $oBorder->setDashStyle($oElementDashStyle->getAttribute('val'));
1190
        }
1191
    }
1192
1193
    /**
1194
     * @param XMLReader $xmlReader
1195
     * @param \DOMElement $oElement
1196
     * @return Color
1197
     */
1198
    protected function loadStyleColor(XMLReader $xmlReader, \DOMElement $oElement)
1199
    {
1200
        $oColor = new Color();
1201
        $oColor->setRGB($oElement->getAttribute('val'));
1202
        $oElementAlpha = $xmlReader->getElement('a:alpha', $oElement);
1203
        if ($oElementAlpha instanceof \DOMElement && $oElementAlpha->hasAttribute('val')) {
1204
            $alpha = strtoupper(dechex((($oElementAlpha->getAttribute('val') / 1000) / 100) * 255));
1205
            $oColor->setRGB($oElement->getAttribute('val'), $alpha);
1206
        }
1207
        return $oColor;
1208
    }
1209
1210
    /**
1211
     * @param XMLReader $xmlReader
1212
     * @param \DOMElement $oElement
1213
     * @return null|Fill
1214
     */
1215
    protected function loadStyleFill(XMLReader $xmlReader, \DOMElement $oElement)
1216
    {
1217
        // Gradient fill
1218
        $oElementFill = $xmlReader->getElement('a:gradFill', $oElement);
1219
        if ($oElementFill instanceof \DOMElement) {
1220
            $oFill = new Fill();
1221
            $oFill->setFillType(Fill::FILL_GRADIENT_LINEAR);
1222
1223
            $oElementColor = $xmlReader->getElement('a:gsLst/a:gs[@pos="0"]/a:srgbClr', $oElementFill);
1224
            if ($oElementColor instanceof \DOMElement && $oElementColor->hasAttribute('val')) {
1225
                $oFill->setStartColor($this->loadStyleColor($xmlReader, $oElementColor));
1226
            }
1227
1228
            $oElementColor = $xmlReader->getElement('a:gsLst/a:gs[@pos="100000"]/a:srgbClr', $oElementFill);
1229
            if ($oElementColor instanceof \DOMElement && $oElementColor->hasAttribute('val')) {
1230
                $oFill->setEndColor($this->loadStyleColor($xmlReader, $oElementColor));
1231
            }
1232
1233
            $oRotation = $xmlReader->getElement('a:lin', $oElementFill);
1234
            if ($oRotation instanceof \DOMElement && $oRotation->hasAttribute('ang')) {
1235
                $oFill->setRotation(CommonDrawing::angleToDegrees($oRotation->getAttribute('ang')));
1236
            }
1237
            return $oFill;
1238
        }
1239
1240
        // Solid fill
1241
        $oElementFill = $xmlReader->getElement('a:solidFill', $oElement);
1242
        if ($oElementFill instanceof \DOMElement) {
1243
            $oFill = new Fill();
1244
            $oFill->setFillType(Fill::FILL_SOLID);
1245
1246
            $oElementColor = $xmlReader->getElement('a:srgbClr', $oElementFill);
1247
            if ($oElementColor instanceof \DOMElement) {
1248
                $oFill->setStartColor($this->loadStyleColor($xmlReader, $oElementColor));
1249
            }
1250
            return $oFill;
1251
        }
1252
        return null;
1253
    }
1254
1255
    /**
1256
     * @param string $fileRels
1257
     * @return string
1258
     */
1259
    protected function loadRels($fileRels)
1260
    {
1261
        $sPart = $this->oZip->getFromName($fileRels);
1262
        if ($sPart !== false) {
1263
            $xmlReader = new XMLReader();
1264
            if ($xmlReader->getDomFromString($sPart)) {
1265
                foreach ($xmlReader->getElements('*') as $oNode) {
1266
                    if (!($oNode instanceof \DOMElement)) {
1267
                        continue;
1268
                    }
1269
                    $this->arrayRels[$fileRels][$oNode->getAttribute('Id')] = array(
1270
                        'Target' => $oNode->getAttribute('Target'),
1271
                        'Type' => $oNode->getAttribute('Type'),
1272
                    );
1273
                }
1274
            }
1275
        }
1276
    }
1277
1278
    /**
1279
     * @param $oSlide
1280
     * @param \DOMNodeList $oElements
1281
     * @param XMLReader $xmlReader
1282
     * @internal param $baseFile
1283
     */
1284
    protected function loadSlideShapes($oSlide, $oElements, $xmlReader)
1285
    {
1286
        foreach ($oElements as $oNode) {
1287
            switch ($oNode->tagName) {
1288
                case 'p:graphicFrame':
1289
                    $this->loadShapeTable($xmlReader, $oNode, $oSlide);
1290
                    break;
1291
                case 'p:pic':
1292
                    $this->loadShapeDrawing($xmlReader, $oNode, $oSlide);
1293
                    break;
1294
                case 'p:sp':
1295
                    $this->loadShapeRichText($xmlReader, $oNode, $oSlide);
1296
                    break;
1297
                default:
1298
                    //var_export($oNode->tagName);
1299
            }
1300
        }
1301
    }
1302
1303 5
    protected function loadEncryptedFile()
0 ignored issues
show
Coding Style Naming introduced by
The variable $CSPName is not named in camelCase.

This check marks variable names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
1304
    {
1305
        //return false;
1306 5
        $oOLE = new OLERead();
1307 5
        $oOLE->read($this->filename);
1308
1309 1
        $oStreamEncrypted = $oOLE->getStream($oOLE->encryptedPackage);
0 ignored issues
show
Bug introduced by
The property encryptedPackage does not seem to exist in PhpOffice\Common\Microsoft\OLERead.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1310
        $pos = 0;
1311
        $size = self::getInt4d($oStreamEncrypted, $pos);
1312
        $pos += 8;
1313
        $data = '';
1314
        for ($inc = 0 ; $inc < $size ; $inc++) {
0 ignored issues
show
Coding Style introduced by
Space found before first semicolon of FOR loop
Loading history...
Coding Style introduced by
Space found before second semicolon of FOR loop
Loading history...
1315
            $data .= pack('v', self::getInt1d($oStreamEncrypted, $pos + $inc));
1316
        }
1317
1318
        $oStream = $oOLE->getStream($oOLE->encryptionInfo);
0 ignored issues
show
Bug introduced by
The property encryptionInfo does not seem to exist in PhpOffice\Common\Microsoft\OLERead.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1319
        $pos = 0;
1320
        // EncryptionVersionInfo
1321
        $vMajor = self::getInt2d($oStream, $pos);
0 ignored issues
show
Unused Code introduced by
$vMajor 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...
1322
        $pos += 2;
1323
        $vMinor = self::getInt2d($oStream, $pos);
0 ignored issues
show
Unused Code introduced by
$vMinor 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...
1324
        $pos += 2;
1325
        // EncryptionHeader.Flags
1326
        $pos += 4;
1327
        // EncryptionHeaderSize
1328
        $size = self::getInt4d($oStream, $pos);
1329
        $pos += 4;
1330
        echo 'EncryptionHeaderSize : ' . $size. '<br />'; //
1331
1332
        // EncryptionHeader
1333
        // EncryptionHeader > Flags
1334
        $flags = self::getInt4d($oStream, $pos);
1335
        echo 'EncryptionHeader > Flags > fCryptoAPI : ' . (($flags >> 2) & bindec('1')). '<br />'; //
1336
        echo 'EncryptionHeader > Flags > fDocProps : ' . (($flags >> 3) & bindec('1')). '<br />'; //
1337
        echo 'EncryptionHeader > Flags > fExternal : ' . (($flags >> 4) & bindec('1')). '<br />'; //
1338
        echo 'EncryptionHeader > Flags > fAES : ' . (($flags >> 5) & bindec('1')). '<br />'; //
1339
        $pos += 4;
1340
        $size -= 4;
1341
        // EncryptionHeader > SizeExtra
1342
        $sizeExtra = self::getInt4d($oStream, $pos);
1343
        echo 'EncryptionHeader > SizeExtra : '.$sizeExtra. '<br />';
1344
        $pos += 4;
1345
        $size -= 4;
1346
        // EncryptionHeader > AlgID
1347
        $algID = self::getInt4d($oStream, $pos);
1348
        echo 'EncryptionHeader > AlgID :'.$algID.' ('.hexdec('0x00006801').' = 0x00006801 = RC4) -  ('.hexdec('0x0000660E').' = 0x0000660E = AES-128) - ('.hexdec('0x0000660F').' = 0x0000660F = AES-192) - ('.hexdec('0x00006610').' = 0x00006610 = AES-256)'. '<br />';
1349
        $pos += 4;
1350
        $size -= 4;
1351
        // EncryptionHeader > AlgIDHash
1352
        $algIDHash = self::getInt4d($oStream, $pos);
1353
        echo 'EncryptionHeader > AlgIDHash : '.$algIDHash. ' ('.hexdec('0x00008004').' = 0x00008004 = SHA1)'. '<br />';
1354
        $pos += 4;
1355
        $size -= 4;
1356
        // EncryptionHeader > KeySize
1357
        $keySize = self::getInt4d($oStream, $pos);
1358
        echo 'EncryptionHeader > KeySize : '.$keySize.  ' ('.hexdec('0x00000080').' = 0x00000080 = AES-128) - ('.hexdec('0x000000C0').' = 0x000000C0 = AES-192) - ('.hexdec('0x00000100').' = 0x00000100 = AES-256)'. '<br />';
1359
        $pos += 4;
1360
        $size -= 4;
1361
        // EncryptionHeader > ProviderType
1362
        $providerType = self::getInt4d($oStream, $pos);
1363
        echo 'EncryptionHeader > ProviderType : '.$providerType. ' ('.hexdec('0x00000018').' = 0x00000018)'. '<br />';
1364
        $pos += 4;
1365
        $size -= 4;
1366
        // EncryptionHeader > Reserved1
1367
        $pos += 4;
1368
        $size -= 4;
1369
        // EncryptionHeader > Reserved2
1370
        $pos += 4;
1371
        $size -= 4;
1372
        // EncryptionHeader > CSPName
1373
        $CSPName = '';
1374
        for ($inc = 0 ; $inc <= $size ; $inc += 2) {
0 ignored issues
show
Coding Style introduced by
Space found before first semicolon of FOR loop
Loading history...
Coding Style introduced by
Space found before second semicolon of FOR loop
Loading history...
1375
            $chr = self::getInt2d($oStream, $pos);
1376
            $pos += 2;
1377
            if ($chr == 0) {
1378
                break;
1379
            }
1380
            $CSPName .= chr($chr);
1381
        }
1382
        echo 'EncryptionHeader > CSPName : '.$CSPName. '<br />';
1383
        // EncryptionVerifier
1384
        // EncryptionVerifier > SaltSize
1385
        $saltSize = self::getInt4d($oStream, $pos);
1386
        echo 'EncryptionVerifier > SaltSize : '.$saltSize.' ('.hexdec('0x00000010').' = 0x00000010)';
1387
        hex_dump($saltSize);
1388
        $pos += 4;
1389
        // EncryptionVerifier > Salt
1390
        $salt = '';
1391
        for ($inc = 0 ; $inc < 16 ; $inc ++) {
0 ignored issues
show
Coding Style introduced by
Space found before first semicolon of FOR loop
Loading history...
Coding Style introduced by
Space found before second semicolon of FOR loop
Loading history...
1392
            $salt .= pack('v', self::getInt1d($oStream, $pos));
1393
            $pos += 1;
1394
        }
1395
        echo 'EncryptionVerifier > Salt : ';
1396
        hex_dump($salt);
1397
        // EncryptionVerifier > EncryptedVerifier
1398
        $encryptedVerifier = '';
1399
        for ($inc = 0 ; $inc < 16 ; $inc ++) {
0 ignored issues
show
Coding Style introduced by
Space found before first semicolon of FOR loop
Loading history...
Coding Style introduced by
Space found before second semicolon of FOR loop
Loading history...
1400
            $encryptedVerifier .= pack('v', self::getInt1d($oStream, $pos));
1401
            $pos += 1;
1402
        }
1403
        echo 'EncryptionVerifier > EncryptedVerifier : ';
1404
        hex_dump($encryptedVerifier);
1405
        // EncryptionVerifier > VerifierHashSize
1406
        $verifierHashSize = self::getInt4d($oStream, $pos);
1407
        echo 'EncryptionVerifier > VerifierHashSize ('.hexdec('0x00000010').' = 0x00000010) :';
1408
        hex_dump($verifierHashSize);
1409
        $pos += 4;
1410
        // EncryptionVerifier > EncryptedVerifierHash
1411
        // mon cas : AES donc 32
1412
        echo 'EncryptionVerifier > EncryptedVerifierHash :';
1413
        $encryptedVerifierHash = '';
1414
        for ($inc = 0 ; $inc < 32 ; $inc ++) {
0 ignored issues
show
Coding Style introduced by
Space found before first semicolon of FOR loop
Loading history...
Coding Style introduced by
Space found before second semicolon of FOR loop
Loading history...
1415
            $encryptedVerifierHash .= pack('v', self::getInt1d($oStream, $pos));
1416
            $pos += 1;
1417
        }
1418
        hex_dump($encryptedVerifierHash);
1419
1420
        // https://github.com/doy/spreadsheet-parsexlsx/pull/37/files#diff-e61fbe6112ca2b7a3c08a4ea62d74ffeR1314
1421
1422
        // https://msdn.microsoft.com/en-us/library/dd925430(v=office.12).aspx
1423
        // H0 = H(salt + password)
1424
        $hash = $salt . iconv("ISO-8859-1", "UTF-16LE", $this->getPassword());
1425
        echo 'Hash (length : '.strlen($hash).')';
1426
        hex_dump($hash);
1427
        for($inc = 0 ; $inc < 50000 ; $inc++) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FOR keyword; 0 found
Loading history...
Coding Style introduced by
Space found before first semicolon of FOR loop
Loading history...
Coding Style introduced by
Space found before second semicolon of FOR loop
Loading history...
1428
            $hash = sha1(pack('L', $inc).$hash, true);
1429
        }
1430
        echo 'Hash (length : '.strlen($hash).')';
1431
        hex_dump($hash);
1432
        //  Hn = H(iterator + Hn-1)
1433
        $hash = sha1($hash . 0x00000000, true);
1434
        echo 'Hash (length : '.strlen($hash).')';
1435
        hex_dump($hash);
1436
1437
        $keySize /=8;
1438
1439
        $x36 = '';
1440
        for($inc = 0 ; $inc < 64 ; $inc++) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FOR keyword; 0 found
Loading history...
Coding Style introduced by
Space found before first semicolon of FOR loop
Loading history...
Coding Style introduced by
Space found before second semicolon of FOR loop
Loading history...
1441
            $x36 .= pack('H*', '36');
1442
        }
1443
        echo 'x36 (length : '.strlen($x36).')';
1444
        hex_dump($x36);
1445
1446
        $x1 = ($x36 ^ $hash);
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $x1. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
1447
        echo 'Hash = $x36 xor $hash (length : '.strlen($x1).')';
1448
        hex_dump($x1);
1449
1450
        if (strlen($x1) >= $keySize) {
1451
            $hash = substr($x1, 0, $keySize);
1452
        } else {
1453
            $x5C = '';
1454
            for($inc = 0 ; $inc < 64 ; $inc++) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FOR keyword; 0 found
Loading history...
Coding Style introduced by
Space found before first semicolon of FOR loop
Loading history...
Coding Style introduced by
Space found before second semicolon of FOR loop
Loading history...
1455
                $x5C .= pack('H*', '5C');
1456
            }
1457
            echo '$x5C (length : '.strlen($x5C).')';
1458
            hex_dump($x5C);
1459
1460
            $x2 = ($x5C ^ $hash);
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $x2. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
1461
            echo '$x1 = $x5C xor $hash (length : '.strlen($x2).')';
1462
            hex_dump($x2);
1463
1464
            $hash = substr($x1.$x2, 0, $keySize);
1465
        }
1466
1467
        echo 'Final hash (length : '.strlen($hash).')';
1468
        hex_dump($hash);
1469
        // https://msdn.microsoft.com/en-us/library/dd926426(v=office.12).aspx
1470
        $verifier = openssl_decrypt($encryptedVerifier, 'AES-128-ECB', $hash, 0, '');
1471
        echo 'Verifier :';
1472
        hex_dump($verifier);
1473
        $verifierHash = openssl_decrypt($encryptedVerifierHash, 'AES-128-ECB', $hash, 0, '');
1474
        echo 'VerifierHash :';
1475
        hex_dump($verifierHash);
1476
1477
        $verifierHash0 = sha1($verifier, true);
1478
        echo 'VerifierHash :';
1479
        hex_dump($verifierHash);
1480
        echo 'VerifierHash sha1($verifier, true):';
1481
        hex_dump($verifierHash0);
1482
    }
1483
1484
    /**
1485
     * Read 8-bit unsigned integer
1486
     *
1487
     * @param string $data
1488
     * @param int $pos
1489
     * @return int
1490
     */
1491
    public static function getInt1d($data, $pos)
1492
    {
1493
        return ord($data[$pos]);
1494
    }
1495
1496
    /**
1497
     * Read 16-bit unsigned integer
1498
     *
1499
     * @param string $data
1500
     * @param int $pos
1501
     * @return int
1502
     */
1503
    public static function getInt2d($data, $pos)
1504
    {
1505
        return ord($data[$pos]) | (ord($data[$pos+1]) << 8);
1506
    }
1507
1508
    /**
1509
     * Read 32-bit signed integer
1510
     *
1511
     * @param string $data
1512
     * @param int $pos
1513
     * @return int
1514
     */
1515
    public static function getInt4d($data, $pos)
1516
    {
1517
        // FIX: represent numbers correctly on 64-bit system
1518
        // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
1519
        // Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
1520
        $or24 = ord($data[$pos + 3]);
1521
        if ($or24 >= 128) {
1522
            // negative number
1523
            $ord24 = -abs((256 - $or24) << 24);
1524
        } else {
1525
            $ord24 = ($or24 & 127) << 24;
1526
        }
1527
        return ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16) | $ord24;
1528
    }
1529
}
1530