Completed
Push — develop ( 39b55d...e2e982 )
by Adrien
19:14
created

Xls::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 1
rs 9.4285
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 ($drawing instanceof \PhpOffice\PhpSpreadsheet\Worksheet\Drawing) {
458 5
                    $filename = $drawing->getPath();
459
460 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...
461
462
                    switch ($imageFormat) {
463 5
                        case 1: // GIF, not supported by BIFF8, we convert to PNG
464 5
                            $blipType = \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE::BLIPTYPE_PNG;
465 5
                            ob_start();
466 5
                            imagepng(imagecreatefromgif($filename));
467 5
                            $blipData = ob_get_contents();
468 5
                            ob_end_clean();
469 5
                            break;
470 5
                        case 2: // JPEG
471 5
                            $blipType = \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE::BLIPTYPE_JPEG;
472 5
                            $blipData = file_get_contents($filename);
473 5
                            break;
474 5
                        case 3: // PNG
475 5
                            $blipType = \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE::BLIPTYPE_PNG;
476 5
                            $blipData = file_get_contents($filename);
477 5
                            break;
478
                        case 6: // Windows DIB (BMP), we convert to PNG
479
                            $blipType = \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE::BLIPTYPE_PNG;
480
                            ob_start();
481
                            imagepng(\PhpOffice\PhpSpreadsheet\Shared\Drawing::imagecreatefrombmp($filename));
482
                            $blipData = ob_get_contents();
483
                            ob_end_clean();
484
                            break;
485
                        default:
486
                            continue 2;
487
                    }
488
489 5
                    $blip = new \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE\Blip();
490 5
                    $blip->setData($blipData);
491
492 5
                    $BSE = new \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE();
493 5
                    $BSE->setBlipType($blipType);
494 5
                    $BSE->setBlip($blip);
495
496 5
                    $bstoreContainer->addBSE($BSE);
497 3
                } elseif ($drawing instanceof \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing) {
498 2
                    switch ($drawing->getRenderingFunction()) {
499 2
                        case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::RENDERING_JPEG:
500 2
                            $blipType = \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE::BLIPTYPE_JPEG;
501 2
                            $renderingFunction = 'imagejpeg';
502 2
                            break;
503 2
                        case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::RENDERING_GIF:
504 2
                        case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::RENDERING_PNG:
505
                        case \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::RENDERING_DEFAULT:
506 2
                            $blipType = \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE::BLIPTYPE_PNG;
507 2
                            $renderingFunction = 'imagepng';
508 2
                            break;
509
                    }
510
511 2
                    ob_start();
512 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...
513 2
                    $blipData = ob_get_contents();
514 2
                    ob_end_clean();
515
516 2
                    $blip = new \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE\Blip();
517 2
                    $blip->setData($blipData);
518
519 2
                    $BSE = new \PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE();
520 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...
521 2
                    $BSE->setBlip($blip);
522
523 10
                    $bstoreContainer->addBSE($BSE);
524
                }
525
            }
526
        }
527
528
        // Set the Escher object
529 10
        $this->writerWorkbook->setEscher($escher);
530 10
    }
531
532
    /**
533
     * Build the OLE Part for DocumentSummary Information
534
     * @return string
535
     */
536 38
    private function writeDocumentSummaryInformation()
537
    {
538
        // offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark)
539 38
        $data = pack('v', 0xFFFE);
540
        // 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...
541 38
        $data .= pack('v', 0x0000);
542
        // offset: 4; size: 2; OS version
543 38
        $data .= pack('v', 0x0106);
544
        // offset: 6; size: 2; OS indicator
545 38
        $data .= pack('v', 0x0002);
546
        // offset: 8; size: 16
547 38
        $data .= pack('VVVV', 0x00, 0x00, 0x00, 0x00);
548
        // offset: 24; size: 4; section count
549 38
        $data .= pack('V', 0x0001);
550
551
        // 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
552 38
        $data .= pack('vvvvvvvv', 0xD502, 0xD5CD, 0x2E9C, 0x101B, 0x9793, 0x0008, 0x2C2B, 0xAEF9);
553
        // offset: 44; size: 4; offset of the start
554 38
        $data .= pack('V', 0x30);
555
556
        // SECTION
557 38
        $dataSection = [];
558 38
        $dataSection_NumProps = 0;
559 38
        $dataSection_Summary = '';
560 38
        $dataSection_Content = '';
561
562
        // GKPIDDSI_CODEPAGE: CodePage
563 38
        $dataSection[] = [
564
            'summary' => ['pack' => 'V', 'data' => 0x01],
565
            'offset' => ['pack' => 'V'],
566
            'type' => ['pack' => 'V', 'data' => 0x02], // 2 byte signed integer
567
            'data' => ['data' => 1252],
568
        ];
569 38
        ++$dataSection_NumProps;
570
571
        // GKPIDDSI_CATEGORY : Category
572 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...
573 31
            $dataProp = $this->spreadsheet->getProperties()->getCategory();
574 31
            $dataSection[] = [
575 31
                'summary' => ['pack' => 'V', 'data' => 0x02],
576
                'offset' => ['pack' => 'V'],
577
                'type' => ['pack' => 'V', 'data' => 0x1E],
578 31
                'data' => ['data' => $dataProp, 'length' => strlen($dataProp)],
579
            ];
580 31
            ++$dataSection_NumProps;
581
        }
582
        // GKPIDDSI_VERSION :Version of the application that wrote the property storage
583 38
        $dataSection[] = [
584
            'summary' => ['pack' => 'V', 'data' => 0x17],
585
            'offset' => ['pack' => 'V'],
586
            'type' => ['pack' => 'V', 'data' => 0x03],
587
            'data' => ['pack' => 'V', 'data' => 0x000C0000],
588
        ];
589 38
        ++$dataSection_NumProps;
590
        // GKPIDDSI_SCALE : FALSE
591 38
        $dataSection[] = [
592
            'summary' => ['pack' => 'V', 'data' => 0x0B],
593
            'offset' => ['pack' => 'V'],
594
            'type' => ['pack' => 'V', 'data' => 0x0B],
595
            'data' => ['data' => false],
596
        ];
597 38
        ++$dataSection_NumProps;
598
        // GKPIDDSI_LINKSDIRTY : True if any of the values for the linked properties have changed outside of the application
599 38
        $dataSection[] = [
600
            'summary' => ['pack' => 'V', 'data' => 0x10],
601
            'offset' => ['pack' => 'V'],
602
            'type' => ['pack' => 'V', 'data' => 0x0B],
603
            'data' => ['data' => false],
604
        ];
605 38
        ++$dataSection_NumProps;
606
        // GKPIDDSI_SHAREDOC : FALSE
607 38
        $dataSection[] = [
608
            'summary' => ['pack' => 'V', 'data' => 0x13],
609
            'offset' => ['pack' => 'V'],
610
            'type' => ['pack' => 'V', 'data' => 0x0B],
611
            'data' => ['data' => false],
612
        ];
613 38
        ++$dataSection_NumProps;
614
        // GKPIDDSI_HYPERLINKSCHANGED : True if any of the values for the _PID_LINKS (hyperlink text) have changed outside of the application
615 38
        $dataSection[] = [
616
            'summary' => ['pack' => 'V', 'data' => 0x16],
617
            'offset' => ['pack' => 'V'],
618
            'type' => ['pack' => 'V', 'data' => 0x0B],
619
            'data' => ['data' => false],
620
        ];
621 38
        ++$dataSection_NumProps;
622
623
        // GKPIDDSI_DOCSPARTS
624
        // 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...
625
        // 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...
626
        // cElements
627 38
        $dataProp = pack('v', 0x0001);
628 38
        $dataProp .= pack('v', 0x0000);
629
        // array of UnalignedLpstr
630
        // cch
631 38
        $dataProp .= pack('v', 0x000A);
632 38
        $dataProp .= pack('v', 0x0000);
633
        // value
634 38
        $dataProp .= 'Worksheet' . chr(0);
635
636 38
        $dataSection[] = [
637 38
            'summary' => ['pack' => 'V', 'data' => 0x0D],
638
            'offset' => ['pack' => 'V'],
639
            'type' => ['pack' => 'V', 'data' => 0x101E],
640 38
            'data' => ['data' => $dataProp, 'length' => strlen($dataProp)],
641
        ];
642 38
        ++$dataSection_NumProps;
643
644
        // GKPIDDSI_HEADINGPAIR
645
        // VtVecHeadingPairValue
646
        // cElements
647 38
        $dataProp = pack('v', 0x0002);
648 38
        $dataProp .= pack('v', 0x0000);
649
        // Array of vtHeadingPair
650
        // vtUnalignedString - headingString
651
        // stringType
652 38
        $dataProp .= pack('v', 0x001E);
653
        // padding
654 38
        $dataProp .= pack('v', 0x0000);
655
        // UnalignedLpstr
656
        // cch
657 38
        $dataProp .= pack('v', 0x0013);
658 38
        $dataProp .= pack('v', 0x0000);
659
        // value
660 38
        $dataProp .= 'Feuilles de calcul';
661
        // vtUnalignedString - headingParts
662
        // wType : 0x0003 = 32 bit signed integer
663 38
        $dataProp .= pack('v', 0x0300);
664
        // padding
665 38
        $dataProp .= pack('v', 0x0000);
666
        // value
667 38
        $dataProp .= pack('v', 0x0100);
668 38
        $dataProp .= pack('v', 0x0000);
669 38
        $dataProp .= pack('v', 0x0000);
670 38
        $dataProp .= pack('v', 0x0000);
671
672 38
        $dataSection[] = [
673 38
            'summary' => ['pack' => 'V', 'data' => 0x0C],
674
            'offset' => ['pack' => 'V'],
675
            'type' => ['pack' => 'V', 'data' => 0x100C],
676 38
            'data' => ['data' => $dataProp, 'length' => strlen($dataProp)],
677
        ];
678 38
        ++$dataSection_NumProps;
679
680
        //         4     Section Length
681
        //        4     Property count
682
        //        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...
683 38
        $dataSection_Content_Offset = 8 + $dataSection_NumProps * 8;
684 38
        foreach ($dataSection as $dataProp) {
685
            // Summary
686 38
            $dataSection_Summary .= pack($dataProp['summary']['pack'], $dataProp['summary']['data']);
687
            // Offset
688 38
            $dataSection_Summary .= pack($dataProp['offset']['pack'], $dataSection_Content_Offset);
689
            // DataType
690 38
            $dataSection_Content .= pack($dataProp['type']['pack'], $dataProp['type']['data']);
691
            // Data
692 38
            if ($dataProp['type']['data'] == 0x02) { // 2 byte signed integer
693 38
                $dataSection_Content .= pack('V', $dataProp['data']['data']);
694
695 38
                $dataSection_Content_Offset += 4 + 4;
696 38
            } elseif ($dataProp['type']['data'] == 0x03) { // 4 byte signed integer
697 38
                $dataSection_Content .= pack('V', $dataProp['data']['data']);
698
699 38
                $dataSection_Content_Offset += 4 + 4;
700 38
            } elseif ($dataProp['type']['data'] == 0x0B) { // Boolean
701 38
                if ($dataProp['data']['data'] == false) {
702 38
                    $dataSection_Content .= pack('V', 0x0000);
703
                } else {
704
                    $dataSection_Content .= pack('V', 0x0001);
705
                }
706 38
                $dataSection_Content_Offset += 4 + 4;
707 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...
708
                // Null-terminated string
709 31
                $dataProp['data']['data'] .= chr(0);
710 31
                $dataProp['data']['length'] += 1;
711
                // Complete the string with null string for being a %4
712 31
                $dataProp['data']['length'] = $dataProp['data']['length'] + ((4 - $dataProp['data']['length'] % 4) == 4 ? 0 : (4 - $dataProp['data']['length'] % 4));
713 31
                $dataProp['data']['data'] = str_pad($dataProp['data']['data'], $dataProp['data']['length'], chr(0), STR_PAD_RIGHT);
714
715 31
                $dataSection_Content .= pack('V', $dataProp['data']['length']);
716 31
                $dataSection_Content .= $dataProp['data']['data'];
717
718 31
                $dataSection_Content_Offset += 4 + 4 + strlen($dataProp['data']['data']);
719 38
            } elseif ($dataProp['type']['data'] == 0x40) { // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
720
                $dataSection_Content .= $dataProp['data']['data'];
721
722
                $dataSection_Content_Offset += 4 + 8;
723
            } else {
724
                // Data Type Not Used at the moment
725 38
                $dataSection_Content .= $dataProp['data']['data'];
726
727 38
                $dataSection_Content_Offset += 4 + $dataProp['data']['length'];
728
            }
729
        }
730
        // Now $dataSection_Content_Offset contains the size of the content
731
732
        // section header
733
        // offset: $secOffset; size: 4; section length
734
        //         + x  Size of the content (summary + content)
735 38
        $data .= pack('V', $dataSection_Content_Offset);
736
        // offset: $secOffset+4; size: 4; property count
737 38
        $data .= pack('V', $dataSection_NumProps);
738
        // Section Summary
739 38
        $data .= $dataSection_Summary;
740
        // Section Content
741 38
        $data .= $dataSection_Content;
742
743 38
        return $data;
744
    }
745
746
    /**
747
     * Build the OLE Part for Summary Information
748
     * @return string
749
     */
750 38
    private function writeSummaryInformation()
751
    {
752
        // offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark)
753 38
        $data = pack('v', 0xFFFE);
754
        // 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...
755 38
        $data .= pack('v', 0x0000);
756
        // offset: 4; size: 2; OS version
757 38
        $data .= pack('v', 0x0106);
758
        // offset: 6; size: 2; OS indicator
759 38
        $data .= pack('v', 0x0002);
760
        // offset: 8; size: 16
761 38
        $data .= pack('VVVV', 0x00, 0x00, 0x00, 0x00);
762
        // offset: 24; size: 4; section count
763 38
        $data .= pack('V', 0x0001);
764
765
        // 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
766 38
        $data .= pack('vvvvvvvv', 0x85E0, 0xF29F, 0x4FF9, 0x1068, 0x91AB, 0x0008, 0x272B, 0xD9B3);
767
        // offset: 44; size: 4; offset of the start
768 38
        $data .= pack('V', 0x30);
769
770
        // SECTION
771 38
        $dataSection = [];
772 38
        $dataSection_NumProps = 0;
773 38
        $dataSection_Summary = '';
774 38
        $dataSection_Content = '';
775
776
        // CodePage : CP-1252
777 38
        $dataSection[] = [
778
            'summary' => ['pack' => 'V', 'data' => 0x01],
779
            'offset' => ['pack' => 'V'],
780
            'type' => ['pack' => 'V', 'data' => 0x02], // 2 byte signed integer
781
            'data' => ['data' => 1252],
782
        ];
783 38
        ++$dataSection_NumProps;
784
785
        //    Title
786 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...
787 37
            $dataProp = $this->spreadsheet->getProperties()->getTitle();
788 37
            $dataSection[] = [
789 37
                'summary' => ['pack' => 'V', 'data' => 0x02],
790
                'offset' => ['pack' => 'V'],
791
                'type' => ['pack' => 'V', 'data' => 0x1E], // null-terminated string prepended by dword string length
792 37
                'data' => ['data' => $dataProp, 'length' => strlen($dataProp)],
793
            ];
794 37
            ++$dataSection_NumProps;
795
        }
796
        //    Subject
797 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...
798 32
            $dataProp = $this->spreadsheet->getProperties()->getSubject();
799 32
            $dataSection[] = [
800 32
                'summary' => ['pack' => 'V', 'data' => 0x03],
801
                'offset' => ['pack' => 'V'],
802
                'type' => ['pack' => 'V', 'data' => 0x1E], // null-terminated string prepended by dword string length
803 32
                'data' => ['data' => $dataProp, 'length' => strlen($dataProp)],
804
            ];
805 32
            ++$dataSection_NumProps;
806
        }
807
        //    Author (Creator)
808 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...
809 38
            $dataProp = $this->spreadsheet->getProperties()->getCreator();
810 38
            $dataSection[] = [
811 38
                'summary' => ['pack' => 'V', 'data' => 0x04],
812
                'offset' => ['pack' => 'V'],
813
                'type' => ['pack' => 'V', 'data' => 0x1E], // null-terminated string prepended by dword string length
814 38
                'data' => ['data' => $dataProp, 'length' => strlen($dataProp)],
815
            ];
816 38
            ++$dataSection_NumProps;
817
        }
818
        //    Keywords
819 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...
820 32
            $dataProp = $this->spreadsheet->getProperties()->getKeywords();
821 32
            $dataSection[] = [
822 32
                'summary' => ['pack' => 'V', 'data' => 0x05],
823
                'offset' => ['pack' => 'V'],
824
                'type' => ['pack' => 'V', 'data' => 0x1E], // null-terminated string prepended by dword string length
825 32
                'data' => ['data' => $dataProp, 'length' => strlen($dataProp)],
826
            ];
827 32
            ++$dataSection_NumProps;
828
        }
829
        //    Comments (Description)
830 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...
831 31
            $dataProp = $this->spreadsheet->getProperties()->getDescription();
832 31
            $dataSection[] = [
833 31
                'summary' => ['pack' => 'V', 'data' => 0x06],
834
                'offset' => ['pack' => 'V'],
835
                'type' => ['pack' => 'V', 'data' => 0x1E], // null-terminated string prepended by dword string length
836 31
                'data' => ['data' => $dataProp, 'length' => strlen($dataProp)],
837
            ];
838 31
            ++$dataSection_NumProps;
839
        }
840
        //    Last Saved By (LastModifiedBy)
841 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...
842 38
            $dataProp = $this->spreadsheet->getProperties()->getLastModifiedBy();
843 38
            $dataSection[] = [
844 38
                'summary' => ['pack' => 'V', 'data' => 0x08],
845
                'offset' => ['pack' => 'V'],
846
                'type' => ['pack' => 'V', 'data' => 0x1E], // null-terminated string prepended by dword string length
847 38
                'data' => ['data' => $dataProp, 'length' => strlen($dataProp)],
848
            ];
849 38
            ++$dataSection_NumProps;
850
        }
851
        //    Created Date/Time
852 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...
853 38
            $dataProp = $this->spreadsheet->getProperties()->getCreated();
854 38
            $dataSection[] = [
855 38
                'summary' => ['pack' => 'V', 'data' => 0x0C],
856
                'offset' => ['pack' => 'V'],
857
                'type' => ['pack' => 'V', 'data' => 0x40], // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
858 38
                'data' => ['data' => \PhpOffice\PhpSpreadsheet\Shared\OLE::localDateToOLE($dataProp)],
859
            ];
860 38
            ++$dataSection_NumProps;
861
        }
862
        //    Modified Date/Time
863 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...
864 38
            $dataProp = $this->spreadsheet->getProperties()->getModified();
865 38
            $dataSection[] = [
866 38
                'summary' => ['pack' => 'V', 'data' => 0x0D],
867
                'offset' => ['pack' => 'V'],
868
                'type' => ['pack' => 'V', 'data' => 0x40], // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
869 38
                'data' => ['data' => \PhpOffice\PhpSpreadsheet\Shared\OLE::localDateToOLE($dataProp)],
870
            ];
871 38
            ++$dataSection_NumProps;
872
        }
873
        //    Security
874 38
        $dataSection[] = [
875
            'summary' => ['pack' => 'V', 'data' => 0x13],
876
            'offset' => ['pack' => 'V'],
877
            'type' => ['pack' => 'V', 'data' => 0x03], // 4 byte signed integer
878
            'data' => ['data' => 0x00],
879
        ];
880 38
        ++$dataSection_NumProps;
881
882
        //         4     Section Length
883
        //        4     Property count
884
        //        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...
885 38
        $dataSection_Content_Offset = 8 + $dataSection_NumProps * 8;
886 38
        foreach ($dataSection as $dataProp) {
887
            // Summary
888 38
            $dataSection_Summary .= pack($dataProp['summary']['pack'], $dataProp['summary']['data']);
889
            // Offset
890 38
            $dataSection_Summary .= pack($dataProp['offset']['pack'], $dataSection_Content_Offset);
891
            // DataType
892 38
            $dataSection_Content .= pack($dataProp['type']['pack'], $dataProp['type']['data']);
893
            // Data
894 38
            if ($dataProp['type']['data'] == 0x02) { // 2 byte signed integer
895 38
                $dataSection_Content .= pack('V', $dataProp['data']['data']);
896
897 38
                $dataSection_Content_Offset += 4 + 4;
898 38
            } elseif ($dataProp['type']['data'] == 0x03) { // 4 byte signed integer
899 38
                $dataSection_Content .= pack('V', $dataProp['data']['data']);
900
901 38
                $dataSection_Content_Offset += 4 + 4;
902 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...
903
                // Null-terminated string
904 38
                $dataProp['data']['data'] .= chr(0);
905 38
                $dataProp['data']['length'] += 1;
906
                // Complete the string with null string for being a %4
907 38
                $dataProp['data']['length'] = $dataProp['data']['length'] + ((4 - $dataProp['data']['length'] % 4) == 4 ? 0 : (4 - $dataProp['data']['length'] % 4));
908 38
                $dataProp['data']['data'] = str_pad($dataProp['data']['data'], $dataProp['data']['length'], chr(0), STR_PAD_RIGHT);
909
910 38
                $dataSection_Content .= pack('V', $dataProp['data']['length']);
911 38
                $dataSection_Content .= $dataProp['data']['data'];
912
913 38
                $dataSection_Content_Offset += 4 + 4 + strlen($dataProp['data']['data']);
914 38
            } elseif ($dataProp['type']['data'] == 0x40) { // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
915 38
                $dataSection_Content .= $dataProp['data']['data'];
916
917 38
                $dataSection_Content_Offset += 4 + 8;
918 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...
919
                // Data Type Not Used at the moment
920
            }
921
        }
922
        // Now $dataSection_Content_Offset contains the size of the content
923
924
        // section header
925
        // offset: $secOffset; size: 4; section length
926
        //         + x  Size of the content (summary + content)
927 38
        $data .= pack('V', $dataSection_Content_Offset);
928
        // offset: $secOffset+4; size: 4; property count
929 38
        $data .= pack('V', $dataSection_NumProps);
930
        // Section Summary
931 38
        $data .= $dataSection_Summary;
932
        // Section Content
933 38
        $data .= $dataSection_Content;
934
935 38
        return $data;
936
    }
937
}
938