Completed
Pull Request — develop (#208)
by Franck
16:00 queued 02:07
created

PowerPoint2007::getInt1d()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 2
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...
115
            }
116
        }
117
118 1
        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
     * @throws \Exception
144
     */
145 5
    protected function loadFile($pFilename)
146
    {
147 5
        $this->oPhpPresentation = new PhpPresentation();
148 5
        $this->oPhpPresentation->removeSlideByIndex();
149 5
        $this->oPhpPresentation->setAllMasterSlides(array());
150 5
        $this->filename = $pFilename;
151
152 5
        $this->oZip = new ZipArchive();
153
154 5
        if ($this->oZip->open($this->filename) == ZipArchive::ER_NOZIP) {
155 5
            $this->loadEncryptedFile();
156
            return $this->oPhpPresentation;
157
        }
158
159
        $docPropsCore = $this->oZip->getFromName('docProps/core.xml');
160
        if ($docPropsCore !== false) {
161
            $this->loadDocumentProperties($docPropsCore);
162
        }
163
164
        $docPropsCustom = $this->oZip->getFromName('docProps/custom.xml');
165
        if ($docPropsCustom !== false) {
166
            $this->loadCustomProperties($docPropsCustom);
167
        }
168
169
        $pptViewProps = $this->oZip->getFromName('ppt/viewProps.xml');
170
        if ($pptViewProps !== false) {
171
            $this->loadViewProperties($pptViewProps);
172
        }
173
174
        $pptPresentation = $this->oZip->getFromName('ppt/presentation.xml');
175
        if ($pptPresentation !== false) {
176
            $this->loadDocumentLayout($pptPresentation);
177
            $this->loadSlides($pptPresentation);
178
        }
179
180
        return $this->oPhpPresentation;
181
    }
182
183
    /**
184
     * Read Document Layout
185
     * @param $sPart
186
     */
187
    protected function loadDocumentLayout($sPart)
188
    {
189
        $xmlReader = new XMLReader();
190
        if ($xmlReader->getDomFromString($sPart)) {
191
            foreach ($xmlReader->getElements('/p:presentation/p:sldSz') as $oElement) {
192
                if (!($oElement instanceof \DOMElement)) {
193
                    continue;
194
                }
195
                $type = $oElement->getAttribute('type');
196
                $oLayout = $this->oPhpPresentation->getLayout();
197
                if ($type == DocumentLayout::LAYOUT_CUSTOM) {
198
                    $oLayout->setCX($oElement->getAttribute('cx'));
199
                    $oLayout->setCY($oElement->getAttribute('cy'));
200
                } else {
201
                    $oLayout->setDocumentLayout($type, true);
202
                    if ($oElement->getAttribute('cx') < $oElement->getAttribute('cy')) {
203
                        $oLayout->setDocumentLayout($type, false);
204
                    }
205
                }
206
            }
207
        }
208
    }
209
210
    /**
211
     * Read Document Properties
212
     * @param string $sPart
213
     */
214
    protected function loadDocumentProperties($sPart)
215
    {
216
        $xmlReader = new XMLReader();
217
        if ($xmlReader->getDomFromString($sPart)) {
218
            $arrayProperties = array(
219
                '/cp:coreProperties/dc:creator' => 'setCreator',
220
                '/cp:coreProperties/cp:lastModifiedBy' => 'setLastModifiedBy',
221
                '/cp:coreProperties/dc:title' => 'setTitle',
222
                '/cp:coreProperties/dc:description' => 'setDescription',
223
                '/cp:coreProperties/dc:subject' => 'setSubject',
224
                '/cp:coreProperties/cp:keywords' => 'setKeywords',
225
                '/cp:coreProperties/cp:category' => 'setCategory',
226
                '/cp:coreProperties/dcterms:created' => 'setCreated',
227
                '/cp:coreProperties/dcterms:modified' => 'setModified',
228
            );
229
            $oProperties = $this->oPhpPresentation->getDocumentProperties();
230
            foreach ($arrayProperties as $path => $property) {
231
                $oElement = $xmlReader->getElement($path);
232
                if ($oElement instanceof \DOMElement) {
233
                    if ($oElement->hasAttribute('xsi:type') && $oElement->getAttribute('xsi:type') == 'dcterms:W3CDTF') {
234
                        $oDateTime = new \DateTime();
235
                        $oDateTime->createFromFormat(\DateTime::W3C, $oElement->nodeValue);
236
                        $oProperties->{$property}($oDateTime->getTimestamp());
237
                    } else {
238
                        $oProperties->{$property}($oElement->nodeValue);
239
                    }
240
                }
241
            }
242
        }
243
    }
244
245
    /**
246
     * Read Custom Properties
247
     * @param string $sPart
248
     */
249
    protected function loadCustomProperties($sPart)
250
    {
251
        $xmlReader = new XMLReader();
252
        $sPart = str_replace(' xmlns="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"', '', $sPart);
253
        if ($xmlReader->getDomFromString($sPart)) {
254
            $pathMarkAsFinal = '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="_MarkAsFinal"]/vt:bool';
255
            if (is_object($oElement = $xmlReader->getElement($pathMarkAsFinal))) {
256
                if ($oElement->nodeValue == 'true') {
257
                    $this->oPhpPresentation->getPresentationProperties()->markAsFinal(true);
258
                }
259
            }
260
        }
261
    }
262
263
    /**
264
     * Read View Properties
265
     * @param string $sPart
266
     */
267
    protected function loadViewProperties($sPart)
268
    {
269
        $xmlReader = new XMLReader();
270
        if ($xmlReader->getDomFromString($sPart)) {
271
            $pathZoom = '/p:viewPr/p:slideViewPr/p:cSldViewPr/p:cViewPr/p:scale/a:sx';
272
            $oElement = $xmlReader->getElement($pathZoom);
273
            if ($oElement instanceof \DOMElement) {
274
                if ($oElement->hasAttribute('d') && $oElement->hasAttribute('n')) {
275
                    $this->oPhpPresentation->getPresentationProperties()->setZoom($oElement->getAttribute('n') / $oElement->getAttribute('d'));
276
                }
277
            }
278
        }
279
    }
280
281
    /**
282
     * Extract all slides
283
     * @param $sPart
284
     * @throws \Exception
285
     */
286
    protected function loadSlides($sPart)
287
    {
288
        $xmlReader = new XMLReader();
289
        if ($xmlReader->getDomFromString($sPart)) {
290
            $fileRels = 'ppt/_rels/presentation.xml.rels';
291
            $this->loadRels($fileRels);
292
            // Load the Masterslides
293
            $this->loadMasterSlides($xmlReader, $fileRels);
294
            // Continue with loading the slides
295
            foreach ($xmlReader->getElements('/p:presentation/p:sldIdLst/p:sldId') as $oElement) {
296
                if (!($oElement instanceof \DOMElement)) {
297
                    continue;
298
                }
299
                $rId = $oElement->getAttribute('r:id');
300
                $pathSlide = isset($this->arrayRels[$fileRels][$rId]) ? $this->arrayRels[$fileRels][$rId]['Target'] : '';
301
                if (!empty($pathSlide)) {
302
                    $pptSlide = $this->oZip->getFromName('ppt/' . $pathSlide);
303
                    if ($pptSlide !== false) {
304
                        $slideRels = 'ppt/slides/_rels/' . basename($pathSlide) . '.rels';
305
                        $this->loadRels($slideRels);
306
                        $this->loadSlide($pptSlide, basename($pathSlide));
307
                        foreach ($this->arrayRels[$slideRels] as $rel) {
308
                            if ($rel['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide') {
309
                                $this->loadSlideNote(basename($rel['Target']), $this->oPhpPresentation->getActiveSlide());
310
                            }
311
                        }
312
                    }
313
                }
314
            }
315
        }
316
    }
317
318
    /**
319
     * Extract all MasterSlides
320
     * @param XMLReader $xmlReader
321
     * @param string $fileRels
322
     * @throws \Exception
323
     */
324
    protected function loadMasterSlides(XMLReader $xmlReader, $fileRels)
325
    {
326
        // Get all the MasterSlide Id's from the presentation.xml file
327
        foreach ($xmlReader->getElements('/p:presentation/p:sldMasterIdLst/p:sldMasterId') as $oElement) {
328
            if (!($oElement instanceof \DOMElement)) {
329
                continue;
330
            }
331
            $rId = $oElement->getAttribute('r:id');
332
            // Get the path to the masterslide from the array with _rels files
333
            $pathMasterSlide = isset($this->arrayRels[$fileRels][$rId]) ?
334
                $this->arrayRels[$fileRels][$rId]['Target'] : '';
335
            if (!empty($pathMasterSlide)) {
336
                $pptMasterSlide = $this->oZip->getFromName('ppt/' . $pathMasterSlide);
337
                if ($pptMasterSlide !== false) {
338
                    $this->loadRels('ppt/slideMasters/_rels/' . basename($pathMasterSlide) . '.rels');
339
                    $this->loadMasterSlide($pptMasterSlide, basename($pathMasterSlide));
340
                }
341
            }
342
        }
343
    }
344
345
    /**
346
     * Extract data from slide
347
     * @param string $sPart
348
     * @param string $baseFile
349
     * @throws \Exception
350
     */
351
    protected function loadSlide($sPart, $baseFile)
352
    {
353
        $xmlReader = new XMLReader();
354
        if ($xmlReader->getDomFromString($sPart)) {
355
            // Core
356
            $oSlide = $this->oPhpPresentation->createSlide();
357
            $this->oPhpPresentation->setActiveSlideIndex($this->oPhpPresentation->getSlideCount() - 1);
358
            $oSlide->setRelsIndex('ppt/slides/_rels/' . $baseFile . '.rels');
359
360
            // Background
361
            $oElement = $xmlReader->getElement('/p:sld/p:cSld/p:bg/p:bgPr');
362
            if ($oElement instanceof \DOMElement) {
363
                $oElementColor = $xmlReader->getElement('a:solidFill/a:srgbClr', $oElement);
364
                if ($oElementColor instanceof \DOMElement) {
365
                    // Color
366
                    $oColor = new Color();
367
                    $oColor->setRGB($oElementColor->hasAttribute('val') ? $oElementColor->getAttribute('val') : null);
368
                    // Background
369
                    $oBackground = new Slide\Background\Color();
370
                    $oBackground->setColor($oColor);
371
                    // Slide Background
372
                    $oSlide = $this->oPhpPresentation->getActiveSlide();
373
                    $oSlide->setBackground($oBackground);
374
                }
375
                $oElementColor = $xmlReader->getElement('a:solidFill/a:schemeClr', $oElement);
376
                if ($oElementColor instanceof \DOMElement) {
377
                    // Color
378
                    $oColor = new SchemeColor();
379
                    $oColor->setValue($oElementColor->hasAttribute('val') ? $oElementColor->getAttribute('val') : null);
380
                    // Background
381
                    $oBackground = new Slide\Background\SchemeColor();
382
                    $oBackground->setSchemeColor($oColor);
383
                    // Slide Background
384
                    $oSlide = $this->oPhpPresentation->getActiveSlide();
385
                    $oSlide->setBackground($oBackground);
386
                }
387
                $oElementImage = $xmlReader->getElement('a:blipFill/a:blip', $oElement);
388
                if ($oElementImage instanceof \DOMElement) {
389
                    $relImg = $this->arrayRels['ppt/slides/_rels/' . $baseFile . '.rels'][$oElementImage->getAttribute('r:embed')];
390
                    if (is_array($relImg)) {
391
                        // File
392
                        $pathImage = 'ppt/slides/' . $relImg['Target'];
393
                        $pathImage = explode('/', $pathImage);
394
                        foreach ($pathImage as $key => $partPath) {
395
                            if ($partPath == '..') {
396
                                unset($pathImage[$key - 1]);
397
                                unset($pathImage[$key]);
398
                            }
399
                        }
400
                        $pathImage = implode('/', $pathImage);
401
                        $contentImg = $this->oZip->getFromName($pathImage);
402
403
                        $tmpBkgImg = tempnam(sys_get_temp_dir(), 'PhpPresentationReaderPpt2007Bkg');
404
                        file_put_contents($tmpBkgImg, $contentImg);
405
                        // Background
406
                        $oBackground = new Slide\Background\Image();
407
                        $oBackground->setPath($tmpBkgImg);
408
                        // Slide Background
409
                        $oSlide = $this->oPhpPresentation->getActiveSlide();
410
                        $oSlide->setBackground($oBackground);
411
                    }
412
                }
413
            }
414
415
            // Shapes
416
            $arrayElements = $xmlReader->getElements('/p:sld/p:cSld/p:spTree/*');
417
            if ($arrayElements) {
418
                $this->loadSlideShapes($oSlide, $arrayElements, $xmlReader);
419
            }
420
421
            // Layout
422
            $oSlide = $this->oPhpPresentation->getActiveSlide();
423
            foreach ($this->arrayRels['ppt/slides/_rels/' . $baseFile . '.rels'] as $valueRel) {
424
                if ($valueRel['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout') {
425
                    $layoutBasename = basename($valueRel['Target']);
426
                    if (array_key_exists($layoutBasename, $this->arraySlideLayouts)) {
427
                        $oSlide->setSlideLayout($this->arraySlideLayouts[$layoutBasename]);
428
                    }
429
                    break;
430
                }
431
            }
432
        }
433
    }
434
435
    /**
436
     * @param string $sPart
437
     * @param string $baseFile
438
     * @throws \Exception
439
     */
440
    protected function loadMasterSlide($sPart, $baseFile)
441
    {
442
        $xmlReader = new XMLReader();
443
        if ($xmlReader->getDomFromString($sPart)) {
444
            // Core
445
            $oSlideMaster = $this->oPhpPresentation->createMasterSlide();
446
            $oSlideMaster->setTextStyles(new TextStyle(false));
447
            $oSlideMaster->setRelsIndex('ppt/slideMasters/_rels/' . $baseFile . '.rels');
448
449
            // Background
450
            $oElement = $xmlReader->getElement('/p:sldMaster/p:cSld/p:bg');
451
            if ($oElement instanceof \DOMElement) {
452
                $this->loadSlideBackground($xmlReader, $oElement, $oSlideMaster);
453
            }
454
455
            // Shapes
456
            $arrayElements = $xmlReader->getElements('/p:sldMaster/p:cSld/p:spTree/*');
457
            if ($arrayElements) {
458
                $this->loadSlideShapes($oSlideMaster, $arrayElements, $xmlReader);
459
            }
460
            // Header & Footer
461
462
            // ColorMapping
463
            $colorMap = array();
464
            $oElement = $xmlReader->getElement('/p:sldMaster/p:clrMap');
465
            if ($oElement->hasAttributes()) {
466
                foreach ($oElement->attributes as $attr) {
467
                    $colorMap[$attr->nodeName] = $attr->nodeValue;
468
                }
469
                $oSlideMaster->colorMap->setMapping($colorMap);
470
            }
471
472
            // TextStyles
473
            $arrayElementTxStyles = $xmlReader->getElements('/p:sldMaster/p:txStyles/*');
474
            if ($arrayElementTxStyles) {
475
                foreach ($arrayElementTxStyles as $oElementTxStyle) {
476
                    $arrayElementsLvl = $xmlReader->getElements('/p:sldMaster/p:txStyles/' . $oElementTxStyle->nodeName . '/*');
477
                    foreach ($arrayElementsLvl as $oElementLvl) {
478
                        if (!($oElementLvl instanceof \DOMElement) || $oElementLvl->nodeName == 'a:extLst') {
479
                            continue;
480
                        }
481
                        $oRTParagraph = new Paragraph();
482
483
                        if ($oElementLvl->nodeName == 'a:defPPr') {
484
                            $level = 0;
485
                        } else {
486
                            $level = str_replace('a:lvl', '', $oElementLvl->nodeName);
487
                            $level = str_replace('pPr', '', $level);
488
                        }
489
490
                        if ($oElementLvl->hasAttribute('algn')) {
491
                            $oRTParagraph->getAlignment()->setHorizontal($oElementLvl->getAttribute('algn'));
492
                        }
493
                        if ($oElementLvl->hasAttribute('marL')) {
494
                            $val = $oElementLvl->getAttribute('marL');
495
                            $val = CommonDrawing::emuToPixels($val);
496
                            $oRTParagraph->getAlignment()->setMarginLeft($val);
497
                        }
498
                        if ($oElementLvl->hasAttribute('marR')) {
499
                            $val = $oElementLvl->getAttribute('marR');
500
                            $val = CommonDrawing::emuToPixels($val);
501
                            $oRTParagraph->getAlignment()->setMarginRight($val);
502
                        }
503
                        if ($oElementLvl->hasAttribute('indent')) {
504
                            $val = $oElementLvl->getAttribute('indent');
505
                            $val = CommonDrawing::emuToPixels($val);
506
                            $oRTParagraph->getAlignment()->setIndent($val);
507
                        }
508
                        $oElementLvlDefRPR = $xmlReader->getElement('a:defRPr', $oElementLvl);
509
                        if ($oElementLvlDefRPR instanceof \DOMElement) {
510
                            if ($oElementLvlDefRPR->hasAttribute('sz')) {
511
                                $oRTParagraph->getFont()->setSize($oElementLvlDefRPR->getAttribute('sz') / 100);
512
                            }
513
                            if ($oElementLvlDefRPR->hasAttribute('b') && $oElementLvlDefRPR->getAttribute('b') == 1) {
514
                                $oRTParagraph->getFont()->setBold(true);
515
                            }
516
                            if ($oElementLvlDefRPR->hasAttribute('i') && $oElementLvlDefRPR->getAttribute('i') == 1) {
517
                                $oRTParagraph->getFont()->setItalic(true);
518
                            }
519
                        }
520
                        $oElementSchemeColor = $xmlReader->getElement('a:defRPr/a:solidFill/a:schemeClr', $oElementLvl);
521
                        if ($oElementSchemeColor instanceof \DOMElement) {
522
                            if ($oElementSchemeColor->hasAttribute('val')) {
523
                                $oSchemeColor = new SchemeColor();
524
                                $oSchemeColor->setValue($oElementSchemeColor->getAttribute('val'));
525
                                $oRTParagraph->getFont()->setColor($oSchemeColor);
526
                            }
527
                        }
528
529
                        switch ($oElementTxStyle->nodeName) {
530
                            case 'p:bodyStyle':
531
                                $oSlideMaster->getTextStyles()->setBodyStyleAtLvl($oRTParagraph, $level);
532
                                break;
533
                            case 'p:otherStyle':
534
                                $oSlideMaster->getTextStyles()->setOtherStyleAtLvl($oRTParagraph, $level);
535
                                break;
536
                            case 'p:titleStyle':
537
                                $oSlideMaster->getTextStyles()->setTitleStyleAtLvl($oRTParagraph, $level);
538
                                break;
539
                        }
540
                    }
541
                }
542
            }
543
544
            // Load the theme
545
            foreach ($this->arrayRels[$oSlideMaster->getRelsIndex()] as $arrayRel) {
546
                if ($arrayRel['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme') {
547
                    $pptTheme = $this->oZip->getFromName('ppt/' . substr($arrayRel['Target'], strrpos($arrayRel['Target'], '../') + 3));
548
                    if ($pptTheme !== false) {
549
                        $this->loadTheme($pptTheme, $oSlideMaster);
550
                    }
551
                    break;
552
                }
553
            }
554
555
            // Load the Layoutslide
556
            foreach ($xmlReader->getElements('/p:sldMaster/p:sldLayoutIdLst/p:sldLayoutId') as $oElement) {
557
                if (!($oElement instanceof \DOMElement)) {
558
                    continue;
559
                }
560
                $rId = $oElement->getAttribute('r:id');
561
                // Get the path to the masterslide from the array with _rels files
562
                $pathLayoutSlide = isset($this->arrayRels[$oSlideMaster->getRelsIndex()][$rId]) ?
563
                    $this->arrayRels[$oSlideMaster->getRelsIndex()][$rId]['Target'] : '';
564
                if (!empty($pathLayoutSlide)) {
565
                    $pptLayoutSlide = $this->oZip->getFromName('ppt/' . substr($pathLayoutSlide, strrpos($pathLayoutSlide, '../') + 3));
566
                    if ($pptLayoutSlide !== false) {
567
                        $this->loadRels('ppt/slideLayouts/_rels/' . basename($pathLayoutSlide) . '.rels');
568
                        $oSlideMaster->addSlideLayout(
569
                            $this->loadLayoutSlide($pptLayoutSlide, basename($pathLayoutSlide), $oSlideMaster)
570
                        );
571
                    }
572
                }
573
            }
574
        }
575
    }
576
577
    /**
578
     * @param string $sPart
579
     * @param string $baseFile
580
     * @param SlideMaster $oSlideMaster
581
     * @return SlideLayout|null
582
     * @throws \Exception
583
     */
584
    protected function loadLayoutSlide($sPart, $baseFile, SlideMaster $oSlideMaster)
585
    {
586
        $xmlReader = new XMLReader();
587
        if ($xmlReader->getDomFromString($sPart)) {
588
            // Core
589
            $oSlideLayout = new SlideLayout($oSlideMaster);
590
            $oSlideLayout->setRelsIndex('ppt/slideLayouts/_rels/' . $baseFile . '.rels');
591
592
            // Name
593
            $oElement = $xmlReader->getElement('/p:sldLayout/p:cSld');
594
            if ($oElement instanceof \DOMElement && $oElement->hasAttribute('name')) {
595
                $oSlideLayout->setLayoutName($oElement->getAttribute('name'));
596
            }
597
598
            // Background
599
            $oElement = $xmlReader->getElement('/p:sldLayout/p:cSld/p:bg');
600
            if ($oElement instanceof \DOMElement) {
601
                $this->loadSlideBackground($xmlReader, $oElement, $oSlideLayout);
602
            }
603
604
            // ColorMapping
605
            $oElement = $xmlReader->getElement('/p:sldLayout/p:clrMapOvr/a:overrideClrMapping');
606
            if ($oElement instanceof \DOMElement && $oElement->hasAttributes()) {
607
                $colorMap = array();
608
                foreach ($oElement->attributes as $attr) {
609
                    $colorMap[$attr->nodeName] = $attr->nodeValue;
610
                }
611
                $oSlideLayout->colorMap->setMapping($colorMap);
612
            }
613
614
            // Shapes
615
            $oElements = $xmlReader->getElements('/p:sldLayout/p:cSld/p:spTree/*');
616
            if ($oElements) {
617
                $this->loadSlideShapes($oSlideLayout, $oElements, $xmlReader);
618
            }
619
            $this->arraySlideLayouts[$baseFile] = &$oSlideLayout;
620
            return $oSlideLayout;
621
        }
622
        return null;
623
    }
624
625
    /**
626
     * @param string $sPart
627
     * @param SlideMaster $oSlideMaster
628
     */
629
    protected function loadTheme($sPart, SlideMaster $oSlideMaster)
630
    {
631
        $xmlReader = new XMLReader();
632
        if ($xmlReader->getDomFromString($sPart)) {
633
            $oElements = $xmlReader->getElements('/a:theme/a:themeElements/a:clrScheme/*');
634
            if ($oElements) {
635
                foreach ($oElements as $oElement) {
636
                    $oSchemeColor = new SchemeColor();
637
                    $oSchemeColor->setValue(str_replace('a:', '', $oElement->tagName));
638
                    $colorElement = $xmlReader->getElement('*', $oElement);
639
                    if ($colorElement instanceof \DOMElement) {
640
                        if ($colorElement->hasAttribute('lastClr')) {
641
                            $oSchemeColor->setRGB($colorElement->getAttribute('lastClr'));
642
                        } elseif ($colorElement->hasAttribute('val')) {
643
                            $oSchemeColor->setRGB($colorElement->getAttribute('val'));
644
                        }
645
                    }
646
                    $oSlideMaster->addSchemeColor($oSchemeColor);
647
                }
648
            }
649
        }
650
    }
651
652
    /**
653
     * @param XMLReader $xmlReader
654
     * @param \DOMElement $oElement
655
     * @param AbstractSlide $oSlide
656
     * @throws \Exception
657
     */
658
    protected function loadSlideBackground(XMLReader $xmlReader, \DOMElement $oElement, AbstractSlide $oSlide)
659
    {
660
        // Background color
661
        $oElementColor = $xmlReader->getElement('p:bgPr/a:solidFill/a:srgbClr', $oElement);
662
        if ($oElementColor instanceof \DOMElement) {
663
            // Color
664
            $oColor = new Color();
665
            $oColor->setRGB($oElementColor->hasAttribute('val') ? $oElementColor->getAttribute('val') : null);
666
            // Background
667
            $oBackground = new Slide\Background\Color();
668
            $oBackground->setColor($oColor);
669
            // Slide Background
670
            $oSlide->setBackground($oBackground);
671
        }
672
673
        // Background scheme color
674
        $oElementSchemeColor = $xmlReader->getElement('p:bgRef/a:schemeClr', $oElement);
675
        if ($oElementSchemeColor instanceof \DOMElement) {
676
            // Color
677
            $oColor = new SchemeColor();
678
            $oColor->setValue($oElementSchemeColor->hasAttribute('val') ? $oElementSchemeColor->getAttribute('val') : null);
679
            // Background
680
            $oBackground = new Slide\Background\SchemeColor();
681
            $oBackground->setSchemeColor($oColor);
682
            // Slide Background
683
            $oSlide->setBackground($oBackground);
684
        }
685
686
        // Background image
687
        $oElementImage = $xmlReader->getElement('p:bgPr/a:blipFill/a:blip', $oElement);
688
        if ($oElementImage instanceof \DOMElement) {
689
            $relImg = $this->arrayRels[$oSlide->getRelsIndex()][$oElementImage->getAttribute('r:embed')];
690
            if (is_array($relImg)) {
691
                // File
692
                $pathImage = 'ppt/slides/' . $relImg['Target'];
693
                $pathImage = explode('/', $pathImage);
694
                foreach ($pathImage as $key => $partPath) {
695
                    if ($partPath == '..') {
696
                        unset($pathImage[$key - 1]);
697
                        unset($pathImage[$key]);
698
                    }
699
                }
700
                $pathImage = implode('/', $pathImage);
701
                $contentImg = $this->oZip->getFromName($pathImage);
702
703
                $tmpBkgImg = tempnam(sys_get_temp_dir(), 'PhpPresentationReaderPpt2007Bkg');
704
                file_put_contents($tmpBkgImg, $contentImg);
705
                // Background
706
                $oBackground = new Slide\Background\Image();
707
                $oBackground->setPath($tmpBkgImg);
708
                // Slide Background
709
                $oSlide->setBackground($oBackground);
710
            }
711
        }
712
    }
713
714
    /**
715
     * @param string $baseFile
716
     * @param Slide $oSlide
717
     * @throws \Exception
718
     */
719
    protected function loadSlideNote($baseFile, Slide $oSlide)
720
    {
721
        $sPart = $this->oZip->getFromName('ppt/notesSlides/' . $baseFile);
722
        $xmlReader = new XMLReader();
723
        if ($xmlReader->getDomFromString($sPart)) {
724
            $oNote = $oSlide->getNote();
725
726
            $arrayElements = $xmlReader->getElements('/p:notes/p:cSld/p:spTree/*');
727
            if ($arrayElements) {
728
                $this->loadSlideShapes($oNote, $arrayElements, $xmlReader);
729
            }
730
        }
731
    }
732
733
    /**
734
     * @param XMLReader $document
735
     * @param \DOMElement $node
736
     * @param AbstractSlide $oSlide
737
     * @throws \Exception
738
     */
739
    protected function loadShapeDrawing(XMLReader $document, \DOMElement $node, AbstractSlide $oSlide)
740
    {
741
        // Core
742
        $oShape = new Gd();
743
        $oShape->getShadow()->setVisible(false);
744
        // Variables
745
        $fileRels = $oSlide->getRelsIndex();
746
747
        $oElement = $document->getElement('p:nvPicPr/p:cNvPr', $node);
748
        if ($oElement instanceof \DOMElement) {
749
            $oShape->setName($oElement->hasAttribute('name') ? $oElement->getAttribute('name') : '');
750
            $oShape->setDescription($oElement->hasAttribute('descr') ? $oElement->getAttribute('descr') : '');
751
        }
752
753
        $oElement = $document->getElement('p:blipFill/a:blip', $node);
754
        if ($oElement instanceof \DOMElement) {
755
            if ($oElement->hasAttribute('r:embed') && isset($this->arrayRels[$fileRels][$oElement->getAttribute('r:embed')]['Target'])) {
756
                $pathImage = 'ppt/slides/' . $this->arrayRels[$fileRels][$oElement->getAttribute('r:embed')]['Target'];
757
                $pathImage = explode('/', $pathImage);
758
                foreach ($pathImage as $key => $partPath) {
759
                    if ($partPath == '..') {
760
                        unset($pathImage[$key - 1]);
761
                        unset($pathImage[$key]);
762
                    }
763
                }
764
                $pathImage = implode('/', $pathImage);
765
                $imageFile = $this->oZip->getFromName($pathImage);
766
                if (!empty($imageFile)) {
767
                    $oShape->setImageResource(imagecreatefromstring($imageFile));
768
                }
769
            }
770
        }
771
772
        $oElement = $document->getElement('p:spPr', $node);
773
        if ($oElement instanceof \DOMElement) {
774
            $oFill = $this->loadStyleFill($document, $oElement);
775
            $oShape->setFill($oFill);
776
        }
777
778
        $oElement = $document->getElement('p:spPr/a:xfrm', $node);
779
        if ($oElement instanceof \DOMElement) {
780
            if ($oElement->hasAttribute('rot')) {
781
                $oShape->setRotation(CommonDrawing::angleToDegrees($oElement->getAttribute('rot')));
782
            }
783
        }
784
785
        $oElement = $document->getElement('p:spPr/a:xfrm/a:off', $node);
786
        if ($oElement instanceof \DOMElement) {
787
            if ($oElement->hasAttribute('x')) {
788
                $oShape->setOffsetX(CommonDrawing::emuToPixels($oElement->getAttribute('x')));
789
            }
790
            if ($oElement->hasAttribute('y')) {
791
                $oShape->setOffsetY(CommonDrawing::emuToPixels($oElement->getAttribute('y')));
792
            }
793
        }
794
795
        $oElement = $document->getElement('p:spPr/a:xfrm/a:ext', $node);
796
        if ($oElement instanceof \DOMElement) {
797
            if ($oElement->hasAttribute('cx')) {
798
                $oShape->setWidth(CommonDrawing::emuToPixels($oElement->getAttribute('cx')));
799
            }
800
            if ($oElement->hasAttribute('cy')) {
801
                $oShape->setHeight(CommonDrawing::emuToPixels($oElement->getAttribute('cy')));
802
            }
803
        }
804
805
        $oElement = $document->getElement('p:spPr/a:effectLst', $node);
806
        if ($oElement instanceof \DOMElement) {
807
            $oShape->getShadow()->setVisible(true);
808
809
            $oSubElement = $document->getElement('a:outerShdw', $oElement);
810
            if ($oSubElement instanceof \DOMElement) {
811
                if ($oSubElement->hasAttribute('blurRad')) {
812
                    $oShape->getShadow()->setBlurRadius(CommonDrawing::emuToPixels($oSubElement->getAttribute('blurRad')));
813
                }
814
                if ($oSubElement->hasAttribute('dist')) {
815
                    $oShape->getShadow()->setDistance(CommonDrawing::emuToPixels($oSubElement->getAttribute('dist')));
816
                }
817
                if ($oSubElement->hasAttribute('dir')) {
818
                    $oShape->getShadow()->setDirection(CommonDrawing::angleToDegrees($oSubElement->getAttribute('dir')));
819
                }
820
                if ($oSubElement->hasAttribute('algn')) {
821
                    $oShape->getShadow()->setAlignment($oSubElement->getAttribute('algn'));
822
                }
823
            }
824
825
            $oSubElement = $document->getElement('a:outerShdw/a:srgbClr', $oElement);
826
            if ($oSubElement instanceof \DOMElement) {
827
                if ($oSubElement->hasAttribute('val')) {
828
                    $oColor = new Color();
829
                    $oColor->setRGB($oSubElement->getAttribute('val'));
830
                    $oShape->getShadow()->setColor($oColor);
831
                }
832
            }
833
834
            $oSubElement = $document->getElement('a:outerShdw/a:srgbClr/a:alpha', $oElement);
835
            if ($oSubElement instanceof \DOMElement) {
836
                if ($oSubElement->hasAttribute('val')) {
837
                    $oShape->getShadow()->setAlpha((int)$oSubElement->getAttribute('val') / 1000);
838
                }
839
            }
840
        }
841
842
        $oSlide->addShape($oShape);
843
    }
844
845
    /**
846
     * @param XMLReader $document
847
     * @param \DOMElement $node
848
     * @param AbstractSlide $oSlide
849
     * @throws \Exception
850
     */
851
    protected function loadShapeRichText(XMLReader $document, \DOMElement $node, $oSlide)
852
    {
853
        if (!$document->elementExists('p:txBody/a:p/a:r', $node)) {
854
            return;
855
        }
856
        // Core
857
        $oShape = $oSlide->createRichTextShape();
858
        $oShape->setParagraphs(array());
859
        // Variables
860
        if ($oSlide instanceof AbstractSlide) {
861
            $this->fileRels = $oSlide->getRelsIndex();
862
        }
863
864
        $oElement = $document->getElement('p:spPr/a:xfrm', $node);
865
        if ($oElement instanceof \DOMElement && $oElement->hasAttribute('rot')) {
866
            $oShape->setRotation(CommonDrawing::angleToDegrees($oElement->getAttribute('rot')));
867
        }
868
869
        $oElement = $document->getElement('p:spPr/a:xfrm/a:off', $node);
870
        if ($oElement instanceof \DOMElement) {
871
            if ($oElement->hasAttribute('x')) {
872
                $oShape->setOffsetX(CommonDrawing::emuToPixels($oElement->getAttribute('x')));
873
            }
874
            if ($oElement->hasAttribute('y')) {
875
                $oShape->setOffsetY(CommonDrawing::emuToPixels($oElement->getAttribute('y')));
876
            }
877
        }
878
879
        $oElement = $document->getElement('p:spPr/a:xfrm/a:ext', $node);
880
        if ($oElement instanceof \DOMElement) {
881
            if ($oElement->hasAttribute('cx')) {
882
                $oShape->setWidth(CommonDrawing::emuToPixels($oElement->getAttribute('cx')));
883
            }
884
            if ($oElement->hasAttribute('cy')) {
885
                $oShape->setHeight(CommonDrawing::emuToPixels($oElement->getAttribute('cy')));
886
            }
887
        }
888
889
        $oElement = $document->getElement('p:nvSpPr/p:nvPr/p:ph', $node);
890
        if ($oElement instanceof \DOMElement) {
891
            if ($oElement->hasAttribute('type')) {
892
                $placeholder = new Placeholder($oElement->getAttribute('type'));
893
                $oShape->setPlaceHolder($placeholder);
894
            }
895
        }
896
897
        $arrayElements = $document->getElements('p:txBody/a:p', $node);
898
        foreach ($arrayElements as $oElement) {
899
            $this->loadParagraph($document, $oElement, $oShape);
900
        }
901
902
        if (count($oShape->getParagraphs()) > 0) {
903
            $oShape->setActiveParagraph(0);
904
        }
905
    }
906
907
    /**
908
     * @param XMLReader $document
909
     * @param \DOMElement $node
910
     * @param AbstractSlide $oSlide
911
     * @throws \Exception
912
     */
913
    protected function loadShapeTable(XMLReader $document, \DOMElement $node, AbstractSlide $oSlide)
914
    {
915
        $this->fileRels = $oSlide->getRelsIndex();
916
917
        $oShape = $oSlide->createTableShape();
918
919
        $oElement = $document->getElement('p:cNvPr', $node);
920
        if ($oElement instanceof \DOMElement) {
921
            if ($oElement->hasAttribute('name')) {
922
                $oShape->setName($oElement->getAttribute('name'));
923
            }
924
            if ($oElement->hasAttribute('descr')) {
925
                $oShape->setDescription($oElement->getAttribute('descr'));
926
            }
927
        }
928
929
        $oElement = $document->getElement('p:xfrm/a:off', $node);
930
        if ($oElement instanceof \DOMElement) {
931
            if ($oElement->hasAttribute('x')) {
932
                $oShape->setOffsetX(CommonDrawing::emuToPixels($oElement->getAttribute('x')));
933
            }
934
            if ($oElement->hasAttribute('y')) {
935
                $oShape->setOffsetY(CommonDrawing::emuToPixels($oElement->getAttribute('y')));
936
            }
937
        }
938
939
        $oElement = $document->getElement('p:xfrm/a:ext', $node);
940
        if ($oElement instanceof \DOMElement) {
941
            if ($oElement->hasAttribute('cx')) {
942
                $oShape->setWidth(CommonDrawing::emuToPixels($oElement->getAttribute('cx')));
943
            }
944
            if ($oElement->hasAttribute('cy')) {
945
                $oShape->setHeight(CommonDrawing::emuToPixels($oElement->getAttribute('cy')));
946
            }
947
        }
948
949
        $arrayElements = $document->getElements('a:graphic/a:graphicData/a:tbl/a:tblGrid/a:gridCol', $node);
950
        $oShape->setNumColumns($arrayElements->length);
951
        $oShape->createRow();
952
        foreach ($arrayElements as $key => $oElement) {
953
            if ($oElement instanceof \DOMElement && $oElement->getAttribute('w')) {
954
                $oShape->getRow(0)->getCell($key)->setWidth(CommonDrawing::emuToPixels($oElement->getAttribute('w')));
955
            }
956
        }
957
958
        $arrayElements = $document->getElements('a:graphic/a:graphicData/a:tbl/a:tr', $node);
959
        foreach ($arrayElements as $keyRow => $oElementRow) {
960
            if (!($oElementRow instanceof \DOMElement)) {
961
                continue;
962
            }
963
            $oRow = $oShape->getRow($keyRow, true);
964
            if (is_null($oRow)) {
965
                $oRow = $oShape->createRow();
966
            }
967
            if ($oElementRow->hasAttribute('h')) {
968
                $oRow->setHeight(CommonDrawing::emuToPixels($oElementRow->getAttribute('h')));
969
            }
970
            $arrayElementsCell = $document->getElements('a:tc', $oElementRow);
971
            foreach ($arrayElementsCell as $keyCell => $oElementCell) {
972
                if (!($oElementCell instanceof \DOMElement)) {
973
                    continue;
974
                }
975
                $oCell = $oRow->getCell($keyCell);
976
                $oCell->setParagraphs(array());
977
                if ($oElementCell->hasAttribute('gridSpan')) {
978
                    $oCell->setColSpan($oElementCell->getAttribute('gridSpan'));
979
                }
980
                if ($oElementCell->hasAttribute('rowSpan')) {
981
                    $oCell->setRowSpan($oElementCell->getAttribute('rowSpan'));
982
                }
983
984
                foreach ($document->getElements('a:txBody/a:p', $oElementCell) as $oElementPara) {
985
                    $this->loadParagraph($document, $oElementPara, $oCell);
0 ignored issues
show
Bug introduced by
It seems like $oCell defined by $oRow->getCell($keyCell) on line 975 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...
986
                }
987
988
                $oElementTcPr = $document->getElement('a:tcPr', $oElementCell);
989
                if ($oElementTcPr instanceof \DOMElement) {
990
                    $numParagraphs = count($oCell->getParagraphs());
991
                    if ($numParagraphs > 0) {
992
                        if ($oElementTcPr->hasAttribute('vert')) {
993
                            $oCell->getParagraph(0)->getAlignment()->setTextDirection($oElementTcPr->getAttribute('vert'));
994
                        }
995
                        if ($oElementTcPr->hasAttribute('anchor')) {
996
                            $oCell->getParagraph(0)->getAlignment()->setVertical($oElementTcPr->getAttribute('anchor'));
997
                        }
998
                        if ($oElementTcPr->hasAttribute('marB')) {
999
                            $oCell->getParagraph(0)->getAlignment()->setMarginBottom($oElementTcPr->getAttribute('marB'));
1000
                        }
1001
                        if ($oElementTcPr->hasAttribute('marL')) {
1002
                            $oCell->getParagraph(0)->getAlignment()->setMarginLeft($oElementTcPr->getAttribute('marL'));
1003
                        }
1004
                        if ($oElementTcPr->hasAttribute('marR')) {
1005
                            $oCell->getParagraph(0)->getAlignment()->setMarginRight($oElementTcPr->getAttribute('marR'));
1006
                        }
1007
                        if ($oElementTcPr->hasAttribute('marT')) {
1008
                            $oCell->getParagraph(0)->getAlignment()->setMarginTop($oElementTcPr->getAttribute('marT'));
1009
                        }
1010
                    }
1011
1012
                    $oFill = $this->loadStyleFill($document, $oElementTcPr);
1013
                    if ($oFill instanceof Fill) {
1014
                        $oCell->setFill($oFill);
1015
                    }
1016
1017
                    $oBorders = new Borders();
1018
                    $oElementBorderL = $document->getElement('a:lnL', $oElementTcPr);
1019
                    if ($oElementBorderL instanceof \DOMElement) {
1020
                        $this->loadStyleBorder($document, $oElementBorderL, $oBorders->getLeft());
1021
                    }
1022
                    $oElementBorderR = $document->getElement('a:lnR', $oElementTcPr);
1023
                    if ($oElementBorderR instanceof \DOMElement) {
1024
                        $this->loadStyleBorder($document, $oElementBorderR, $oBorders->getRight());
1025
                    }
1026
                    $oElementBorderT = $document->getElement('a:lnT', $oElementTcPr);
1027
                    if ($oElementBorderT instanceof \DOMElement) {
1028
                        $this->loadStyleBorder($document, $oElementBorderT, $oBorders->getTop());
1029
                    }
1030
                    $oElementBorderB = $document->getElement('a:lnB', $oElementTcPr);
1031
                    if ($oElementBorderB instanceof \DOMElement) {
1032
                        $this->loadStyleBorder($document, $oElementBorderB, $oBorders->getBottom());
1033
                    }
1034
                    $oElementBorderDiagDown = $document->getElement('a:lnTlToBr', $oElementTcPr);
1035
                    if ($oElementBorderDiagDown instanceof \DOMElement) {
1036
                        $this->loadStyleBorder($document, $oElementBorderDiagDown, $oBorders->getDiagonalDown());
1037
                    }
1038
                    $oElementBorderDiagUp = $document->getElement('a:lnBlToTr', $oElementTcPr);
1039
                    if ($oElementBorderDiagUp instanceof \DOMElement) {
1040
                        $this->loadStyleBorder($document, $oElementBorderDiagUp, $oBorders->getDiagonalUp());
1041
                    }
1042
                    $oCell->setBorders($oBorders);
1043
                }
1044
            }
1045
        }
1046
    }
1047
1048
    /**
1049
     * @param XMLReader $document
1050
     * @param \DOMElement $oElement
1051
     * @param Cell|RichText $oShape
1052
     * @throws \Exception
1053
     */
1054
    protected function loadParagraph(XMLReader $document, \DOMElement $oElement, $oShape)
1055
    {
1056
        // Core
1057
        $oParagraph = $oShape->createParagraph();
1058
        $oParagraph->setRichTextElements(array());
1059
1060
        $oSubElement = $document->getElement('a:pPr', $oElement);
1061
        if ($oSubElement instanceof \DOMElement) {
1062
            if ($oSubElement->hasAttribute('algn')) {
1063
                $oParagraph->getAlignment()->setHorizontal($oSubElement->getAttribute('algn'));
1064
            }
1065
            if ($oSubElement->hasAttribute('fontAlgn')) {
1066
                $oParagraph->getAlignment()->setVertical($oSubElement->getAttribute('fontAlgn'));
1067
            }
1068
            if ($oSubElement->hasAttribute('marL')) {
1069
                $oParagraph->getAlignment()->setMarginLeft(CommonDrawing::emuToPixels($oSubElement->getAttribute('marL')));
1070
            }
1071
            if ($oSubElement->hasAttribute('marR')) {
1072
                $oParagraph->getAlignment()->setMarginRight(CommonDrawing::emuToPixels($oSubElement->getAttribute('marR')));
1073
            }
1074
            if ($oSubElement->hasAttribute('indent')) {
1075
                $oParagraph->getAlignment()->setIndent(CommonDrawing::emuToPixels($oSubElement->getAttribute('indent')));
1076
            }
1077
            if ($oSubElement->hasAttribute('lvl')) {
1078
                $oParagraph->getAlignment()->setLevel($oSubElement->getAttribute('lvl'));
1079
            }
1080
1081
            $oParagraph->getBulletStyle()->setBulletType(Bullet::TYPE_NONE);
1082
1083
            $oElementBuFont = $document->getElement('a:buFont', $oSubElement);
1084
            if ($oElementBuFont instanceof \DOMElement) {
1085
                if ($oElementBuFont->hasAttribute('typeface')) {
1086
                    $oParagraph->getBulletStyle()->setBulletFont($oElementBuFont->getAttribute('typeface'));
1087
                }
1088
            }
1089
            $oElementBuChar = $document->getElement('a:buChar', $oSubElement);
1090
            if ($oElementBuChar instanceof \DOMElement) {
1091
                $oParagraph->getBulletStyle()->setBulletType(Bullet::TYPE_BULLET);
1092
                if ($oElementBuChar->hasAttribute('char')) {
1093
                    $oParagraph->getBulletStyle()->setBulletChar($oElementBuChar->getAttribute('char'));
1094
                }
1095
            }
1096
            $oElementBuAutoNum = $document->getElement('a:buAutoNum', $oSubElement);
1097
            if ($oElementBuAutoNum instanceof \DOMElement) {
1098
                $oParagraph->getBulletStyle()->setBulletType(Bullet::TYPE_NUMERIC);
1099
                if ($oElementBuAutoNum->hasAttribute('type')) {
1100
                    $oParagraph->getBulletStyle()->setBulletNumericStyle($oElementBuAutoNum->getAttribute('type'));
1101
                }
1102
                if ($oElementBuAutoNum->hasAttribute('startAt') && $oElementBuAutoNum->getAttribute('startAt') != 1) {
1103
                    $oParagraph->getBulletStyle()->setBulletNumericStartAt($oElementBuAutoNum->getAttribute('startAt'));
1104
                }
1105
            }
1106
            $oElementBuClr = $document->getElement('a:buClr', $oSubElement);
1107
            if ($oElementBuClr instanceof \DOMElement) {
1108
                $oColor = new Color();
1109
                /**
1110
                 * @todo Create protected for reading Color
1111
                 */
1112
                $oElementColor = $document->getElement('a:srgbClr', $oElementBuClr);
1113
                if ($oElementColor instanceof \DOMElement) {
1114
                    $oColor->setRGB($oElementColor->hasAttribute('val') ? $oElementColor->getAttribute('val') : null);
1115
                }
1116
                $oParagraph->getBulletStyle()->setBulletColor($oColor);
1117
            }
1118
        }
1119
        $arraySubElements = $document->getElements('(a:r|a:br)', $oElement);
1120
        foreach ($arraySubElements as $oSubElement) {
1121
            if ($oSubElement->tagName == 'a:br') {
1122
                $oParagraph->createBreak();
1123
            }
1124
            if ($oSubElement->tagName == 'a:r') {
1125
                $oElementrPr = $document->getElement('a:rPr', $oSubElement);
1126
                if (is_object($oElementrPr)) {
1127
                    $oText = $oParagraph->createTextRun();
1128
1129
                    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...
1130
                        $att = $oElementrPr->getAttribute('b');
1131
                        $oText->getFont()->setBold($att == 'true' || $att == '1' ? true : false);
1132
                    }
1133
                    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...
1134
                        $att = $oElementrPr->getAttribute('i');
1135
                        $oText->getFont()->setItalic($att == 'true' || $att == '1' ? true : false);
1136
                    }
1137
                    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...
1138
                        $oText->getFont()->setStrikethrough($oElementrPr->getAttribute('strike') == 'noStrike' ? false : true);
1139
                    }
1140
                    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...
1141
                        $oText->getFont()->setSize((int)($oElementrPr->getAttribute('sz') / 100));
1142
                    }
1143
                    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...
1144
                        $oText->getFont()->setUnderline($oElementrPr->getAttribute('u'));
1145
                    }
1146
                    // Color
1147
                    $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...
1148
                    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...
1149
                        $oColor = new Color();
1150
                        $oColor->setRGB($oElementSrgbClr->getAttribute('val'));
1151
                        $oText->getFont()->setColor($oColor);
1152
                    }
1153
                    // Hyperlink
1154
                    $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...
1155
                    if (is_object($oElementHlinkClick)) {
1156
                        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...
1157
                            $oText->getHyperlink()->setTooltip($oElementHlinkClick->getAttribute('tooltip'));
1158
                        }
1159
                        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...
1160
                            $oText->getHyperlink()->setUrl($this->arrayRels[$this->fileRels][$oElementHlinkClick->getAttribute('r:id')]['Target']);
1161
                        }
1162
                    }
1163
                    //} else {
1164
                    // $oText = $oParagraph->createText();
1165
1166
                    $oSubSubElement = $document->getElement('a:t', $oSubElement);
1167
                    $oText->setText($oSubSubElement->nodeValue);
1168
                }
1169
            }
1170
        }
1171
    }
1172
1173
    /**
1174
     * @param XMLReader $xmlReader
1175
     * @param \DOMElement $oElement
1176
     * @param Border $oBorder
1177
     * @throws \Exception
1178
     */
1179
    protected function loadStyleBorder(XMLReader $xmlReader, \DOMElement $oElement, Border $oBorder)
1180
    {
1181
        if ($oElement->hasAttribute('w')) {
1182
            $oBorder->setLineWidth($oElement->getAttribute('w') / 12700);
1183
        }
1184
        if ($oElement->hasAttribute('cmpd')) {
1185
            $oBorder->setLineStyle($oElement->getAttribute('cmpd'));
1186
        }
1187
1188
        $oElementNoFill = $xmlReader->getElement('a:noFill', $oElement);
1189
        if ($oElementNoFill instanceof \DOMElement && $oBorder->getLineStyle() == Border::LINE_SINGLE) {
1190
            $oBorder->setLineStyle(Border::LINE_NONE);
1191
        }
1192
1193
        $oElementColor = $xmlReader->getElement('a:solidFill/a:srgbClr', $oElement);
1194
        if ($oElementColor instanceof \DOMElement) {
1195
            $oBorder->setColor($this->loadStyleColor($xmlReader, $oElementColor));
1196
        }
1197
1198
        $oElementDashStyle = $xmlReader->getElement('a:prstDash', $oElement);
1199
        if ($oElementDashStyle instanceof \DOMElement && $oElementDashStyle->hasAttribute('val')) {
1200
            $oBorder->setDashStyle($oElementDashStyle->getAttribute('val'));
1201
        }
1202
    }
1203
1204
    /**
1205
     * @param XMLReader $xmlReader
1206
     * @param \DOMElement $oElement
1207
     * @return Color
1208
     */
1209
    protected function loadStyleColor(XMLReader $xmlReader, \DOMElement $oElement)
1210
    {
1211
        $oColor = new Color();
1212
        $oColor->setRGB($oElement->getAttribute('val'));
1213
        $oElementAlpha = $xmlReader->getElement('a:alpha', $oElement);
1214
        if ($oElementAlpha instanceof \DOMElement && $oElementAlpha->hasAttribute('val')) {
1215
            $alpha = strtoupper(dechex((($oElementAlpha->getAttribute('val') / 1000) / 100) * 255));
1216
            $oColor->setRGB($oElement->getAttribute('val'), $alpha);
1217
        }
1218
        return $oColor;
1219
    }
1220
1221
    /**
1222
     * @param XMLReader $xmlReader
1223
     * @param \DOMElement $oElement
1224
     * @return null|Fill
1225
     * @throws \Exception
1226
     */
1227
    protected function loadStyleFill(XMLReader $xmlReader, \DOMElement $oElement)
1228
    {
1229
        // Gradient fill
1230
        $oElementFill = $xmlReader->getElement('a:gradFill', $oElement);
1231
        if ($oElementFill instanceof \DOMElement) {
1232
            $oFill = new Fill();
1233
            $oFill->setFillType(Fill::FILL_GRADIENT_LINEAR);
1234
1235
            $oElementColor = $xmlReader->getElement('a:gsLst/a:gs[@pos="0"]/a:srgbClr', $oElementFill);
1236
            if ($oElementColor instanceof \DOMElement && $oElementColor->hasAttribute('val')) {
1237
                $oFill->setStartColor($this->loadStyleColor($xmlReader, $oElementColor));
1238
            }
1239
1240
            $oElementColor = $xmlReader->getElement('a:gsLst/a:gs[@pos="100000"]/a:srgbClr', $oElementFill);
1241
            if ($oElementColor instanceof \DOMElement && $oElementColor->hasAttribute('val')) {
1242
                $oFill->setEndColor($this->loadStyleColor($xmlReader, $oElementColor));
1243
            }
1244
1245
            $oRotation = $xmlReader->getElement('a:lin', $oElementFill);
1246
            if ($oRotation instanceof \DOMElement && $oRotation->hasAttribute('ang')) {
1247
                $oFill->setRotation(CommonDrawing::angleToDegrees($oRotation->getAttribute('ang')));
1248
            }
1249
            return $oFill;
1250
        }
1251
1252
        // Solid fill
1253
        $oElementFill = $xmlReader->getElement('a:solidFill', $oElement);
1254
        if ($oElementFill instanceof \DOMElement) {
1255
            $oFill = new Fill();
1256
            $oFill->setFillType(Fill::FILL_SOLID);
1257
1258
            $oElementColor = $xmlReader->getElement('a:srgbClr', $oElementFill);
1259
            if ($oElementColor instanceof \DOMElement) {
1260
                $oFill->setStartColor($this->loadStyleColor($xmlReader, $oElementColor));
1261
            }
1262
            return $oFill;
1263
        }
1264
        return null;
1265
    }
1266
1267
    /**
1268
     * @param string $fileRels
1269
     */
1270
    protected function loadRels($fileRels)
1271
    {
1272
        $sPart = $this->oZip->getFromName($fileRels);
1273
        if ($sPart !== false) {
1274
            $xmlReader = new XMLReader();
1275
            if ($xmlReader->getDomFromString($sPart)) {
1276
                foreach ($xmlReader->getElements('*') as $oNode) {
1277
                    if (!($oNode instanceof \DOMElement)) {
1278
                        continue;
1279
                    }
1280
                    $this->arrayRels[$fileRels][$oNode->getAttribute('Id')] = array(
1281
                        'Target' => $oNode->getAttribute('Target'),
1282
                        'Type' => $oNode->getAttribute('Type'),
1283
                    );
1284
                }
1285
            }
1286
        }
1287
    }
1288
1289
    /**
1290
     * @param $oSlide
1291
     * @param \DOMNodeList $oElements
1292
     * @param XMLReader $xmlReader
1293
     * @throws \Exception
1294
     * @internal param $baseFile
1295
     */
1296
    protected function loadSlideShapes($oSlide, $oElements, $xmlReader)
1297
    {
1298
        foreach ($oElements as $oNode) {
1299
            switch ($oNode->tagName) {
1300
                case 'p:graphicFrame':
1301
                    $this->loadShapeTable($xmlReader, $oNode, $oSlide);
1302
                    break;
1303
                case 'p:pic':
1304
                    $this->loadShapeDrawing($xmlReader, $oNode, $oSlide);
1305
                    break;
1306
                case 'p:sp':
1307
                    $this->loadShapeRichText($xmlReader, $oNode, $oSlide);
1308
                    break;
1309
                default:
1310
                    //var_export($oNode->tagName);
1311
            }
1312
        }
1313
    }
1314
1315 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...
1316
    {
1317
        //return false;
1318 5
        $oOLE = new OLERead();
1319 5
        $oOLE->read($this->filename);
1320
1321 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...
1322
        $pos = 0;
1323
        $size = self::getInt4d($oStreamEncrypted, $pos);
1324
        $pos += 8;
1325
        $data = '';
1326
        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...
1327
            $data .= pack('v', self::getInt1d($oStreamEncrypted, $pos + $inc));
1328
        }
1329
1330
        $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...
1331
        $pos = 0;
1332
        // EncryptionVersionInfo
1333
        $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...
1334
        $pos += 2;
1335
        $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...
1336
        $pos += 2;
1337
        // EncryptionHeader.Flags
1338
        $pos += 4;
1339
        // EncryptionHeaderSize
1340
        $size = self::getInt4d($oStream, $pos);
1341
        $pos += 4;
1342
        echo 'EncryptionHeaderSize : ' . $size. '<br />'; //
1343
1344
        // EncryptionHeader
1345
        // EncryptionHeader > Flags
1346
        $flags = self::getInt4d($oStream, $pos);
1347
        echo 'EncryptionHeader > Flags > fCryptoAPI : ' . (($flags >> 2) & bindec('1')). '<br />'; //
1348
        echo 'EncryptionHeader > Flags > fDocProps : ' . (($flags >> 3) & bindec('1')). '<br />'; //
1349
        echo 'EncryptionHeader > Flags > fExternal : ' . (($flags >> 4) & bindec('1')). '<br />'; //
1350
        echo 'EncryptionHeader > Flags > fAES : ' . (($flags >> 5) & bindec('1')). '<br />'; //
1351
        $pos += 4;
1352
        $size -= 4;
1353
        // EncryptionHeader > SizeExtra
1354
        $sizeExtra = self::getInt4d($oStream, $pos);
1355
        echo 'EncryptionHeader > SizeExtra : '.$sizeExtra. '<br />';
1356
        $pos += 4;
1357
        $size -= 4;
1358
        // EncryptionHeader > AlgID
1359
        $algID = self::getInt4d($oStream, $pos);
1360
        echo 'EncryptionHeader > AlgID :'.$algID.' ('.hexdec('0x00006801').' = 0x00006801 = RC4) -  (<strong>'.hexdec('0x0000660E').' = 0x0000660E = AES-128</strong>) - ('.hexdec('0x0000660F').' = 0x0000660F = AES-192) - ('.hexdec('0x00006610').' = 0x00006610 = AES-256)'. '<br />';
1361
        $pos += 4;
1362
        $size -= 4;
1363
        // EncryptionHeader > AlgIDHash
1364
        $algIDHash = self::getInt4d($oStream, $pos);
1365
        echo 'EncryptionHeader > AlgIDHash : '.$algIDHash. ' ('.hexdec('0x00008004').' = 0x00008004 = SHA1)'. '<br />';
1366
        $pos += 4;
1367
        $size -= 4;
1368
        // EncryptionHeader > KeySize
1369
        $keySize = self::getInt4d($oStream, $pos);
1370
        echo 'EncryptionHeader > KeySize : '.$keySize.  ' (<strong>'.hexdec('0x00000080').' = 0x00000080 = AES-128</strong>) - ('.hexdec('0x000000C0').' = 0x000000C0 = AES-192) - ('.hexdec('0x00000100').' = 0x00000100 = AES-256)'. '<br />';
1371
        $pos += 4;
1372
        $size -= 4;
1373
        // EncryptionHeader > ProviderType
1374
        $providerType = self::getInt4d($oStream, $pos);
1375
        echo 'EncryptionHeader > ProviderType : '.$providerType. ' ('.hexdec('0x00000018').' = 0x00000018)'. '<br />';
1376
        $pos += 4;
1377
        $size -= 4;
1378
        // EncryptionHeader > Reserved1
1379
        $pos += 4;
1380
        $size -= 4;
1381
        // EncryptionHeader > Reserved2
1382
        $pos += 4;
1383
        $size -= 4;
1384
        // EncryptionHeader > CSPName
1385
        $CSPName = '';
1386
        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...
1387
            $chr = self::getInt2d($oStream, $pos);
1388
            $pos += 2;
1389
            if ($chr === 0) {
1390
                break;
1391
            }
1392
            $CSPName .= chr($chr);
1393
        }
1394
        echo 'EncryptionHeader > CSPName : '.$CSPName. '<br />';
1395
        // EncryptionVerifier
1396
        // EncryptionVerifier > SaltSize
1397
        $saltSize = self::getInt4d($oStream, $pos);
1398
        echo 'EncryptionVerifier > SaltSize : '.$saltSize.' ('.hexdec('0x00000010').' = 0x00000010)';
1399
        hex_dump($saltSize);
1400
        $pos += 4;
1401
        // EncryptionVerifier > Salt
1402
        $salt = '';
1403
        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...
1404
            $salt .= pack('v', self::getInt1d($oStream, $pos));
1405
            $pos += 1;
1406
        }
1407
        echo 'EncryptionVerifier > Salt : ';
1408
        hex_dump($salt);
1409
        // EncryptionVerifier > EncryptedVerifier
1410
        $encryptedVerifier = '';
1411
        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...
1412
            $encryptedVerifier .= pack('v', self::getInt1d($oStream, $pos));
1413
            $pos += 1;
1414
        }
1415
        echo 'EncryptionVerifier > EncryptedVerifier : ';
1416
        hex_dump($encryptedVerifier);
1417
        // EncryptionVerifier > VerifierHashSize
1418
        $verifierHashSize = self::getInt4d($oStream, $pos);
1419
        echo 'EncryptionVerifier > VerifierHashSize ('.hexdec('0x00000010').' = 0x00000010) :';
1420
        hex_dump($verifierHashSize);
1421
        $pos += 4;
1422
        // EncryptionVerifier > EncryptedVerifierHash
1423
        // mon cas : AES donc 32
1424
        echo 'EncryptionVerifier > EncryptedVerifierHash :';
1425
        $encryptedVerifierHash = '';
1426
        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...
1427
            $encryptedVerifierHash .= pack('v', self::getInt1d($oStream, $pos));
1428
            $pos += 1;
1429
        }
1430
        hex_dump($encryptedVerifierHash);
1431
1432
        // https://github.com/doy/spreadsheet-parsexlsx/pull/37/files#diff-e61fbe6112ca2b7a3c08a4ea62d74ffeR1314
1433
1434
        // https://msdn.microsoft.com/en-us/library/dd925430(v=office.12).aspx
1435
        // H0 = H(salt + password)
1436
        $hash = $salt . iconv("ISO-8859-1", "UTF-16LE", $this->getPassword());
1437
        echo 'Hash (length : '.strlen($hash).')';
1438
        hex_dump($hash);
1439
        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...
1440
            $hash = sha1(pack('L', $inc).$hash, true);
1441
        }
1442
        echo 'Hash (length : '.strlen($hash).')';
1443
        hex_dump($hash);
1444
        //  Hn = H(iterator + Hn-1)
1445
        $hash = sha1($hash . 0x00000000, true);
1446
        echo 'Hash (length : '.strlen($hash).')';
1447
        hex_dump($hash);
1448
1449
        $keySize /=8;
1450
1451
        $x36 = '';
1452
        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...
1453
            $x36 .= pack('H*', 0x36);
1454
        }
1455
        echo 'x36 (length : '.strlen($x36).')';
1456
        hex_dump($x36);
1457
1458
        $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...
1459
        echo 'Hash = $x36 xor $hash (length : '.strlen($x1).')';
1460
        hex_dump($x1);
1461
1462
        if (strlen($x1) >= $keySize) {
1463
            $hash = substr($x1, 0, $keySize);
1464
        } else {
1465
            $x5C = '';
1466
            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...
1467
                $x5C .= pack('H*', '5C');
1468
            }
1469
            echo '$x5C (length : '.strlen($x5C).')';
1470
            hex_dump($x5C);
1471
1472
            $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...
1473
            echo '$x1 = $x5C xor $hash (length : '.strlen($x2).')';
1474
            hex_dump($x2);
1475
1476
            $hash = substr($x1.$x2, 0, $keySize);
1477
        }
1478
1479
        echo 'Final hash (length : '.strlen($hash).')';
1480
        hex_dump($hash);
1481
        // https://msdn.microsoft.com/en-us/library/dd926426(v=office.12).aspx
1482
        $verifier = openssl_decrypt($encryptedVerifier, 'AES-128-ECB', $hash, 0, '');
1483
        echo 'Verifier :';
1484
        hex_dump($verifier);
1485
        $verifierHash = openssl_decrypt($encryptedVerifierHash, 'AES-128-ECB', $hash, 0, '');
1486
        echo 'VerifierHash :';
1487
        hex_dump($verifierHash);
1488
1489
        $verifierHash0 = sha1($verifier, true);
1490
        echo 'VerifierHash :';
1491
        hex_dump($verifierHash);
1492
        echo 'VerifierHash sha1($verifier, true):';
1493
        hex_dump($verifierHash0);
1494
    }
1495
1496
    /**
1497
     * Read 8-bit unsigned integer
1498
     *
1499
     * @param string $data
1500
     * @param int $pos
1501
     * @return int
1502
     */
1503
    public static function getInt1d($data, $pos)
1504
    {
1505
        return ord($data[$pos]);
1506
    }
1507
1508
    /**
1509
     * Read 16-bit unsigned integer
1510
     *
1511
     * @param string $data
1512
     * @param int $pos
1513
     * @return int
1514
     */
1515
    public static function getInt2d($data, $pos)
1516
    {
1517
        return ord($data[$pos]) | (ord($data[$pos+1]) << 8);
1518
    }
1519
1520
    /**
1521
     * Read 32-bit signed integer
1522
     *
1523
     * @param string $data
1524
     * @param int $pos
1525
     * @return int
1526
     */
1527
    public static function getInt4d($data, $pos)
1528
    {
1529
        // FIX: represent numbers correctly on 64-bit system
1530
        // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
1531
        // Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
1532
        $or24 = ord($data[$pos + 3]);
1533
        if ($or24 >= 128) {
1534
            // negative number
1535
            $ord24 = -abs((256 - $or24) << 24);
1536
        } else {
1537
            $ord24 = ($or24 & 127) << 24;
1538
        }
1539
        return ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16) | $ord24;
1540
    }
1541
}
1542