Completed
Pull Request — develop (#208)
by Franck
22:58 queued 12:19
created

ODPresentation   F

Complexity

Total Complexity 127

Size/Duplication

Total Lines 651
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 17

Test Coverage

Coverage 88.99%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 127
c 2
b 0
f 0
lcom 1
cbo 17
dl 0
loc 651
ccs 307
cts 345
cp 0.8899
rs 1.4178

17 Methods

Rating   Name   Duplication   Size   Complexity  
A canRead() 0 4 1
A load() 0 9 2
B fileSupportsUnserializePhpPresentation() 0 18 6
B loadFile() 0 22 4
B loadDocumentProperties() 0 25 4
B loadSlides() 0 13 5
F loadStyle() 0 128 42
C loadSlide() 0 26 7
C loadShapeDrawing() 0 39 13
D loadShapeRichText() 0 25 9
A readParagraph() 0 12 3
B readParagraphItem() 0 22 6
A readList() 0 13 4
A readListItem() 0 14 4
A loadStylesFile() 0 11 4
D loadFileFromODP() 0 107 9
B hash_pbkdf2() 0 22 4

How to fix   Complexity   

Complex Class

Complex classes like ODPresentation often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ODPresentation, and based on these observations, apply Extract Interface, too.

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 ZipArchive;
21
use PhpOffice\Common\XMLReader;
22
use PhpOffice\Common\Drawing as CommonDrawing;
23
use PhpOffice\PhpPresentation\PhpPresentation;
24
use PhpOffice\PhpPresentation\Shape\Drawing\Gd;
25
use PhpOffice\PhpPresentation\Shape\RichText;
26
use PhpOffice\PhpPresentation\Shape\RichText\Paragraph;
27
use PhpOffice\PhpPresentation\Slide\Background\Image;
28
use PhpOffice\PhpPresentation\Style\Bullet;
29
use PhpOffice\PhpPresentation\Style\Color;
30
use PhpOffice\PhpPresentation\Style\Font;
31
use PhpOffice\PhpPresentation\Style\Shadow;
32
use PhpOffice\PhpPresentation\Style\Alignment;
33
34
/**
35
 * Serialized format reader
36
 */
37
class ODPresentation extends AbstractReader implements ReaderInterface
38
{
39
    /**
40
     * Output Object
41
     * @var PhpPresentation
42
     */
43
    protected $oPhpPresentation;
44
45
    /**
46
     * Output Object
47
     * @var \ZipArchive
48
     */
49
    protected $oZip;
50
51
    /**
52
     * @var string
53
     */
54
    protected $filename;
55
56
    /**
57
     * @var array[]
58
     */
59
    protected $arrayStyles = array();
60
61
    /**
62
     * @var array[]
63
     */
64
    protected $arrayCommonStyles = array();
65
66
    /**
67
     * @var \PhpOffice\Common\XMLReader
68
     */
69
    protected $oXMLReader;
70
71
    /**
72
     * @var \PhpOffice\Common\XMLReader
73
     */
74
    protected $oXMLMetaInfManifest;
75
76
    /**
77
     * Can the current \PhpOffice\PhpPresentation\Reader\ReaderInterface read the file?
78
     *
79
     * @param  string $pFilename
80
     * @throws \Exception
81
     * @return boolean
82
     */
83 2
    public function canRead($pFilename)
84
    {
85 2
        return $this->fileSupportsUnserializePhpPresentation($pFilename);
86
    }
87
88
    /**
89
     * Does a file support UnserializePhpPresentation ?
90
     *
91
     * @param  string    $pFilename
92
     * @throws \Exception
93
     * @return boolean
94
     */
95 8
    public function fileSupportsUnserializePhpPresentation($pFilename = '')
96
    {
97
        // Check if file exists
98 8
        if (!file_exists($pFilename)) {
99 2
            throw new \Exception("Could not open " . $pFilename . " for reading! File does not exist.");
100
        }
101
        
102 6
        $oZip = new ZipArchive();
103
        // Is it a zip ?
104 6
        if ($oZip->open($pFilename) === true) {
105
            // Is it an OpenXML Document ?
106
            // Is it a Presentation ?
107 4
            if (is_array($oZip->statName('META-INF/manifest.xml')) && is_array($oZip->statName('mimetype')) && $oZip->getFromName('mimetype') == 'application/vnd.oasis.opendocument.presentation') {
108 4
                return true;
109
            }
110 1
        }
111 3
        return false;
112
    }
113
114
    /**
115
     * Loads PhpPresentation Serialized file
116
     *
117
     * @param  string        $pFilename
118
     * @return \PhpOffice\PhpPresentation\PhpPresentation
119
     * @throws \Exception
120
     */
121 5
    public function load($pFilename)
122
    {
123
        // Unserialize... First make sure the file supports it!
124 5
        if (!$this->fileSupportsUnserializePhpPresentation($pFilename)) {
125 1
            throw new \Exception("Invalid file format for PhpOffice\PhpPresentation\Reader\ODPresentation: " . $pFilename . ".");
126
        }
127
128 3
        return $this->loadFile($pFilename);
129
    }
130
131
    /**
132
     * Load PhpPresentation Serialized file
133
     *
134
     * @param  string        $pFilename
135
     * @return \PhpOffice\PhpPresentation\PhpPresentation
136
     */
137 3
    protected function loadFile($pFilename)
138
    {
139 3
        $this->filename = $pFilename;
140
141 3
        $this->oPhpPresentation = new PhpPresentation();
142 3
        $this->oPhpPresentation->removeSlideByIndex();
143
        
144 3
        $this->oZip = new ZipArchive();
145 3
        $this->oZip->open($this->filename);
146
147 3
        if ($this->loadFileFromODP('meta.xml') !== false) {
148 3
            $this->loadDocumentProperties();
149 3
        }
150 3
        if ($this->loadFileFromODP('styles.xml') !== false) {
151 3
            $this->loadStylesFile();
152 3
        }
153 3
        if ($this->loadFileFromODP('content.xml') !== false) {
154 3
            $this->loadSlides();
155 3
        }
156
157 3
        return $this->oPhpPresentation;
158
    }
159
    
160
    /**
161
     * Read Document Properties
162
     */
163 3
    protected function loadDocumentProperties()
164
    {
165
        $arrayProperties = array(
166 3
            '/office:document-meta/office:meta/meta:initial-creator' => 'setCreator',
167 3
            '/office:document-meta/office:meta/dc:creator' => 'setLastModifiedBy',
168 3
            '/office:document-meta/office:meta/dc:title' => 'setTitle',
169 3
            '/office:document-meta/office:meta/dc:description' => 'setDescription',
170 3
            '/office:document-meta/office:meta/dc:subject' => 'setSubject',
171 3
            '/office:document-meta/office:meta/meta:keyword' => 'setKeywords',
172 3
            '/office:document-meta/office:meta/meta:creation-date' => 'setCreated',
173 3
            '/office:document-meta/office:meta/dc:date' => 'setModified',
174 3
        );
175 3
        $oProperties = $this->oPhpPresentation->getDocumentProperties();
176 3
        foreach ($arrayProperties as $path => $property) {
177 3
            if (is_object($oElement = $this->oXMLReader->getElement($path))) {
178 3
                if (in_array($property, array('setCreated', 'setModified'))) {
179 3
                    $oDateTime = new \DateTime();
180 3
                    $oDateTime->createFromFormat(\DateTime::W3C, $oElement->nodeValue);
181 3
                    $oProperties->{$property}($oDateTime->getTimestamp());
182 3
                } else {
183 1
                    $oProperties->{$property}($oElement->nodeValue);
184
                }
185 3
            }
186 3
        }
187 3
    }
188
    
189
    /**
190
     * Extract all slides
191
     */
192 3
    protected function loadSlides()
193
    {
194 3
        foreach ($this->oXMLReader->getElements('/office:document-content/office:automatic-styles/*') as $oElement) {
195 3
            if ($oElement->hasAttribute('style:name')) {
196 3
                $this->loadStyle($oElement);
197 3
            }
198 3
        }
199 3
        foreach ($this->oXMLReader->getElements('/office:document-content/office:body/office:presentation/draw:page') as $oElement) {
200 3
            if ($oElement->nodeName == 'draw:page') {
201 3
                $this->loadSlide($oElement);
202 3
            }
203 3
        }
204 3
    }
205
    
206
    /**
207
     * Extract style
208
     * @param \DOMElement $nodeStyle
209
     */
210 3
    protected function loadStyle(\DOMElement $nodeStyle)
211
    {
212 3
        $keyStyle = $nodeStyle->getAttribute('style:name');
213
214 3
        $nodeDrawingPageProps = $this->oXMLReader->getElement('style:drawing-page-properties', $nodeStyle);
215 3
        if ($nodeDrawingPageProps) {
216
            // Read Background Color
217 3
            if ($nodeDrawingPageProps->hasAttribute('draw:fill-color') && $nodeDrawingPageProps->getAttribute('draw:fill') == 'solid') {
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...
218
                $oBackground = new \PhpOffice\PhpPresentation\Slide\Background\Color();
219
                $oColor = new Color();
220
                $oColor->setRGB(substr($nodeDrawingPageProps->getAttribute('draw:fill-color'), -6));
221
                $oBackground->setColor($oColor);
222
            }
223
            // Read Background Image
224 3
            if ($nodeDrawingPageProps->getAttribute('draw:fill') == 'bitmap' && $nodeDrawingPageProps->hasAttribute('draw:fill-image-name')) {
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...
225
                $nameStyle = $nodeDrawingPageProps->getAttribute('draw:fill-image-name');
226
                if (!empty($this->arrayCommonStyles[$nameStyle]) && $this->arrayCommonStyles[$nameStyle]['type'] == 'image' && !empty($this->arrayCommonStyles[$nameStyle]['path'])) {
227
                    $tmpBkgImg = tempnam(sys_get_temp_dir(), 'PhpPresentationReaderODPBkg');
228
                    $contentImg = $this->oZip->getFromName($this->arrayCommonStyles[$nameStyle]['path']);
229
                    file_put_contents($tmpBkgImg, $contentImg);
230
231
                    $oBackground = new Image();
232
                    $oBackground->setPath($tmpBkgImg);
233
                }
234
            }
235 3
        }
236
237 3
        $nodeGraphicProps = $this->oXMLReader->getElement('style:graphic-properties', $nodeStyle);
238 3
        if ($nodeGraphicProps) {
239
            // Read Shadow
240 3
            if ($nodeGraphicProps->hasAttribute('draw:shadow') && $nodeGraphicProps->getAttribute('draw:shadow') == 'visible') {
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...
241 1
                $oShadow = new Shadow();
242 1
                $oShadow->setVisible(true);
243 1
                if ($nodeGraphicProps->hasAttribute('draw:shadow-color')) {
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...
244 1
                    $oShadow->getColor()->setRGB(substr($nodeGraphicProps->getAttribute('draw:shadow-color'), -6));
245 1
                }
246 1
                if ($nodeGraphicProps->hasAttribute('draw:shadow-opacity')) {
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...
247 1
                    $oShadow->setAlpha(100 - (int)substr($nodeGraphicProps->getAttribute('draw:shadow-opacity'), 0, -1));
248 1
                }
249 1
                if ($nodeGraphicProps->hasAttribute('draw:shadow-offset-x') && $nodeGraphicProps->hasAttribute('draw:shadow-offset-y')) {
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...
250 1
                    $offsetX = substr($nodeGraphicProps->getAttribute('draw:shadow-offset-x'), 0, -2);
251 1
                    $offsetY = substr($nodeGraphicProps->getAttribute('draw:shadow-offset-y'), 0, -2);
252 1
                    $distance = 0;
253 1
                    if ($offsetX != 0) {
254 1
                        $distance = ($offsetX < 0 ? $offsetX * -1 : $offsetX);
255 1
                    } elseif ($offsetY != 0) {
256
                        $distance = ($offsetY < 0 ? $offsetY * -1 : $offsetY);
257
                    }
258 1
                    $oShadow->setDirection(rad2deg(atan2($offsetY, $offsetX)));
259 1
                    $oShadow->setDistance(CommonDrawing::centimetersToPixels($distance));
260 1
                }
261 1
            }
262 3
        }
263
        
264 3
        $nodeTextProperties = $this->oXMLReader->getElement('style:text-properties', $nodeStyle);
265 3
        if ($nodeTextProperties) {
266 1
            $oFont = new Font();
267 1
            if ($nodeTextProperties->hasAttribute('fo:color')) {
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...
268 1
                $oFont->getColor()->setRGB(substr($nodeTextProperties->getAttribute('fo:color'), -6));
269 1
            }
270 1
            if ($nodeTextProperties->hasAttribute('fo:font-family')) {
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...
271 1
                $oFont->setName($nodeTextProperties->getAttribute('fo:font-family'));
272 1
            }
273 1
            if ($nodeTextProperties->hasAttribute('fo:font-weight') && $nodeTextProperties->getAttribute('fo:font-weight') == 'bold') {
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...
274 1
                $oFont->setBold(true);
275 1
            }
276 1
            if ($nodeTextProperties->hasAttribute('fo:font-size')) {
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...
277 1
                $oFont->setSize(substr($nodeTextProperties->getAttribute('fo:font-size'), 0, -2));
278 1
            }
279 1
        }
280
281 3
        $nodeParagraphProps = $this->oXMLReader->getElement('style:paragraph-properties', $nodeStyle);
282 3
        if ($nodeParagraphProps) {
283 2
            $oAlignment = new Alignment();
284 2
            if ($nodeParagraphProps->hasAttribute('fo:text-align')) {
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...
285 2
                $oAlignment->setHorizontal($nodeParagraphProps->getAttribute('fo:text-align'));
286 2
            }
287 2
        }
288
        
289 3
        if ($nodeStyle->nodeName == 'text:list-style') {
290 2
            $arrayListStyle = array();
291 2
            foreach ($this->oXMLReader->getElements('text:list-level-style-bullet', $nodeStyle) as $oNodeListLevel) {
292 2
                $oAlignment = new Alignment();
293 2
                $oBullet = new Bullet();
294 2
                $oBullet->setBulletType(Bullet::TYPE_NONE);
295 2
                if ($oNodeListLevel->hasAttribute('text:level')) {
296 2
                    $oAlignment->setLevel((int) $oNodeListLevel->getAttribute('text:level') - 1);
297 2
                }
298 2
                if ($oNodeListLevel->hasAttribute('text:bullet-char')) {
299 2
                    $oBullet->setBulletChar($oNodeListLevel->getAttribute('text:bullet-char'));
300 2
                    $oBullet->setBulletType(Bullet::TYPE_BULLET);
301 2
                }
302
                
303 2
                $oNodeListProperties = $this->oXMLReader->getElement('style:list-level-properties', $oNodeListLevel);
304 2
                if ($oNodeListProperties) {
305 2
                    if ($oNodeListProperties->hasAttribute('text:min-label-width')) {
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...
306 2
                        $oAlignment->setIndent((int)round(CommonDrawing::centimetersToPixels(substr($oNodeListProperties->getAttribute('text:min-label-width'), 0, -2))));
307 2
                    }
308 2
                    if ($oNodeListProperties->hasAttribute('text:space-before')) {
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...
309 2
                        $iSpaceBefore = CommonDrawing::centimetersToPixels(substr($oNodeListProperties->getAttribute('text:space-before'), 0, -2));
310 2
                        $iMarginLeft = $iSpaceBefore + $oAlignment->getIndent();
311 2
                        $oAlignment->setMarginLeft($iMarginLeft);
312 2
                    }
313 2
                }
314 2
                $oNodeTextProperties = $this->oXMLReader->getElement('style:text-properties', $oNodeListLevel);
315 2
                if ($oNodeTextProperties) {
316 2
                    if ($oNodeTextProperties->hasAttribute('fo:font-family')) {
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...
317 2
                        $oBullet->setBulletFont($oNodeTextProperties->getAttribute('fo:font-family'));
318 2
                    }
319 2
                }
320
                
321 2
                $arrayListStyle[$oAlignment->getLevel()] = array(
322 2
                    'alignment' => $oAlignment,
323 2
                    'bullet' => $oBullet,
324
                );
325 2
            }
326 2
        }
327
        
328 3
        $this->arrayStyles[$keyStyle] = array(
329 3
            'alignment' => isset($oAlignment) ? $oAlignment : null,
330 3
            'background' => isset($oBackground) ? $oBackground : null,
331 3
            'font' => isset($oFont) ? $oFont : null,
332 3
            'shadow' => isset($oShadow) ? $oShadow : null,
333 3
            'listStyle' => isset($arrayListStyle) ? $arrayListStyle : null,
334
        );
335
        
336 3
        return true;
337
    }
338
339
    /**
340
     * Read Slide
341
     *
342
     * @param \DOMElement $nodeSlide
343
     */
344 3
    protected function loadSlide(\DOMElement $nodeSlide)
345
    {
346
        // Core
347 3
        $this->oPhpPresentation->createSlide();
348 3
        $this->oPhpPresentation->setActiveSlideIndex($this->oPhpPresentation->getSlideCount() - 1);
349 3
        if ($nodeSlide->hasAttribute('draw:name')) {
350 3
            $this->oPhpPresentation->getActiveSlide()->setName($nodeSlide->getAttribute('draw:name'));
351 3
        }
352 3
        if ($nodeSlide->hasAttribute('draw:style-name')) {
353 3
            $keyStyle = $nodeSlide->getAttribute('draw:style-name');
354 3
            if (isset($this->arrayStyles[$keyStyle])) {
355 3
                $this->oPhpPresentation->getActiveSlide()->setBackground($this->arrayStyles[$keyStyle]['background']);
356 3
            }
357 3
        }
358 3
        foreach ($this->oXMLReader->getElements('draw:frame', $nodeSlide) as $oNodeFrame) {
359 3
            if ($this->oXMLReader->getElement('draw:image', $oNodeFrame)) {
360 2
                $this->loadShapeDrawing($oNodeFrame);
361 2
                continue;
362
            }
363 3
            if ($this->oXMLReader->getElement('draw:text-box', $oNodeFrame)) {
364 3
                $this->loadShapeRichText($oNodeFrame);
365 3
                continue;
366
            }
367 3
        }
368 3
        return true;
369
    }
370
    
371
    /**
372
     * Read Shape Drawing
373
     *
374
     * @param \DOMElement $oNodeFrame
375
     */
376 2
    protected function loadShapeDrawing(\DOMElement $oNodeFrame)
377
    {
378
        // Core
379 2
        $oShape = new Gd();
380 2
        $oShape->getShadow()->setVisible(false);
381
382 2
        $oNodeImage = $this->oXMLReader->getElement('draw:image', $oNodeFrame);
383 2
        if ($oNodeImage) {
384 2
            if ($oNodeImage->hasAttribute('xlink:href')) {
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...
385 2
                $sFilename = $oNodeImage->getAttribute('xlink:href');
386
                // svm = StarView Metafile
387 2
                if (pathinfo($sFilename, PATHINFO_EXTENSION) == 'svm') {
388 1
                    return;
389
                }
390 2
                $imageFile = $this->oZip->getFromName($sFilename);
391 2
                if (!empty($imageFile)) {
392 2
                    $oShape->setImageResource(imagecreatefromstring($imageFile));
393 2
                }
394 2
            }
395 2
        }
396
        
397 2
        $oShape->setName($oNodeFrame->hasAttribute('draw:name') ? $oNodeFrame->getAttribute('draw:name') : '');
398 2
        $oShape->setDescription($oNodeFrame->hasAttribute('draw:name') ? $oNodeFrame->getAttribute('draw:name') : '');
399 2
        $oShape->setResizeProportional(false);
400 2
        $oShape->setWidth($oNodeFrame->hasAttribute('svg:width') ? (int)round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:width'), 0, -2))) : '');
401 2
        $oShape->setHeight($oNodeFrame->hasAttribute('svg:height') ? (int)round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:height'), 0, -2))) : '');
402 2
        $oShape->setResizeProportional(true);
403 2
        $oShape->setOffsetX($oNodeFrame->hasAttribute('svg:x') ? (int)round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:x'), 0, -2))) : '');
404 2
        $oShape->setOffsetY($oNodeFrame->hasAttribute('svg:y') ? (int)round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:y'), 0, -2))) : '');
405
        
406 2
        if ($oNodeFrame->hasAttribute('draw:style-name')) {
407 2
            $keyStyle = $oNodeFrame->getAttribute('draw:style-name');
408 2
            if (isset($this->arrayStyles[$keyStyle])) {
409 2
                $oShape->setShadow($this->arrayStyles[$keyStyle]['shadow']);
410 2
            }
411 2
        }
412
        
413 2
        $this->oPhpPresentation->getActiveSlide()->addShape($oShape);
414 2
    }
415
416
    /**
417
     * Read Shape RichText
418
     *
419
     * @param \DOMElement $oNodeFrame
420
     */
421 3
    protected function loadShapeRichText(\DOMElement $oNodeFrame)
422
    {
423
        // Core
424 3
        $oShape = $this->oPhpPresentation->getActiveSlide()->createRichTextShape();
425 3
        $oShape->setParagraphs(array());
426
        
427 3
        $oShape->setWidth($oNodeFrame->hasAttribute('svg:width') ? (int)round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:width'), 0, -2))) : '');
428 3
        $oShape->setHeight($oNodeFrame->hasAttribute('svg:height') ? (int)round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:height'), 0, -2))) : '');
429 3
        $oShape->setOffsetX($oNodeFrame->hasAttribute('svg:x') ? (int)round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:x'), 0, -2))) : '');
430 3
        $oShape->setOffsetY($oNodeFrame->hasAttribute('svg:y') ? (int)round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:y'), 0, -2))) : '');
431
        
432 3
        foreach ($this->oXMLReader->getElements('draw:text-box/*', $oNodeFrame) as $oNodeParagraph) {
433 2
            $this->levelParagraph = 0;
434 2
            if ($oNodeParagraph->nodeName == 'text:p') {
435 2
                $this->readParagraph($oShape, $oNodeParagraph);
436 2
            }
437 2
            if ($oNodeParagraph->nodeName == 'text:list') {
438 1
                $this->readList($oShape, $oNodeParagraph);
439 1
            }
440 3
        }
441
        
442 3
        if (count($oShape->getParagraphs()) > 0) {
443 2
            $oShape->setActiveParagraph(0);
444 2
        }
445 3
    }
446
    
447
    protected $levelParagraph = 0;
448
    
449
    /**
450
     * Read Paragraph
451
     * @param RichText $oShape
452
     * @param \DOMElement $oNodeParent
453
     */
454 2
    protected function readParagraph(RichText $oShape, \DOMElement $oNodeParent)
455
    {
456 2
        $oParagraph = $oShape->createParagraph();
457 2
        $oDomList = $this->oXMLReader->getElements('text:span', $oNodeParent);
458 2
        if ($oDomList->length == 0) {
459 1
            $this->readParagraphItem($oParagraph, $oNodeParent);
460 1
        } else {
461 1
            foreach ($oDomList as $oNodeRichTextElement) {
462 1
                $this->readParagraphItem($oParagraph, $oNodeRichTextElement);
463 1
            }
464
        }
465 2
    }
466
    
467
    /**
468
     * Read Paragraph Item
469
     * @param RichText $oShape
0 ignored issues
show
Bug introduced by
There is no parameter named $oShape. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
470
     * @param \DOMElement $oNodeParent
471
     */
472 2
    protected function readParagraphItem(Paragraph $oParagraph, \DOMElement $oNodeParent)
473
    {
474 2
        if ($this->oXMLReader->elementExists('text:line-break', $oNodeParent)) {
475 1
            $oParagraph->createBreak();
476 1
        } else {
477 2
            $oTextRun = $oParagraph->createTextRun();
478 2
            if ($oNodeParent->hasAttribute('text:style-name')) {
479 1
                $keyStyle = $oNodeParent->getAttribute('text:style-name');
480 1
                if (isset($this->arrayStyles[$keyStyle])) {
481 1
                    $oTextRun->setFont($this->arrayStyles[$keyStyle]['font']);
482 1
                }
483 1
            }
484 2
            if ($oTextRunLink = $this->oXMLReader->getElement('text:a', $oNodeParent)) {
485 1
                $oTextRun->setText($oTextRunLink->nodeValue);
486 1
                if ($oTextRunLink->hasAttribute('xlink:href')) {
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...
487 1
                    $oTextRun->getHyperlink()->setUrl($oTextRunLink->getAttribute('xlink:href'));
488 1
                }
489 1
            } else {
490 2
                $oTextRun->setText($oNodeParent->nodeValue);
491
            }
492
        }
493 2
    }
494
495
    /**
496
     * Read List
497
     *
498
     * @param RichText $oShape
499
     * @param \DOMElement $oNodeParent
500
     */
501 1
    protected function readList(RichText $oShape, \DOMElement $oNodeParent)
502
    {
503 1
        foreach ($this->oXMLReader->getElements('text:list-item/*', $oNodeParent) as $oNodeListItem) {
504 1
            if ($oNodeListItem->nodeName == 'text:p') {
505 1
                $this->readListItem($oShape, $oNodeListItem, $oNodeParent);
506 1
            }
507 1
            if ($oNodeListItem->nodeName == 'text:list') {
508 1
                $this->levelParagraph++;
509 1
                $this->readList($oShape, $oNodeListItem);
510 1
                $this->levelParagraph--;
511 1
            }
512 1
        }
513 1
    }
514
    
515
    /**
516
     * Read List Item
517
     * @param RichText $oShape
518
     * @param \DOMElement $oNodeParent
519
     * @param \DOMElement $oNodeParagraph
520
     */
521 1
    protected function readListItem(RichText $oShape, \DOMElement $oNodeParent, \DOMElement $oNodeParagraph)
522
    {
523 1
        $oParagraph = $oShape->createParagraph();
524 1
        if ($oNodeParagraph->hasAttribute('text:style-name')) {
525 1
            $keyStyle = $oNodeParagraph->getAttribute('text:style-name');
526 1
            if (isset($this->arrayStyles[$keyStyle])) {
527 1
                $oParagraph->setAlignment($this->arrayStyles[$keyStyle]['listStyle'][$this->levelParagraph]['alignment']);
528 1
                $oParagraph->setBulletStyle($this->arrayStyles[$keyStyle]['listStyle'][$this->levelParagraph]['bullet']);
529 1
            }
530 1
        }
531 1
        foreach ($this->oXMLReader->getElements('text:span', $oNodeParent) as $oNodeRichTextElement) {
532 1
            $this->readParagraphItem($oParagraph, $oNodeRichTextElement);
533 1
        }
534 1
    }
535
536
    /**
537
     * Load file 'styles.xml'
538
     */
539 3
    protected function loadStylesFile()
540
    {
541 3
        foreach ($this->oXMLReader->getElements('/office:document-styles/office:styles/*') as $oElement) {
542 3
            if ($oElement->nodeName == 'draw:fill-image') {
543
                $this->arrayCommonStyles[$oElement->getAttribute('draw:name')] = array(
544
                    'type' => 'image',
545
                    'path' => $oElement->hasAttribute('xlink:href') ? $oElement->getAttribute('xlink:href') : null
546
                );
547
            }
548 3
        }
549 3
    }
550
551
    /**
552
     * @param string $filename
553
     * @return bool
554
     * @throws \Exception
555
     */
556 3
    protected function loadFileFromODP($filename)
557
    {
558 3
        $bEncrypted = false;
559
560 3
        if (!$this->oXMLMetaInfManifest) {
561 3
            $this->oXMLMetaInfManifest = new XMLReader();
562 3
            if ($this->oXMLMetaInfManifest->getDomFromZip($this->filename, 'META-INF/manifest.xml') === false) {
563
                return false;
564
            }
565 3
        }
566
        // Search file in META-INF/manifest.xml
567 3
        $oElement = $this->oXMLMetaInfManifest->getElement('/manifest:manifest/manifest:file-entry[@manifest:full-path=\''.$filename.'\']');
568 3
        if (!$oElement) {
569
            return false;
570
        }
571
        // Has it some manifest:encryption-data ?
572 3
        $oElementEncryption = $this->oXMLMetaInfManifest->getElement('manifest:encryption-data', $oElement);
0 ignored issues
show
Documentation introduced by
$oElement 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...
573 3
        if ($oElementEncryption) {
574
            $bEncrypted = true;
575
        }
576
577 3
        $fileContent = $this->oZip->getFromName($filename);
578 3
        if (!$fileContent){
579
            return false;
580
        }
581
582
        // No Encrypted file
583 3
        if (!$bEncrypted) {
584 3
            $this->oXMLReader = new XMLReader();
585 3
            $this->oXMLReader->getDomFromString($fileContent);
586 3
            return true;
587
        }
588
589
        //return false;
590
        /*
591
          <manifest:encryption-data
592
                manifest:checksum-type="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0#sha256-1k"
593
                manifest:checksum="BfB+taOY0kcVO/9WNi4DfqioRp3LMwVoNbqfAQ37yac=">
594
              <manifest:algorithm
595
                    manifest:algorithm-name="http://www.w3.org/2001/04/xmlenc#aes256-cbc"
596
                    manifest:initialisation-vector="I7rMXmvuynJFxJtm+EQ5qA=="/>
597
              <manifest:key-derivation
598
                    manifest:key-derivation-name="PBKDF2"
599
                    manifest:key-size="32"
600
                    manifest:iteration-count="1024"
601
                    manifest:salt="Mows9XX/YiNKNJ0qll3jgA=="/>
602
              <manifest:start-key-generation
603
                    manifest:start-key-generation-name="http://www.w3.org/2000/09/xmldsig#sha256"
604
                    manifest:key-size="32"/>
605
          </manifest:encryption-data>
606
         </manifest:file-entry>
607
         */
608
        return false;
609
        // Encrypted file
610
        $checksum = $oElementEncryption->getAttribute('manifest:checksum');
0 ignored issues
show
Unused Code introduced by
// Encrypted file $check...e('manifest:checksum'); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
Unused Code introduced by
$checksum 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...
611
612
        $oEltKeyDerivation = $this->oXMLMetaInfManifest->getElement('manifest:key-derivation', $oElementEncryption);
613
        $salt = $oEltKeyDerivation->getAttribute('manifest:salt');
614
        //$salt = base64_decode($salt);
615
        echo 'manifest:salt : ';
616
        var_dump($salt);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($salt); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
617
        $iterationCount = $oEltKeyDerivation->getAttribute('manifest:iteration-count');
618
        echo 'manifest:iteration-count : ';
619
        var_dump($iterationCount);
620
        $keySize = $oEltKeyDerivation->getAttribute('manifest:key-size');
621
        echo 'manifest:key-size : ';
622
        var_dump($keySize);
623
624
        $oEltAlgorithm = $this->oXMLMetaInfManifest->getElement('manifest:algorithm', $oElementEncryption);
625
        $iv = $oEltAlgorithm->getAttribute('manifest:initialisation-vector');
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $iv. 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...
626
        $iv = base64_decode($iv);
627
        echo 'manifest:initialisation-vector : ';
628
        var_dump($iv);
629
630
        $pwdHash = hash('sha256', $this->getPassword());
631
        echo 'sha256('.$this->getPassword().'): ';
632
        var_dump($pwdHash);
633
        //$pwdHash = substr($pwdHash, 0 , 32);
634
        //var_dump($pwdHash);
635
636
        $key = hash_pbkdf2('sha1', $pwdHash, $salt, $iterationCount, $keySize, true);
637
        echo 'hash_pbkdf2 (sha1, hash, salt, iterationCount, $iterationCount) : ';
638
        var_dump($key);
639
        //$key = $this->hash_pbkdf2('sha1', $pwdHash, $salt, $iterationCount, $keySize, true);
640
        //echo 'hash_pbkdf2 (sha1, hash, salt, iterationCount, $iterationCount) : ';
641
        //var_dump($key);
642
643
        $data = openssl_decrypt($fileContent, 'AES-256-CBC', $key, 0, $iv);
644
        if(!$data) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after IF keyword; 0 found
Loading history...
645
            while ($msg = openssl_error_string())
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
Coding Style introduced by
Expected 0 spaces before semicolon; newline found
Loading history...
646
                var_dump($msg);
647
            die();
0 ignored issues
show
Coding Style Compatibility introduced by
The method loadFileFromODP() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
648
        } else {
649
            var_dump($data);
650
            $data = gzinflate($data);
651
            var_dump($data);
652
        }
653
654
        /*$data = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $fileContent, MCRYPT_MODE_CBC, $iv);
655
        var_dump($data);
656
        $data = gzinflate($data);
657
        if($data) {
658
            var_dump($data);
659
        }*/
660
661
        return false;
662
    }
663
664
    protected function hash_pbkdf2($a = 'sha256', $password, $salt, $rounds = 5000, $key_length = 32, $raw_output = false)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $a. 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...
Coding Style Naming introduced by
The method hash_pbkdf2 is not named in camelCase.

This check marks method 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...
Coding Style Naming introduced by
The parameter $key_length is not named in camelCase.

This check marks parameter 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...
Coding Style Naming introduced by
The parameter $raw_output is not named in camelCase.

This check marks parameter 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...
Coding Style Naming introduced by
The variable $key_length 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...
Coding Style Naming introduced by
The variable $raw_output 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...
Coding Style introduced by
Method name "ODPresentation::hash_pbkdf2" is not in camel caps format
Loading history...
Coding Style introduced by
Parameters which have default values should be placed at the end.

If you place a parameter with a default value before a parameter with a default value, the default value of the first parameter will never be used as it will always need to be passed anyway:

// $a must always be passed; it's default value is never used.
function someFunction($a = 5, $b) { }
Loading history...
665
    {
666
        // Derived key
667
        $dk = '';
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $dk. 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...
668
        // Create key
669
        for ($block=1; $block<=$key_length; $block++)
670
        {
671
            // Initial hash for this block
672
            $ib = $h = hash_hmac($a, $salt . pack('N', $block), $password, true);
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $ib. 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...
Comprehensibility introduced by
Avoid variables with short names like $h. 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...
673
            // Perform block iterations
674
            for ($i=1; $i<$rounds; $i++)
675
            {
676
                // XOR each iteration
677
                $ib ^= ($h = hash_hmac($a, $h, $password, true));
678
            }
679
            // Append iterated block
680
            $dk .= $ib;
681
        }
682
        // Return derived key of correct length
683
        $key = substr($dk, 0, $key_length);
684
        return $raw_output ? $key : base64_encode($key);
685
    }
686
687
}
688