Completed
Push — develop ( 3851aa...435d68 )
by Adrien
21:08
created

Xls::setTempDir()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Writer;
4
5
/**
6
 * Copyright (c) 2006 - 2015 PhpSpreadsheet
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21
 *
22
 * @category   PhpSpreadsheet
23
 * @copyright  Copyright (c) 2006 - 2015 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
24
 * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
25
 * @version    ##VERSION##, ##DATE##
26
 */
27
class Xls extends BaseWriter implements IWriter
28
{
29
    /**
30
     * PhpSpreadsheet object
31
     *
32
     * @var \PhpOffice\PhpSpreadsheet\Spreadsheet
33
     */
34
    private $spreadsheet;
35
36
    /**
37
     * Total number of shared strings in workbook
38
     *
39
     * @var int
40
     */
41
    private $strTotal = 0;
42
43
    /**
44
     * Number of unique shared strings in workbook
45
     *
46
     * @var int
47
     */
48
    private $strUnique = 0;
49
50
    /**
51
     * Array of unique shared strings in workbook
52
     *
53
     * @var array
54
     */
55
    private $strTable = [];
56
57
    /**
58
     * Color cache. Mapping between RGB value and color index.
59
     *
60
     * @var array
61
     */
62
    private $colors;
63
64
    /**
65
     * Formula parser
66
     *
67
     * @var \PhpOffice\PhpSpreadsheet\Writer\Xls\Parser
68
     */
69
    private $parser;
70
71
    /**
72
     * Identifier clusters for drawings. Used in MSODRAWINGGROUP record.
73
     *
74
     * @var array
75
     */
76
    private $IDCLs;
77
78
    /**
79
     * Basic OLE object summary information
80
     *
81
     * @var array
82
     */
83
    private $summaryInformation;
84
85
    /**
86
     * Extended OLE object document summary information
87
     *
88
     * @var array
89
     */
90
    private $documentSummaryInformation;
91
92
    /**
93
     * Create a new Xls Writer
94
     *
95
     * @param    \PhpOffice\PhpSpreadsheet\Spreadsheet    $spreadsheet    PhpSpreadsheet object
96
     */
97 38
    public function __construct(\PhpOffice\PhpSpreadsheet\Spreadsheet $spreadsheet)
98
    {
99 38
        $this->spreadsheet = $spreadsheet;
100
101 38
        $this->parser = new Xls\Parser();
102 38
    }
103
104
    /**
105
     * Save Spreadsheet to file
106
     *
107
     * @param    string        $pFilename
108
     * @throws    \PhpOffice\PhpSpreadsheet\Writer\Exception
109
     */
110 38
    public function save($pFilename = null)
111
    {
112
113
        // garbage collect
114 38
        $this->spreadsheet->garbageCollect();
115
116 38
        $saveDebugLog = \PhpOffice\PhpSpreadsheet\Calculation::getInstance($this->spreadsheet)->getDebugLog()->getWriteDebugLog();
117 38
        \PhpOffice\PhpSpreadsheet\Calculation::getInstance($this->spreadsheet)->getDebugLog()->setWriteDebugLog(false);
118 38
        $saveDateReturnType = \PhpOffice\PhpSpreadsheet\Calculation\Functions::getReturnDateType();
119 38
        \PhpOffice\PhpSpreadsheet\Calculation\Functions::setReturnDateType(\PhpOffice\PhpSpreadsheet\Calculation\Functions::RETURNDATE_EXCEL);
120
121
        // initialize colors array
122 38
        $this->colors = [];
123
124
        // Initialise workbook writer
125 38
        $this->writerWorkbook = new Xls\Workbook($this->spreadsheet, $this->strTotal, $this->strUnique, $this->strTable, $this->colors, $this->parser);
0 ignored issues
show
Bug introduced by
The property writerWorkbook does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
126
127
        // Initialise worksheet writers
128 38
        $countSheets = $this->spreadsheet->getSheetCount();
129 38
        for ($i = 0; $i < $countSheets; ++$i) {
130 38
            $this->writerWorksheets[$i] = new Xls\Worksheet($this->strTotal, $this->strUnique, $this->strTable, $this->colors, $this->parser, $this->preCalculateFormulas, $this->spreadsheet->getSheet($i));
0 ignored issues
show
Bug introduced by
The property writerWorksheets does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
Documentation introduced by
$this->spreadsheet->getSheet($i) is of type object<PhpOffice\PhpSpreadsheet\Worksheet>, but the function expects a string.

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...
131
        }
132
133
        // build Escher objects. Escher objects for workbooks needs to be build before Escher object for workbook.
134 38
        $this->buildWorksheetEschers();
135 38
        $this->buildWorkbookEscher();
136
137
        // add 15 identical cell style Xfs
138
        // for now, we use the first cellXf instead of cellStyleXf
139 38
        $cellXfCollection = $this->spreadsheet->getCellXfCollection();
140 38
        for ($i = 0; $i < 15; ++$i) {
141 38
            $this->writerWorkbook->addXfWriter($cellXfCollection[0], true);
142
        }
143
144
        // add all the cell Xfs
145 38
        foreach ($this->spreadsheet->getCellXfCollection() as $style) {
146 38
            $this->writerWorkbook->addXfWriter($style, false);
147
        }
148
149
        // add fonts from rich text eleemnts
150 38
        for ($i = 0; $i < $countSheets; ++$i) {
151 38
            foreach ($this->writerWorksheets[$i]->phpSheet->getCellCollection() as $cellID) {
152 38
                $cell = $this->writerWorksheets[$i]->phpSheet->getCell($cellID);
153 38
                $cVal = $cell->getValue();
154 38
                if ($cVal instanceof \PhpOffice\PhpSpreadsheet\RichText) {
155 9
                    $elements = $cVal->getRichTextElements();
156 9
                    foreach ($elements as $element) {
157 9
                        if ($element instanceof \PhpOffice\PhpSpreadsheet\RichText\Run) {
158 9
                            $font = $element->getFont();
159 38
                            $this->writerWorksheets[$i]->fontHashIndex[$font->getHashCode()] = $this->writerWorkbook->addFont($font);
160
                        }
161
                    }
162
                }
163
            }
164
        }
165
166
        // initialize OLE file
167 38
        $workbookStreamName = 'Workbook';
168 38
        $OLE = new \PhpOffice\PhpSpreadsheet\Shared\OLE\PPS\File(\PhpOffice\PhpSpreadsheet\Shared\OLE::ascToUcs($workbookStreamName));
169
170
        // Write the worksheet streams before the global workbook stream,
171
        // because the byte sizes of these are needed in the global workbook stream
172 38
        $worksheetSizes = [];
173 38
        for ($i = 0; $i < $countSheets; ++$i) {
174 38
            $this->writerWorksheets[$i]->close();
175 38
            $worksheetSizes[] = $this->writerWorksheets[$i]->_datasize;
176
        }
177
178
        // add binary data for global workbook stream
179 38
        $OLE->append($this->writerWorkbook->writeWorkbook($worksheetSizes));
180
181
        // add binary data for sheet streams
182 38
        for ($i = 0; $i < $countSheets; ++$i) {
183 38
            $OLE->append($this->writerWorksheets[$i]->getData());
184
        }
185
186 38
        $this->documentSummaryInformation = $this->writeDocumentSummaryInformation();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->writeDocumentSummaryInformation() of type string is incompatible with the declared type array of property $documentSummaryInformation.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
187
        // initialize OLE Document Summary Information
188 38 View Code Duplication
        if (isset($this->documentSummaryInformation) && !empty($this->documentSummaryInformation)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
189 38
            $OLE_DocumentSummaryInformation = new \PhpOffice\PhpSpreadsheet\Shared\OLE\PPS\File(\PhpOffice\PhpSpreadsheet\Shared\OLE::ascToUcs(chr(5) . 'DocumentSummaryInformation'));
190 38
            $OLE_DocumentSummaryInformation->append($this->documentSummaryInformation);
191
        }
192
193 38
        $this->summaryInformation = $this->writeSummaryInformation();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->writeSummaryInformation() of type string is incompatible with the declared type array of property $summaryInformation.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
194
        // initialize OLE Summary Information
195 38 View Code Duplication
        if (isset($this->summaryInformation) && !empty($this->summaryInformation)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
196 38
            $OLE_SummaryInformation = new \PhpOffice\PhpSpreadsheet\Shared\OLE\PPS\File(\PhpOffice\PhpSpreadsheet\Shared\OLE::ascToUcs(chr(5) . 'SummaryInformation'));
197 38
            $OLE_SummaryInformation->append($this->summaryInformation);
198
        }
199
200
        // define OLE Parts
201 38
        $arrRootData = [$OLE];
202
        // initialize OLE Properties file
203 38
        if (isset($OLE_SummaryInformation)) {
204 38
            $arrRootData[] = $OLE_SummaryInformation;
205
        }
206
        // initialize OLE Extended Properties file
207 38
        if (isset($OLE_DocumentSummaryInformation)) {
208 38
            $arrRootData[] = $OLE_DocumentSummaryInformation;
209
        }
210
211 38
        $root = new \PhpOffice\PhpSpreadsheet\Shared\OLE\PPS\Root(time(), time(), $arrRootData);
212
        // save the OLE file
213 38
        $res = $root->save($pFilename);
0 ignored issues
show
Unused Code introduced by
$res is not used, you could remove the assignment.

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

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

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

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

Loading history...
214
215 38
        \PhpOffice\PhpSpreadsheet\Calculation\Functions::setReturnDateType($saveDateReturnType);
216 38
        \PhpOffice\PhpSpreadsheet\Calculation::getInstance($this->spreadsheet)->getDebugLog()->setWriteDebugLog($saveDebugLog);
217 38
    }
218
219
    /**
220
     * Set temporary storage directory
221
     *
222
     * @deprecated
223
     * @param    string    $pValue        Temporary storage directory
224
     * @throws    \PhpOffice\PhpSpreadsheet\Writer\Exception    when directory does not exist
225
     * @return \PhpOffice\PhpSpreadsheet\Writer\Xls
226
     */
227
    public function setTempDir($pValue = '')
0 ignored issues
show
Unused Code introduced by
The parameter $pValue is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
228
    {
229
        return $this;
230
    }
231
232
    /**
233
     * Build the Worksheet Escher objects
234
     */
235 38
    private function buildWorksheetEschers()
236
    {
237
        // 1-based index to BstoreContainer
238 38
        $blipIndex = 0;
239 38
        $lastReducedSpId = 0;
240 38
        $lastSpId = 0;
241
242 38
        foreach ($this->spreadsheet->getAllsheets() as $sheet) {
243
            // sheet index
244 38
            $sheetIndex = $sheet->getParent()->getIndex($sheet);
245
246 38
            $escher = null;
0 ignored issues
show
Unused Code introduced by
$escher 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...
247
248
            // check if there are any shapes for this sheet
249 38
            $filterRange = $sheet->getAutoFilter()->getRange();
250 38
            if (count($sheet->getDrawingCollection()) == 0 && empty($filterRange)) {
251 30
                continue;
252
            }
253
254
            // create intermediate Escher object
255 10
            $escher = new \PhpOffice\PhpSpreadsheet\Shared\Escher();
256
257
            // dgContainer
258 10
            $dgContainer = new \PhpOffice\PhpSpreadsheet\Shared\Escher\DgContainer();
259
260
            // set the drawing index (we use sheet index + 1)
261 10
            $dgId = $sheet->getParent()->getIndex($sheet) + 1;
262 10
            $dgContainer->setDgId($dgId);
263 10
            $escher->setDgContainer($dgContainer);
264
265
            // spgrContainer
266 10
            $spgrContainer = new \PhpOffice\PhpSpreadsheet\Shared\Escher\DgContainer\SpgrContainer();
267 10
            $dgContainer->setSpgrContainer($spgrContainer);
268
269
            // add one shape which is the group shape
270 10
            $spContainer = new \PhpOffice\PhpSpreadsheet\Shared\Escher\DgContainer\SpgrContainer\SpContainer();
271 10
            $spContainer->setSpgr(true);
272 10
            $spContainer->setSpType(0);
273 10
            $spContainer->setSpId(($sheet->getParent()->getIndex($sheet) + 1) << 10);
274 10
            $spgrContainer->addChild($spContainer);
275
276
            // add the shapes
277
278 10
            $countShapes[$sheetIndex] = 0; // count number of shapes (minus group shape), in sheet
0 ignored issues
show
Coding Style Comprehensibility introduced by
$countShapes was never initialized. Although not strictly required by PHP, it is generally a good practice to add $countShapes = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
279
280 10
            foreach ($sheet->getDrawingCollection() as $drawing) {
281 7
                ++$blipIndex;
282
283 7
                ++$countShapes[$sheetIndex];
0 ignored issues
show
Bug introduced by
The variable $countShapes does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
284
285
                // add the shape
286 7
                $spContainer = new \PhpOffice\PhpSpreadsheet\Shared\Escher\DgContainer\SpgrContainer\SpContainer();
287
288
                // set the shape type
289 7
                $spContainer->setSpType(0x004B);
290
                // set the shape flag
291 7
                $spContainer->setSpFlag(0x02);
292
293
                // set the shape index (we combine 1-based sheet index and $countShapes to create unique shape index)
294 7
                $reducedSpId = $countShapes[$sheetIndex];
295 7
                $spId = $reducedSpId | ($sheet->getParent()->getIndex($sheet) + 1) << 10;
296 7
                $spContainer->setSpId($spId);
297
298
                // keep track of last reducedSpId
299 7
                $lastReducedSpId = $reducedSpId;
300
301
                // keep track of last spId
302 7
                $lastSpId = $spId;
303
304
                // set the BLIP index
305 7
                $spContainer->setOPT(0x4104, $blipIndex);
306
307
                // set coordinates and offsets, client anchor
308 7
                $coordinates = $drawing->getCoordinates();
309 7
                $offsetX = $drawing->getOffsetX();
310 7
                $offsetY = $drawing->getOffsetY();
311 7
                $width = $drawing->getWidth();
312 7
                $height = $drawing->getHeight();
313
314 7
                $twoAnchor = \PhpOffice\PhpSpreadsheet\Shared\Xls::oneAnchor2twoAnchor($sheet, $coordinates, $offsetX, $offsetY, $width, $height);
315
316 7
                $spContainer->setStartCoordinates($twoAnchor['startCoordinates']);
317 7
                $spContainer->setStartOffsetX($twoAnchor['startOffsetX']);
318 7
                $spContainer->setStartOffsetY($twoAnchor['startOffsetY']);
319 7
                $spContainer->setEndCoordinates($twoAnchor['endCoordinates']);
320 7
                $spContainer->setEndOffsetX($twoAnchor['endOffsetX']);
321 7
                $spContainer->setEndOffsetY($twoAnchor['endOffsetY']);
322
323 7
                $spgrContainer->addChild($spContainer);
324
            }
325
326
            // AutoFilters
327 10
            if (!empty($filterRange)) {
328 3
                $rangeBounds = \PhpOffice\PhpSpreadsheet\Cell::rangeBoundaries($filterRange);
329 3
                $iNumColStart = $rangeBounds[0][0];
330 3
                $iNumColEnd = $rangeBounds[1][0];
331
332 3
                $iInc = $iNumColStart;
333 3
                while ($iInc <= $iNumColEnd) {
334 3
                    ++$countShapes[$sheetIndex];
335
336
                    // create an Drawing Object for the dropdown
337 3
                    $oDrawing = new \PhpOffice\PhpSpreadsheet\Worksheet\BaseDrawing();
338
                    // get the coordinates of drawing
339 3
                    $cDrawing = \PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex($iInc - 1) . $rangeBounds[0][1];
340 3
                    $oDrawing->setCoordinates($cDrawing);
341 3
                    $oDrawing->setWorksheet($sheet);
342
343
                    // add the shape
344 3
                    $spContainer = new \PhpOffice\PhpSpreadsheet\Shared\Escher\DgContainer\SpgrContainer\SpContainer();
345
                    // set the shape type
346 3
                    $spContainer->setSpType(0x00C9);
347
                    // set the shape flag
348 3
                    $spContainer->setSpFlag(0x01);
349
350
                    // set the shape index (we combine 1-based sheet index and $countShapes to create unique shape index)
351 3
                    $reducedSpId = $countShapes[$sheetIndex];
352 3
                    $spId = $reducedSpId | ($sheet->getParent()->getIndex($sheet) + 1) << 10;
353 3
                    $spContainer->setSpId($spId);
354
355
                    // keep track of last reducedSpId
356 3
                    $lastReducedSpId = $reducedSpId;
357
358
                    // keep track of last spId
359 3
                    $lastSpId = $spId;
360
361 3
                    $spContainer->setOPT(0x007F, 0x01040104); // Protection -> fLockAgainstGrouping
362 3
                    $spContainer->setOPT(0x00BF, 0x00080008); // Text -> fFitTextToShape
363 3
                    $spContainer->setOPT(0x01BF, 0x00010000); // Fill Style -> fNoFillHitTest
364 3
                    $spContainer->setOPT(0x01FF, 0x00080000); // Line Style -> fNoLineDrawDash
365 3
                    $spContainer->setOPT(0x03BF, 0x000A0000); // Group Shape -> fPrint
366
367
                    // set coordinates and offsets, client anchor
368 3
                    $endCoordinates = \PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex($iInc - 1);
369 3
                    $endCoordinates .= $rangeBounds[0][1] + 1;
370
371 3
                    $spContainer->setStartCoordinates($cDrawing);
372 3
                    $spContainer->setStartOffsetX(0);
373 3
                    $spContainer->setStartOffsetY(0);
374 3
                    $spContainer->setEndCoordinates($endCoordinates);
375 3
                    $spContainer->setEndOffsetX(0);
376 3
                    $spContainer->setEndOffsetY(0);
377
378 3
                    $spgrContainer->addChild($spContainer);
379 3
                    ++$iInc;
380
                }
381
            }
382
383
            // identifier clusters, used for workbook Escher object
384 10
            $this->IDCLs[$dgId] = $lastReducedSpId;
385
386
            // set last shape index
387 10
            $dgContainer->setLastSpId($lastSpId);
388
389
            // set the Escher object
390 10
            $this->writerWorksheets[$sheetIndex]->setEscher($escher);
391
        }
392 38
    }
393
394
    /**
395
     * Build the Escher object corresponding to the MSODRAWINGGROUP record
396
     */
397 38
    private function buildWorkbookEscher()
398
    {
399 38
        $escher = null;
0 ignored issues
show
Unused Code introduced by
$escher 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...
400
401
        // any drawings in this workbook?
402 38
        $found = false;
403 38
        foreach ($this->spreadsheet->getAllSheets() as $sheet) {
404 38
            if (count($sheet->getDrawingCollection()) > 0) {
405 10
                $found = true;
406 38
                break;
407
            }
408
        }
409
410
        // nothing to do if there are no drawings
411 38
        if (!$found) {
412 29
            return;
413
        }
414
415
        // if we reach here, then there are drawings in the workbook
416 10
        $escher = new \PhpOffice\PhpSpreadsheet\Shared\Escher();
417
418
        // dggContainer
419 10
        $dggContainer = new \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer();
420 10
        $escher->setDggContainer($dggContainer);
421
422
        // set IDCLs (identifier clusters)
423 10
        $dggContainer->setIDCLs($this->IDCLs);
424
425
        // this loop is for determining maximum shape identifier of all drawing
426 10
        $spIdMax = 0;
427 10
        $totalCountShapes = 0;
428 10
        $countDrawings = 0;
429
430 10
        foreach ($this->spreadsheet->getAllsheets() as $sheet) {
431 10
            $sheetCountShapes = 0; // count number of shapes (minus group shape), in sheet
432
433 10
            if (count($sheet->getDrawingCollection()) > 0) {
434 10
                ++$countDrawings;
435
436 10
                foreach ($sheet->getDrawingCollection() as $drawing) {
437 10
                    ++$sheetCountShapes;
438 10
                    ++$totalCountShapes;
439
440 10
                    $spId = $sheetCountShapes | ($this->spreadsheet->getIndex($sheet) + 1) << 10;
441 10
                    $spIdMax = max($spId, $spIdMax);
442
                }
443
            }
444
        }
445
446 10
        $dggContainer->setSpIdMax($spIdMax + 1);
447 10
        $dggContainer->setCDgSaved($countDrawings);
448 10
        $dggContainer->setCSpSaved($totalCountShapes + $countDrawings); // total number of shapes incl. one group shapes per drawing
449
450
        // bstoreContainer
451 10
        $bstoreContainer = new \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer();
452 10
        $dggContainer->setBstoreContainer($bstoreContainer);
453
454
        // the BSE's (all the images)
455 10
        foreach ($this->spreadsheet->getAllsheets() as $sheet) {
456 10
            foreach ($sheet->getDrawingCollection() as $drawing) {
457 10
                if (!extension_loaded('gd')) {
458
                    throw new \RuntimeException('Saving images in xls requires gd extension');
459
                }
460 10
                if ($drawing instanceof \PhpOffice\PhpSpreadsheet\Worksheet\Drawing) {
461 5
                    $filename = $drawing->getPath();
462
463 5
                    list($imagesx, $imagesy, $imageFormat) = getimagesize($filename);
0 ignored issues
show
Unused Code introduced by
The assignment to $imagesx is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
Unused Code introduced by
The assignment to $imagesy is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
464
465
                    switch ($imageFormat) {
466 5
                        case 1: // GIF, not supported by BIFF8, we convert to PNG
467
                            $blipType = \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE::BLIPTYPE_PNG;
468
                            ob_start();
469
                            imagepng(imagecreatefromgif($filename));
470
                            $blipData = ob_get_contents();
471
                            ob_end_clean();
472
                            break;
473 5
                        case 2: // JPEG
474 5
                            $blipType = \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE::BLIPTYPE_JPEG;
475 5
                            $blipData = file_get_contents($filename);
476 5
                            break;
477 5
                        case 3: // PNG
478 5
                            $blipType = \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE::BLIPTYPE_PNG;
479 5
                            $blipData = file_get_contents($filename);
480 5
                            break;
481
                        case 6: // Windows DIB (BMP), we convert to PNG
482
                            $blipType = \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE::BLIPTYPE_PNG;
483
                            ob_start();
484
                            imagepng(\PhpOffice\PhpSpreadsheet\Shared\Drawing::imagecreatefrombmp($filename));
485
                            $blipData = ob_get_contents();
486
                            ob_end_clean();
487
                            break;
488
                        default:
489
                            continue 2;
490
                    }
491
492 5
                    $blip = new \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE\Blip();
493 5
                    $blip->setData($blipData);
494
495 5
                    $BSE = new \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE();
496 5
                    $BSE->setBlipType($blipType);
497 5
                    $BSE->setBlip($blip);
498
499 5
                    $bstoreContainer->addBSE($BSE);
500 3
                } elseif ($drawing instanceof \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing) {
501 2
                    switch ($drawing->getRenderingFunction()) {
502 2
                        case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::RENDERING_JPEG:
503 2
                            $blipType = \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE::BLIPTYPE_JPEG;
504 2
                            $renderingFunction = 'imagejpeg';
505 2
                            break;
506 2
                        case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::RENDERING_GIF:
507 2
                        case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::RENDERING_PNG:
508
                        case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::RENDERING_DEFAULT:
509 2
                            $blipType = \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE::BLIPTYPE_PNG;
510 2
                            $renderingFunction = 'imagepng';
511 2
                            break;
512
                    }
513
514 2
                    ob_start();
515 2
                    call_user_func($renderingFunction, $drawing->getImageResource());
0 ignored issues
show
Bug introduced by
The variable $renderingFunction does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
516 2
                    $blipData = ob_get_contents();
517 2
                    ob_end_clean();
518
519 2
                    $blip = new \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE\Blip();
520 2
                    $blip->setData($blipData);
521
522 2
                    $BSE = new \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE();
523 2
                    $BSE->setBlipType($blipType);
0 ignored issues
show
Bug introduced by
The variable $blipType does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
524 2
                    $BSE->setBlip($blip);
525
526 10
                    $bstoreContainer->addBSE($BSE);
527
                }
528
            }
529
        }
530
531
        // Set the Escher object
532 10
        $this->writerWorkbook->setEscher($escher);
533 10
    }
534
535
    /**
536
     * Build the OLE Part for DocumentSummary Information
537
     * @return string
538
     */
539 38
    private function writeDocumentSummaryInformation()
540
    {
541
        // offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark)
542 38
        $data = pack('v', 0xFFFE);
543
        // offset: 2; size: 2;
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
544 38
        $data .= pack('v', 0x0000);
545
        // offset: 4; size: 2; OS version
546 38
        $data .= pack('v', 0x0106);
547
        // offset: 6; size: 2; OS indicator
548 38
        $data .= pack('v', 0x0002);
549
        // offset: 8; size: 16
550 38
        $data .= pack('VVVV', 0x00, 0x00, 0x00, 0x00);
551
        // offset: 24; size: 4; section count
552 38
        $data .= pack('V', 0x0001);
553
554
        // offset: 28; size: 16; first section's class id: 02 d5 cd d5 9c 2e 1b 10 93 97 08 00 2b 2c f9 ae
555 38
        $data .= pack('vvvvvvvv', 0xD502, 0xD5CD, 0x2E9C, 0x101B, 0x9793, 0x0008, 0x2C2B, 0xAEF9);
556
        // offset: 44; size: 4; offset of the start
557 38
        $data .= pack('V', 0x30);
558
559
        // SECTION
560 38
        $dataSection = [];
561 38
        $dataSection_NumProps = 0;
562 38
        $dataSection_Summary = '';
563 38
        $dataSection_Content = '';
564
565
        // GKPIDDSI_CODEPAGE: CodePage
566 38
        $dataSection[] = [
567
            'summary' => ['pack' => 'V', 'data' => 0x01],
568
            'offset' => ['pack' => 'V'],
569
            'type' => ['pack' => 'V', 'data' => 0x02], // 2 byte signed integer
570
            'data' => ['data' => 1252],
571
        ];
572 38
        ++$dataSection_NumProps;
573
574
        // GKPIDDSI_CATEGORY : Category
575 38 View Code Duplication
        if ($this->spreadsheet->getProperties()->getCategory()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
576 31
            $dataProp = $this->spreadsheet->getProperties()->getCategory();
577 31
            $dataSection[] = [
578 31
                'summary' => ['pack' => 'V', 'data' => 0x02],
579
                'offset' => ['pack' => 'V'],
580
                'type' => ['pack' => 'V', 'data' => 0x1E],
581 31
                'data' => ['data' => $dataProp, 'length' => strlen($dataProp)],
582
            ];
583 31
            ++$dataSection_NumProps;
584
        }
585
        // GKPIDDSI_VERSION :Version of the application that wrote the property storage
586 38
        $dataSection[] = [
587
            'summary' => ['pack' => 'V', 'data' => 0x17],
588
            'offset' => ['pack' => 'V'],
589
            'type' => ['pack' => 'V', 'data' => 0x03],
590
            'data' => ['pack' => 'V', 'data' => 0x000C0000],
591
        ];
592 38
        ++$dataSection_NumProps;
593
        // GKPIDDSI_SCALE : FALSE
594 38
        $dataSection[] = [
595
            'summary' => ['pack' => 'V', 'data' => 0x0B],
596
            'offset' => ['pack' => 'V'],
597
            'type' => ['pack' => 'V', 'data' => 0x0B],
598
            'data' => ['data' => false],
599
        ];
600 38
        ++$dataSection_NumProps;
601
        // GKPIDDSI_LINKSDIRTY : True if any of the values for the linked properties have changed outside of the application
602 38
        $dataSection[] = [
603
            'summary' => ['pack' => 'V', 'data' => 0x10],
604
            'offset' => ['pack' => 'V'],
605
            'type' => ['pack' => 'V', 'data' => 0x0B],
606
            'data' => ['data' => false],
607
        ];
608 38
        ++$dataSection_NumProps;
609
        // GKPIDDSI_SHAREDOC : FALSE
610 38
        $dataSection[] = [
611
            'summary' => ['pack' => 'V', 'data' => 0x13],
612
            'offset' => ['pack' => 'V'],
613
            'type' => ['pack' => 'V', 'data' => 0x0B],
614
            'data' => ['data' => false],
615
        ];
616 38
        ++$dataSection_NumProps;
617
        // GKPIDDSI_HYPERLINKSCHANGED : True if any of the values for the _PID_LINKS (hyperlink text) have changed outside of the application
618 38
        $dataSection[] = [
619
            'summary' => ['pack' => 'V', 'data' => 0x16],
620
            'offset' => ['pack' => 'V'],
621
            'type' => ['pack' => 'V', 'data' => 0x0B],
622
            'data' => ['data' => false],
623
        ];
624 38
        ++$dataSection_NumProps;
625
626
        // GKPIDDSI_DOCSPARTS
627
        // MS-OSHARED p75 (2.3.3.2.2.1)
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
628
        // Structure is VtVecUnalignedLpstrValue (2.3.3.1.9)
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
629
        // cElements
630 38
        $dataProp = pack('v', 0x0001);
631 38
        $dataProp .= pack('v', 0x0000);
632
        // array of UnalignedLpstr
633
        // cch
634 38
        $dataProp .= pack('v', 0x000A);
635 38
        $dataProp .= pack('v', 0x0000);
636
        // value
637 38
        $dataProp .= 'Worksheet' . chr(0);
638
639 38
        $dataSection[] = [
640 38
            'summary' => ['pack' => 'V', 'data' => 0x0D],
641
            'offset' => ['pack' => 'V'],
642
            'type' => ['pack' => 'V', 'data' => 0x101E],
643 38
            'data' => ['data' => $dataProp, 'length' => strlen($dataProp)],
644
        ];
645 38
        ++$dataSection_NumProps;
646
647
        // GKPIDDSI_HEADINGPAIR
648
        // VtVecHeadingPairValue
649
        // cElements
650 38
        $dataProp = pack('v', 0x0002);
651 38
        $dataProp .= pack('v', 0x0000);
652
        // Array of vtHeadingPair
653
        // vtUnalignedString - headingString
654
        // stringType
655 38
        $dataProp .= pack('v', 0x001E);
656
        // padding
657 38
        $dataProp .= pack('v', 0x0000);
658
        // UnalignedLpstr
659
        // cch
660 38
        $dataProp .= pack('v', 0x0013);
661 38
        $dataProp .= pack('v', 0x0000);
662
        // value
663 38
        $dataProp .= 'Feuilles de calcul';
664
        // vtUnalignedString - headingParts
665
        // wType : 0x0003 = 32 bit signed integer
666 38
        $dataProp .= pack('v', 0x0300);
667
        // padding
668 38
        $dataProp .= pack('v', 0x0000);
669
        // value
670 38
        $dataProp .= pack('v', 0x0100);
671 38
        $dataProp .= pack('v', 0x0000);
672 38
        $dataProp .= pack('v', 0x0000);
673 38
        $dataProp .= pack('v', 0x0000);
674
675 38
        $dataSection[] = [
676 38
            'summary' => ['pack' => 'V', 'data' => 0x0C],
677
            'offset' => ['pack' => 'V'],
678
            'type' => ['pack' => 'V', 'data' => 0x100C],
679 38
            'data' => ['data' => $dataProp, 'length' => strlen($dataProp)],
680
        ];
681 38
        ++$dataSection_NumProps;
682
683
        //         4     Section Length
684
        //        4     Property count
685
        //        8 * $dataSection_NumProps (8 =  ID (4) + OffSet(4))
0 ignored issues
show
Unused Code Comprehensibility introduced by
44% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
686 38
        $dataSection_Content_Offset = 8 + $dataSection_NumProps * 8;
687 38
        foreach ($dataSection as $dataProp) {
688
            // Summary
689 38
            $dataSection_Summary .= pack($dataProp['summary']['pack'], $dataProp['summary']['data']);
690
            // Offset
691 38
            $dataSection_Summary .= pack($dataProp['offset']['pack'], $dataSection_Content_Offset);
692
            // DataType
693 38
            $dataSection_Content .= pack($dataProp['type']['pack'], $dataProp['type']['data']);
694
            // Data
695 38
            if ($dataProp['type']['data'] == 0x02) { // 2 byte signed integer
696 38
                $dataSection_Content .= pack('V', $dataProp['data']['data']);
697
698 38
                $dataSection_Content_Offset += 4 + 4;
699 38
            } elseif ($dataProp['type']['data'] == 0x03) { // 4 byte signed integer
700 38
                $dataSection_Content .= pack('V', $dataProp['data']['data']);
701
702 38
                $dataSection_Content_Offset += 4 + 4;
703 38
            } elseif ($dataProp['type']['data'] == 0x0B) { // Boolean
704 38
                if ($dataProp['data']['data'] == false) {
705 38
                    $dataSection_Content .= pack('V', 0x0000);
706
                } else {
707
                    $dataSection_Content .= pack('V', 0x0001);
708
                }
709 38
                $dataSection_Content_Offset += 4 + 4;
710 38 View Code Duplication
            } elseif ($dataProp['type']['data'] == 0x1E) { // null-terminated string prepended by dword string length
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
711
                // Null-terminated string
712 31
                $dataProp['data']['data'] .= chr(0);
713 31
                $dataProp['data']['length'] += 1;
714
                // Complete the string with null string for being a %4
715 31
                $dataProp['data']['length'] = $dataProp['data']['length'] + ((4 - $dataProp['data']['length'] % 4) == 4 ? 0 : (4 - $dataProp['data']['length'] % 4));
716 31
                $dataProp['data']['data'] = str_pad($dataProp['data']['data'], $dataProp['data']['length'], chr(0), STR_PAD_RIGHT);
717
718 31
                $dataSection_Content .= pack('V', $dataProp['data']['length']);
719 31
                $dataSection_Content .= $dataProp['data']['data'];
720
721 31
                $dataSection_Content_Offset += 4 + 4 + strlen($dataProp['data']['data']);
722 38
            } elseif ($dataProp['type']['data'] == 0x40) { // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
723
                $dataSection_Content .= $dataProp['data']['data'];
724
725
                $dataSection_Content_Offset += 4 + 8;
726
            } else {
727
                // Data Type Not Used at the moment
728 38
                $dataSection_Content .= $dataProp['data']['data'];
729
730 38
                $dataSection_Content_Offset += 4 + $dataProp['data']['length'];
731
            }
732
        }
733
        // Now $dataSection_Content_Offset contains the size of the content
734
735
        // section header
736
        // offset: $secOffset; size: 4; section length
737
        //         + x  Size of the content (summary + content)
738 38
        $data .= pack('V', $dataSection_Content_Offset);
739
        // offset: $secOffset+4; size: 4; property count
740 38
        $data .= pack('V', $dataSection_NumProps);
741
        // Section Summary
742 38
        $data .= $dataSection_Summary;
743
        // Section Content
744 38
        $data .= $dataSection_Content;
745
746 38
        return $data;
747
    }
748
749
    /**
750
     * Build the OLE Part for Summary Information
751
     * @return string
752
     */
753 38
    private function writeSummaryInformation()
754
    {
755
        // offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark)
756 38
        $data = pack('v', 0xFFFE);
757
        // offset: 2; size: 2;
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
758 38
        $data .= pack('v', 0x0000);
759
        // offset: 4; size: 2; OS version
760 38
        $data .= pack('v', 0x0106);
761
        // offset: 6; size: 2; OS indicator
762 38
        $data .= pack('v', 0x0002);
763
        // offset: 8; size: 16
764 38
        $data .= pack('VVVV', 0x00, 0x00, 0x00, 0x00);
765
        // offset: 24; size: 4; section count
766 38
        $data .= pack('V', 0x0001);
767
768
        // offset: 28; size: 16; first section's class id: e0 85 9f f2 f9 4f 68 10 ab 91 08 00 2b 27 b3 d9
769 38
        $data .= pack('vvvvvvvv', 0x85E0, 0xF29F, 0x4FF9, 0x1068, 0x91AB, 0x0008, 0x272B, 0xD9B3);
770
        // offset: 44; size: 4; offset of the start
771 38
        $data .= pack('V', 0x30);
772
773
        // SECTION
774 38
        $dataSection = [];
775 38
        $dataSection_NumProps = 0;
776 38
        $dataSection_Summary = '';
777 38
        $dataSection_Content = '';
778
779
        // CodePage : CP-1252
780 38
        $dataSection[] = [
781
            'summary' => ['pack' => 'V', 'data' => 0x01],
782
            'offset' => ['pack' => 'V'],
783
            'type' => ['pack' => 'V', 'data' => 0x02], // 2 byte signed integer
784
            'data' => ['data' => 1252],
785
        ];
786 38
        ++$dataSection_NumProps;
787
788
        //    Title
789 38 View Code Duplication
        if ($this->spreadsheet->getProperties()->getTitle()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
790 37
            $dataProp = $this->spreadsheet->getProperties()->getTitle();
791 37
            $dataSection[] = [
792 37
                'summary' => ['pack' => 'V', 'data' => 0x02],
793
                'offset' => ['pack' => 'V'],
794
                'type' => ['pack' => 'V', 'data' => 0x1E], // null-terminated string prepended by dword string length
795 37
                'data' => ['data' => $dataProp, 'length' => strlen($dataProp)],
796
            ];
797 37
            ++$dataSection_NumProps;
798
        }
799
        //    Subject
800 38 View Code Duplication
        if ($this->spreadsheet->getProperties()->getSubject()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
801 32
            $dataProp = $this->spreadsheet->getProperties()->getSubject();
802 32
            $dataSection[] = [
803 32
                'summary' => ['pack' => 'V', 'data' => 0x03],
804
                'offset' => ['pack' => 'V'],
805
                'type' => ['pack' => 'V', 'data' => 0x1E], // null-terminated string prepended by dword string length
806 32
                'data' => ['data' => $dataProp, 'length' => strlen($dataProp)],
807
            ];
808 32
            ++$dataSection_NumProps;
809
        }
810
        //    Author (Creator)
811 38 View Code Duplication
        if ($this->spreadsheet->getProperties()->getCreator()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
812 38
            $dataProp = $this->spreadsheet->getProperties()->getCreator();
813 38
            $dataSection[] = [
814 38
                'summary' => ['pack' => 'V', 'data' => 0x04],
815
                'offset' => ['pack' => 'V'],
816
                'type' => ['pack' => 'V', 'data' => 0x1E], // null-terminated string prepended by dword string length
817 38
                'data' => ['data' => $dataProp, 'length' => strlen($dataProp)],
818
            ];
819 38
            ++$dataSection_NumProps;
820
        }
821
        //    Keywords
822 38 View Code Duplication
        if ($this->spreadsheet->getProperties()->getKeywords()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
823 32
            $dataProp = $this->spreadsheet->getProperties()->getKeywords();
824 32
            $dataSection[] = [
825 32
                'summary' => ['pack' => 'V', 'data' => 0x05],
826
                'offset' => ['pack' => 'V'],
827
                'type' => ['pack' => 'V', 'data' => 0x1E], // null-terminated string prepended by dword string length
828 32
                'data' => ['data' => $dataProp, 'length' => strlen($dataProp)],
829
            ];
830 32
            ++$dataSection_NumProps;
831
        }
832
        //    Comments (Description)
833 38 View Code Duplication
        if ($this->spreadsheet->getProperties()->getDescription()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
834 31
            $dataProp = $this->spreadsheet->getProperties()->getDescription();
835 31
            $dataSection[] = [
836 31
                'summary' => ['pack' => 'V', 'data' => 0x06],
837
                'offset' => ['pack' => 'V'],
838
                'type' => ['pack' => 'V', 'data' => 0x1E], // null-terminated string prepended by dword string length
839 31
                'data' => ['data' => $dataProp, 'length' => strlen($dataProp)],
840
            ];
841 31
            ++$dataSection_NumProps;
842
        }
843
        //    Last Saved By (LastModifiedBy)
844 38 View Code Duplication
        if ($this->spreadsheet->getProperties()->getLastModifiedBy()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
845 38
            $dataProp = $this->spreadsheet->getProperties()->getLastModifiedBy();
846 38
            $dataSection[] = [
847 38
                'summary' => ['pack' => 'V', 'data' => 0x08],
848
                'offset' => ['pack' => 'V'],
849
                'type' => ['pack' => 'V', 'data' => 0x1E], // null-terminated string prepended by dword string length
850 38
                'data' => ['data' => $dataProp, 'length' => strlen($dataProp)],
851
            ];
852 38
            ++$dataSection_NumProps;
853
        }
854
        //    Created Date/Time
855 38 View Code Duplication
        if ($this->spreadsheet->getProperties()->getCreated()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
856 38
            $dataProp = $this->spreadsheet->getProperties()->getCreated();
857 38
            $dataSection[] = [
858 38
                'summary' => ['pack' => 'V', 'data' => 0x0C],
859
                'offset' => ['pack' => 'V'],
860
                'type' => ['pack' => 'V', 'data' => 0x40], // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
861 38
                'data' => ['data' => \PhpOffice\PhpSpreadsheet\Shared\OLE::localDateToOLE($dataProp)],
862
            ];
863 38
            ++$dataSection_NumProps;
864
        }
865
        //    Modified Date/Time
866 38 View Code Duplication
        if ($this->spreadsheet->getProperties()->getModified()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
867 38
            $dataProp = $this->spreadsheet->getProperties()->getModified();
868 38
            $dataSection[] = [
869 38
                'summary' => ['pack' => 'V', 'data' => 0x0D],
870
                'offset' => ['pack' => 'V'],
871
                'type' => ['pack' => 'V', 'data' => 0x40], // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
872 38
                'data' => ['data' => \PhpOffice\PhpSpreadsheet\Shared\OLE::localDateToOLE($dataProp)],
873
            ];
874 38
            ++$dataSection_NumProps;
875
        }
876
        //    Security
877 38
        $dataSection[] = [
878
            'summary' => ['pack' => 'V', 'data' => 0x13],
879
            'offset' => ['pack' => 'V'],
880
            'type' => ['pack' => 'V', 'data' => 0x03], // 4 byte signed integer
881
            'data' => ['data' => 0x00],
882
        ];
883 38
        ++$dataSection_NumProps;
884
885
        //         4     Section Length
886
        //        4     Property count
887
        //        8 * $dataSection_NumProps (8 =  ID (4) + OffSet(4))
0 ignored issues
show
Unused Code Comprehensibility introduced by
44% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
888 38
        $dataSection_Content_Offset = 8 + $dataSection_NumProps * 8;
889 38
        foreach ($dataSection as $dataProp) {
890
            // Summary
891 38
            $dataSection_Summary .= pack($dataProp['summary']['pack'], $dataProp['summary']['data']);
892
            // Offset
893 38
            $dataSection_Summary .= pack($dataProp['offset']['pack'], $dataSection_Content_Offset);
894
            // DataType
895 38
            $dataSection_Content .= pack($dataProp['type']['pack'], $dataProp['type']['data']);
896
            // Data
897 38
            if ($dataProp['type']['data'] == 0x02) { // 2 byte signed integer
898 38
                $dataSection_Content .= pack('V', $dataProp['data']['data']);
899
900 38
                $dataSection_Content_Offset += 4 + 4;
901 38
            } elseif ($dataProp['type']['data'] == 0x03) { // 4 byte signed integer
902 38
                $dataSection_Content .= pack('V', $dataProp['data']['data']);
903
904 38
                $dataSection_Content_Offset += 4 + 4;
905 38 View Code Duplication
            } elseif ($dataProp['type']['data'] == 0x1E) { // null-terminated string prepended by dword string length
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
906
                // Null-terminated string
907 38
                $dataProp['data']['data'] .= chr(0);
908 38
                $dataProp['data']['length'] += 1;
909
                // Complete the string with null string for being a %4
910 38
                $dataProp['data']['length'] = $dataProp['data']['length'] + ((4 - $dataProp['data']['length'] % 4) == 4 ? 0 : (4 - $dataProp['data']['length'] % 4));
911 38
                $dataProp['data']['data'] = str_pad($dataProp['data']['data'], $dataProp['data']['length'], chr(0), STR_PAD_RIGHT);
912
913 38
                $dataSection_Content .= pack('V', $dataProp['data']['length']);
914 38
                $dataSection_Content .= $dataProp['data']['data'];
915
916 38
                $dataSection_Content_Offset += 4 + 4 + strlen($dataProp['data']['data']);
917 38
            } elseif ($dataProp['type']['data'] == 0x40) { // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
918 38
                $dataSection_Content .= $dataProp['data']['data'];
919
920 38
                $dataSection_Content_Offset += 4 + 8;
921 38
            } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
922
                // Data Type Not Used at the moment
923
            }
924
        }
925
        // Now $dataSection_Content_Offset contains the size of the content
926
927
        // section header
928
        // offset: $secOffset; size: 4; section length
929
        //         + x  Size of the content (summary + content)
930 38
        $data .= pack('V', $dataSection_Content_Offset);
931
        // offset: $secOffset+4; size: 4; property count
932 38
        $data .= pack('V', $dataSection_NumProps);
933
        // Section Summary
934 38
        $data .= $dataSection_Summary;
935
        // Section Content
936 38
        $data .= $dataSection_Content;
937
938 38
        return $data;
939
    }
940
}
941