Completed
Push — develop ( 467115...a39d71 )
by Adrien
17:43
created

Worksheet   F

Complexity

Total Complexity 680

Size/Duplication

Total Lines 4195
Duplicated Lines 24.93 %

Coupling/Cohesion

Components 2
Dependencies 33

Test Coverage

Coverage 60.59%

Importance

Changes 0
Metric Value
dl 1046
loc 4195
ccs 1316
cts 2172
cp 0.6059
rs 0.5217
c 0
b 0
f 0
wmc 680
lcom 2
cbo 33

69 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 48 3
F close() 0 247 36
A writeBIFF8CellRangeAddressFixed() 0 19 2
A getData() 0 14 2
A printRowColHeaders() 0 4 1
A setOutline() 0 12 2
A writeNumber() 0 16 2
A writeString() 0 4 1
A writeRichTextString() 16 16 2
A writeLabel() 0 21 2
A writeLabelSst() 17 17 2
A writeNote() 0 22 2
A writeBlank() 10 11 1
A writeBoolErr() 10 11 1
C writeFormula() 0 76 11
A writeStringRecord() 10 10 1
A writeUrl() 0 5 1
A writeUrlRange() 0 12 3
B writeUrlWeb() 0 31 1
B writeUrlInternal() 0 35 1
B writeUrlExternal() 0 84 4
B writeRow() 0 45 6
A writeDimensions() 0 10 1
C writeWindow2() 0 49 7
A writeDefaultRowHeight() 0 18 2
A writeDefcol() 0 11 1
C writeColinfo() 0 43 7
B writeSelection() 0 57 6
B writeMergedCells() 0 50 5
A writeSheetLayout() 0 23 2
B writeSheetProtection() 0 40 1
B writeRangeProtection() 0 41 3
A writeExterncount() 9 9 1
A writeExternsheet() 0 22 2
F writePanes() 0 75 21
A writeSetup() 0 57 4
A writeHeader() 20 20 1
A writeFooter() 20 20 1
A writeHcenter() 12 12 2
A writeVcenter() 11 11 2
A writeMarginLeft() 15 15 2
A writeMarginRight() 15 15 2
A writeMarginTop() 15 15 2
A writeMarginBottom() 15 15 2
A writePrintHeaders() 11 11 1
A writePrintGridlines() 11 11 2
A writeGridset() 0 11 1
A writeAutoFilterInfo() 0 12 1
B writeGuts() 0 39 5
B writeWsbool() 0 31 6
C writeBreaks() 0 77 11
A writeProtect() 17 17 2
A writeScenProtect() 20 20 3
A writeObjectProtect() 20 20 3
A writePassword() 0 17 3
A insertBitmap() 0 22 2
C positionImage() 0 53 9
A writeObjPicture() 0 64 1
B processBitmapGd() 0 21 5
C processBitmap() 0 76 9
A writeZoom() 14 14 2
A getEscher() 0 4 1
A setEscher() 0 4 1
F writeDataValidity() 63 187 32
B mapErrorCode() 0 21 8
B writePageLayoutView() 0 27 2
F writeCFRule() 695 1172 387
C writeCFHeader() 0 47 15
B writeMsoDrawing() 0 81 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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

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

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

1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Writer\Xls;
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
 *
24
 * @copyright  Copyright (c) 2006 - 2015 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
25
 * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
26
 */
27
28
// Original file header of PEAR::Spreadsheet_Excel_Writer_Worksheet (used as the base for this class):
29
// -----------------------------------------------------------------------------------------
30
// /*
31
// *  Module written/ported by Xavier Noguer <[email protected]>
32
// *
33
// *  The majority of this is _NOT_ my code.  I simply ported it from the
34
// *  PERL Spreadsheet::WriteExcel module.
35
// *
36
// *  The author of the Spreadsheet::WriteExcel module is John McNamara
37
// *  <[email protected]>
38
// *
39
// *  I _DO_ maintain this code, and John McNamara has nothing to do with the
40
// *  porting of this code to PHP.  Any questions directly related to this
41
// *  class library should be directed to me.
42
// *
43
// *  License Information:
44
// *
45
// *    Spreadsheet_Excel_Writer:  A library for generating Excel Spreadsheets
46
// *    Copyright (c) 2002-2003 Xavier Noguer [email protected]
47
// *
48
// *    This library is free software; you can redistribute it and/or
49
// *    modify it under the terms of the GNU Lesser General Public
50
// *    License as published by the Free Software Foundation; either
51
// *    version 2.1 of the License, or (at your option) any later version.
52
// *
53
// *    This library is distributed in the hope that it will be useful,
54
// *    but WITHOUT ANY WARRANTY; without even the implied warranty of
55
// *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
56
// *    Lesser General Public License for more details.
57
// *
58
// *    You should have received a copy of the GNU Lesser General Public
59
// *    License along with this library; if not, write to the Free Software
60
// *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
61
// */
62
class Worksheet extends BIFFwriter
63
{
64
    /**
65
     * Formula parser.
66
     *
67
     * @var \PhpOffice\PhpSpreadsheet\Writer\Xls\Parser
68
     */
69
    private $parser;
70
71
    /**
72
     * Maximum number of characters for a string (LABEL record in BIFF5).
73
     *
74
     * @var int
75
     */
76
    private $xlsStringMaxLength;
77
78
    /**
79
     * Array containing format information for columns.
80
     *
81
     * @var array
82
     */
83
    private $columnInfo;
84
85
    /**
86
     * Array containing the selected area for the worksheet.
87
     *
88
     * @var array
89
     */
90
    private $selection;
91
92
    /**
93
     * The active pane for the worksheet.
94
     *
95
     * @var int
96
     */
97
    private $activePane;
98
99
    /**
100
     * Whether to use outline.
101
     *
102
     * @var int
103
     */
104
    private $outlineOn;
105
106
    /**
107
     * Auto outline styles.
108
     *
109
     * @var bool
110
     */
111
    private $outlineStyle;
112
113
    /**
114
     * Whether to have outline summary below.
115
     *
116
     * @var bool
117
     */
118
    private $outlineBelow;
119
120
    /**
121
     * Whether to have outline summary at the right.
122
     *
123
     * @var bool
124
     */
125
    private $outlineRight;
126
127
    /**
128
     * Reference to the total number of strings in the workbook.
129
     *
130
     * @var int
131
     */
132
    private $stringTotal;
133
134
    /**
135
     * Reference to the number of unique strings in the workbook.
136
     *
137
     * @var int
138
     */
139
    private $stringUnique;
140
141
    /**
142
     * Reference to the array containing all the unique strings in the workbook.
143
     *
144
     * @var array
145
     */
146
    private $stringTable;
147
148
    /**
149
     * Color cache.
150
     */
151
    private $colors;
152
153
    /**
154
     * Index of first used row (at least 0).
155
     *
156
     * @var int
157
     */
158
    private $firstRowIndex;
159
160
    /**
161
     * Index of last used row. (no used rows means -1).
162
     *
163
     * @var int
164
     */
165
    private $lastRowIndex;
166
167
    /**
168
     * Index of first used column (at least 0).
169
     *
170
     * @var int
171
     */
172
    private $firstColumnIndex;
173
174
    /**
175
     * Index of last used column (no used columns means -1).
176
     *
177
     * @var int
178
     */
179
    private $lastColumnIndex;
180
181
    /**
182
     * Sheet object.
183
     *
184
     * @var \PhpOffice\PhpSpreadsheet\Worksheet
185
     */
186
    public $phpSheet;
187
188
    /**
189
     * Count cell style Xfs.
190
     *
191
     * @var int
192
     */
193
    private $countCellStyleXfs;
194
195
    /**
196
     * Escher object corresponding to MSODRAWING.
197
     *
198
     * @var \PhpOffice\PhpSpreadsheet\Shared\Escher
199
     */
200
    private $escher;
201
202
    /**
203
     * Array of font hashes associated to FONT records index.
204
     *
205
     * @var array
206
     */
207
    public $fontHashIndex;
208
209
    /**
210
     * @var bool
211
     */
212
    private $preCalculateFormulas;
213
214
    /**
215
     * @var int
216
     */
217
    private $printHeaders;
218
219
    /**
220
     * Constructor.
221
     *
222
     * @param int        &$str_total        Total number of strings
223
     * @param int        &$str_unique    Total number of unique strings
224
     * @param array        &$str_table        String Table
225
     * @param array        &$colors        Colour Table
226
     * @param mixed        $parser            The formula parser created for the Workbook
227
     * @param bool    $preCalculateFormulas    Flag indicating whether formulas should be calculated or just written
228
     * @param string    $phpSheet        The worksheet to write
229
     * @param \PhpOffice\PhpSpreadsheet\Worksheet $phpSheet
230
     */
231 38
    public function __construct(&$str_total, &$str_unique, &$str_table, &$colors, $parser, $preCalculateFormulas, $phpSheet)
232
    {
233
        // It needs to call its parent's constructor explicitly
234 38
        parent::__construct();
235
236 38
        $this->preCalculateFormulas = $preCalculateFormulas;
237 38
        $this->stringTotal = &$str_total;
238 38
        $this->stringUnique = &$str_unique;
239 38
        $this->stringTable = &$str_table;
240 38
        $this->colors = &$colors;
241 38
        $this->parser = $parser;
242
243 38
        $this->phpSheet = $phpSheet;
0 ignored issues
show
Documentation Bug introduced by
It seems like $phpSheet of type string is incompatible with the declared type object<PhpOffice\PhpSpreadsheet\Worksheet> of property $phpSheet.

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...
244
245 38
        $this->xlsStringMaxLength = 255;
246 38
        $this->columnInfo = [];
247 38
        $this->selection = [0, 0, 0, 0];
248 38
        $this->activePane = 3;
249
250 38
        $this->printHeaders = 0;
251
252 38
        $this->outlineStyle = 0;
0 ignored issues
show
Documentation Bug introduced by
The property $outlineStyle was declared of type boolean, but 0 is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
253 38
        $this->outlineBelow = 1;
0 ignored issues
show
Documentation Bug introduced by
The property $outlineBelow was declared of type boolean, but 1 is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
254 38
        $this->outlineRight = 1;
0 ignored issues
show
Documentation Bug introduced by
The property $outlineRight was declared of type boolean, but 1 is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
255 38
        $this->outlineOn = 1;
256
257 38
        $this->fontHashIndex = [];
258
259
        // calculate values for DIMENSIONS record
260 38
        $minR = 1;
0 ignored issues
show
Unused Code introduced by
$minR 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...
261 38
        $minC = 'A';
262
263 38
        $maxR = $this->phpSheet->getHighestRow();
0 ignored issues
show
Bug introduced by
The method getHighestRow cannot be called on $this->phpSheet (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
264 38
        $maxC = $this->phpSheet->getHighestColumn();
0 ignored issues
show
Bug introduced by
The method getHighestColumn cannot be called on $this->phpSheet (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
265
266
        // Determine lowest and highest column and row
267 38
        $this->lastRowIndex = ($maxR > 65535) ? 65535 : $maxR;
268
269 38
        $this->firstColumnIndex = \PhpOffice\PhpSpreadsheet\Cell::columnIndexFromString($minC);
270 38
        $this->lastColumnIndex = \PhpOffice\PhpSpreadsheet\Cell::columnIndexFromString($maxC);
271
272
//        if ($this->firstColumnIndex > 255) $this->firstColumnIndex = 255;
0 ignored issues
show
Unused Code Comprehensibility introduced by
48% 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...
273 38
        if ($this->lastColumnIndex > 255) {
274
            $this->lastColumnIndex = 255;
275
        }
276
277 38
        $this->countCellStyleXfs = count($phpSheet->getParent()->getCellStyleXfCollection());
0 ignored issues
show
Bug introduced by
The method getParent cannot be called on $phpSheet (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
278 38
    }
279
280
    /**
281
     * Add data to the beginning of the workbook (note the reverse order)
282
     * and to the end of the workbook.
283
     *
284
     * @see \PhpOffice\PhpSpreadsheet\Writer\Xls\Workbook::storeWorkbook()
285
     */
286 38
    public function close()
287
    {
288 38
        $phpSheet = $this->phpSheet;
289
290 38
        $num_sheets = $phpSheet->getParent()->getSheetCount();
0 ignored issues
show
Unused Code introduced by
$num_sheets 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...
291
292
        // Write BOF record
293 38
        $this->storeBof(0x0010);
294
295
        // Write PRINTHEADERS
296 38
        $this->writePrintHeaders();
297
298
        // Write PRINTGRIDLINES
299 38
        $this->writePrintGridlines();
300
301
        // Write GRIDSET
302 38
        $this->writeGridset();
303
304
        // Calculate column widths
305 38
        $phpSheet->calculateColumnWidths();
306
307
        // Column dimensions
308 38
        if (($defaultWidth = $phpSheet->getDefaultColumnDimension()->getWidth()) < 0) {
309 38
            $defaultWidth = \PhpOffice\PhpSpreadsheet\Shared\Font::getDefaultColumnWidthByFont($phpSheet->getParent()->getDefaultStyle()->getFont());
310
        }
311
312 38
        $columnDimensions = $phpSheet->getColumnDimensions();
313 38
        $maxCol = $this->lastColumnIndex - 1;
314 38
        for ($i = 0; $i <= $maxCol; ++$i) {
315 38
            $hidden = 0;
316 38
            $level = 0;
317 38
            $xfIndex = 15; // there are 15 cell style Xfs
318
319 38
            $width = $defaultWidth;
320
321 38
            $columnLetter = \PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex($i);
322 38
            if (isset($columnDimensions[$columnLetter])) {
323 19
                $columnDimension = $columnDimensions[$columnLetter];
324 19
                if ($columnDimension->getWidth() >= 0) {
325 19
                    $width = $columnDimension->getWidth();
326
                }
327 19
                $hidden = $columnDimension->getVisible() ? 0 : 1;
328 19
                $level = $columnDimension->getOutlineLevel();
329 19
                $xfIndex = $columnDimension->getXfIndex() + 15; // there are 15 cell style Xfs
330
            }
331
332
            // Components of columnInfo:
333
            // $firstcol first column on the range
334
            // $lastcol  last column on the range
335
            // $width    width to set
336
            // $xfIndex  The optional cell style Xf index to apply to the columns
337
            // $hidden   The optional hidden atribute
338
            // $level    The optional outline level
339 38
            $this->columnInfo[] = [$i, $i, $width, $xfIndex, $hidden, $level];
340
        }
341
342
        // Write GUTS
343 38
        $this->writeGuts();
344
345
        // Write DEFAULTROWHEIGHT
346 38
        $this->writeDefaultRowHeight();
347
        // Write WSBOOL
348 38
        $this->writeWsbool();
349
        // Write horizontal and vertical page breaks
350 38
        $this->writeBreaks();
351
        // Write page header
352 38
        $this->writeHeader();
353
        // Write page footer
354 38
        $this->writeFooter();
355
        // Write page horizontal centering
356 38
        $this->writeHcenter();
357
        // Write page vertical centering
358 38
        $this->writeVcenter();
359
        // Write left margin
360 38
        $this->writeMarginLeft();
361
        // Write right margin
362 38
        $this->writeMarginRight();
363
        // Write top margin
364 38
        $this->writeMarginTop();
365
        // Write bottom margin
366 38
        $this->writeMarginBottom();
367
        // Write page setup
368 38
        $this->writeSetup();
369
        // Write sheet protection
370 38
        $this->writeProtect();
371
        // Write SCENPROTECT
372 38
        $this->writeScenProtect();
373
        // Write OBJECTPROTECT
374 38
        $this->writeObjectProtect();
375
        // Write sheet password
376 38
        $this->writePassword();
377
        // Write DEFCOLWIDTH record
378 38
        $this->writeDefcol();
379
380
        // Write the COLINFO records if they exist
381 38
        if (!empty($this->columnInfo)) {
382 38
            $colcount = count($this->columnInfo);
383 38
            for ($i = 0; $i < $colcount; ++$i) {
384 38
                $this->writeColinfo($this->columnInfo[$i]);
385
            }
386
        }
387 38
        $autoFilterRange = $phpSheet->getAutoFilter()->getRange();
388 38
        if (!empty($autoFilterRange)) {
389
            // Write AUTOFILTERINFO
390 3
            $this->writeAutoFilterInfo();
391
        }
392
393
        // Write sheet dimensions
394 38
        $this->writeDimensions();
395
396
        // Row dimensions
397 38
        foreach ($phpSheet->getRowDimensions() as $rowDimension) {
398 37
            $xfIndex = $rowDimension->getXfIndex() + 15; // there are 15 cellXfs
399 37
            $this->writeRow($rowDimension->getRowIndex() - 1, $rowDimension->getRowHeight(), $xfIndex, ($rowDimension->getVisible() ? '0' : '1'), $rowDimension->getOutlineLevel());
0 ignored issues
show
Documentation introduced by
$rowDimension->getVisible() ? '0' : '1' is of type string, but the function expects a boolean.

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...
400
        }
401
402
        // Write Cells
403 38
        foreach ($phpSheet->getCellCollection() as $cellID) {
404 38
            $cell = $phpSheet->getCell($cellID);
405 38
            $row = $cell->getRow() - 1;
406 38
            $column = \PhpOffice\PhpSpreadsheet\Cell::columnIndexFromString($cell->getColumn()) - 1;
407
408
            // Don't break Excel!
409
//            if ($row + 1 > 65536 or $column + 1 > 256) {
410 38
            if ($row > 65535 || $column > 255) {
411
                break;
412
            }
413
414
            // Write cell value
415 38
            $xfIndex = $cell->getXfIndex() + 15; // there are 15 cell style Xfs
416
417 38
            $cVal = $cell->getValue();
418 38
            if ($cVal instanceof \PhpOffice\PhpSpreadsheet\RichText) {
419 9
                $arrcRun = [];
420 9
                $str_len = \PhpOffice\PhpSpreadsheet\Shared\StringHelper::countCharacters($cVal->getPlainText(), 'UTF-8');
0 ignored issues
show
Unused Code introduced by
$str_len 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...
421 9
                $str_pos = 0;
422 9
                $elements = $cVal->getRichTextElements();
423 9
                foreach ($elements as $element) {
424
                    // FONT Index
425 9
                    if ($element instanceof \PhpOffice\PhpSpreadsheet\RichText\Run) {
426 9
                        $str_fontidx = $this->fontHashIndex[$element->getFont()->getHashCode()];
427
                    } else {
428 8
                        $str_fontidx = 0;
429
                    }
430 9
                    $arrcRun[] = ['strlen' => $str_pos, 'fontidx' => $str_fontidx];
431
                    // Position FROM
432 9
                    $str_pos += \PhpOffice\PhpSpreadsheet\Shared\StringHelper::countCharacters($element->getText(), 'UTF-8');
433
                }
434 9
                $this->writeRichTextString($row, $column, $cVal->getPlainText(), $xfIndex, $arrcRun);
435
            } else {
436 37
                switch ($cell->getDatatype()) {
437 37
                    case \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING:
438 30
                    case \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_NULL:
439 35
                        if ($cVal === '' || $cVal === null) {
440 18
                            $this->writeBlank($row, $column, $xfIndex);
441
                        } else {
442 33
                            $this->writeString($row, $column, $cVal, $xfIndex);
443
                        }
444 35
                        break;
445 26
                    case \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_NUMERIC:
446 23
                        $this->writeNumber($row, $column, $cVal, $xfIndex);
447 23
                        break;
448 18
                    case \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_FORMULA:
449 16
                        $calculatedValue = $this->preCalculateFormulas ?
450 16
                            $cell->getCalculatedValue() : null;
451 16
                        $this->writeFormula($row, $column, $cVal, $xfIndex, $calculatedValue);
452 16
                        break;
453 8
                    case \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_BOOL:
454 8
                        $this->writeBoolErr($row, $column, $cVal, 0, $xfIndex);
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a boolean.

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...
455 8
                        break;
456
                    case \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_ERROR:
457
                        $this->writeBoolErr($row, $column, self::mapErrorCode($cVal), 1, $xfIndex);
0 ignored issues
show
Documentation introduced by
1 is of type integer, but the function expects a boolean.

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...
458 38
                        break;
459
                }
460
            }
461
        }
462
463
        // Append
464 38
        $this->writeMsoDrawing();
465
466
        // Write WINDOW2 record
467 38
        $this->writeWindow2();
468
469
        // Write PLV record
470 38
        $this->writePageLayoutView();
471
472
        // Write ZOOM record
473 38
        $this->writeZoom();
474 38
        if ($phpSheet->getFreezePane()) {
475 3
            $this->writePanes();
476
        }
477
478
        // Write SELECTION record
479 38
        $this->writeSelection();
480
481
        // Write MergedCellsTable Record
482 38
        $this->writeMergedCells();
483
484
        // Hyperlinks
485 38
        foreach ($phpSheet->getHyperLinkCollection() as $coordinate => $hyperlink) {
486 7
            list($column, $row) = \PhpOffice\PhpSpreadsheet\Cell::coordinateFromString($coordinate);
487
488 7
            $url = $hyperlink->getUrl();
489
490 7
            if (strpos($url, 'sheet://') !== false) {
491
                // internal to current workbook
492 6
                $url = str_replace('sheet://', 'internal:', $url);
493 7
            } elseif (preg_match('/^(http:|https:|ftp:|mailto:)/', $url)) {
0 ignored issues
show
Unused Code introduced by
This elseif statement is empty, and could be removed.

This check looks for the bodies of elseif 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 elseif bodies can be removed. If you have an empty elseif but statements in the else branch, consider inverting the condition.

Loading history...
494
                // URL
495
            } else {
496
                // external (local file)
497
                $url = 'external:' . $url;
498
            }
499
500 7
            $this->writeUrl($row - 1, \PhpOffice\PhpSpreadsheet\Cell::columnIndexFromString($column) - 1, $url);
501
        }
502
503 38
        $this->writeDataValidity();
504 38
        $this->writeSheetLayout();
505
506
        // Write SHEETPROTECTION record
507 38
        $this->writeSheetProtection();
508 38
        $this->writeRangeProtection();
509
510 38
        $arrConditionalStyles = $phpSheet->getConditionalStylesCollection();
511 38
        if (!empty($arrConditionalStyles)) {
512 2
            $arrConditional = [];
513
            // @todo CFRule & CFHeader
514
            // Write CFHEADER record
515 2
            $this->writeCFHeader();
516
            // Write ConditionalFormattingTable records
517 2
            foreach ($arrConditionalStyles as $cellCoordinate => $conditionalStyles) {
518 2
                foreach ($conditionalStyles as $conditional) {
519 2
                    if ($conditional->getConditionType() == \PhpOffice\PhpSpreadsheet\Style\Conditional::CONDITION_EXPRESSION
520 2
                        || $conditional->getConditionType() == \PhpOffice\PhpSpreadsheet\Style\Conditional::CONDITION_CELLIS) {
521 2
                        if (!in_array($conditional->getHashCode(), $arrConditional)) {
522 2
                            $arrConditional[] = $conditional->getHashCode();
523
                            // Write CFRULE record
524 2
                            $this->writeCFRule($conditional);
525
                        }
526
                    }
527
                }
528
            }
529
        }
530
531 38
        $this->storeEof();
532 38
    }
533
534
    /**
535
     * Write a cell range address in BIFF8
536
     * always fixed range
537
     * See section 2.5.14 in OpenOffice.org's Documentation of the Microsoft Excel File Format.
538
     *
539
     * @param string $range E.g. 'A1' or 'A1:B6'
540
     *
541
     * @return string Binary data
542
     */
543 7
    private function writeBIFF8CellRangeAddressFixed($range = 'A1')
544
    {
545 7
        $explodes = explode(':', $range);
546
547
        // extract first cell, e.g. 'A1'
548 7
        $firstCell = $explodes[0];
549
550
        // extract last cell, e.g. 'B6'
551 7
        if (count($explodes) == 1) {
552 2
            $lastCell = $firstCell;
553
        } else {
554 5
            $lastCell = $explodes[1];
555
        }
556
557 7
        $firstCellCoordinates = \PhpOffice\PhpSpreadsheet\Cell::coordinateFromString($firstCell); // e.g. array(0, 1)
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...
558 7
        $lastCellCoordinates = \PhpOffice\PhpSpreadsheet\Cell::coordinateFromString($lastCell); // e.g. array(1, 6)
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...
559
560 7
        return pack('vvvv', $firstCellCoordinates[1] - 1, $lastCellCoordinates[1] - 1, \PhpOffice\PhpSpreadsheet\Cell::columnIndexFromString($firstCellCoordinates[0]) - 1, \PhpOffice\PhpSpreadsheet\Cell::columnIndexFromString($lastCellCoordinates[0]) - 1);
561
    }
562
563
    /**
564
     * Retrieves data from memory in one chunk, or from disk in $buffer
565
     * sized chunks.
566
     *
567
     * @return string The data
568
     */
569 38
    public function getData()
570
    {
571 38
        $buffer = 4096;
0 ignored issues
show
Unused Code introduced by
$buffer 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...
572
573
        // Return data stored in memory
574 38
        if (isset($this->_data)) {
575 38
            $tmp = $this->_data;
576 38
            unset($this->_data);
577
578 38
            return $tmp;
579
        }
580
        // No data to return
581
        return false;
582
    }
583
584
    /**
585
     * Set the option to print the row and column headers on the printed page.
586
     *
587
     * @param int $print Whether to print the headers or not. Defaults to 1 (print).
588
     */
589
    public function printRowColHeaders($print = 1)
590
    {
591
        $this->printHeaders = $print;
592
    }
593
594
    /**
595
     * This method sets the properties for outlining and grouping. The defaults
596
     * correspond to Excel's defaults.
597
     *
598
     * @param bool $visible
599
     * @param bool $symbols_below
600
     * @param bool $symbols_right
601
     * @param bool $auto_style
602
     */
603
    public function setOutline($visible = true, $symbols_below = true, $symbols_right = true, $auto_style = false)
604
    {
605
        $this->outlineOn = $visible;
0 ignored issues
show
Documentation Bug introduced by
The property $outlineOn was declared of type integer, but $visible is of type boolean. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
606
        $this->outlineBelow = $symbols_below;
607
        $this->outlineRight = $symbols_right;
608
        $this->outlineStyle = $auto_style;
609
610
        // Ensure this is a boolean vale for Window2
611
        if ($this->outlineOn) {
612
            $this->outlineOn = 1;
613
        }
614
    }
615
616
    /**
617
     * Write a double to the specified row and column (zero indexed).
618
     * An integer can be written as a double. Excel will display an
619
     * integer. $format is optional.
620
     *
621
     * Returns  0 : normal termination
622
     *         -2 : row or column out of range
623
     *
624
     * @param int $row    Zero indexed row
625
     * @param int $col    Zero indexed column
626
     * @param float   $num    The number to write
627
     * @param mixed   $xfIndex The optional XF format
628
     *
629
     * @return int
630
     */
631 23
    private function writeNumber($row, $col, $num, $xfIndex)
632
    {
633 23
        $record = 0x0203; // Record identifier
634 23
        $length = 0x000E; // Number of bytes to follow
635
636 23
        $header = pack('vv', $record, $length);
637 23
        $data = pack('vvv', $row, $col, $xfIndex);
638 23
        $xl_double = pack('d', $num);
639 23
        if (self::getByteOrder()) { // if it's Big Endian
640
            $xl_double = strrev($xl_double);
641
        }
642
643 23
        $this->append($header . $data . $xl_double);
644
645 23
        return 0;
646
    }
647
648
    /**
649
     * Write a LABELSST record or a LABEL record. Which one depends on BIFF version.
650
     *
651
     * @param int $row Row index (0-based)
652
     * @param int $col Column index (0-based)
653
     * @param string $str The string
654
     * @param int $xfIndex Index to XF record
655
     */
656 33
    private function writeString($row, $col, $str, $xfIndex)
657
    {
658 33
        $this->writeLabelSst($row, $col, $str, $xfIndex);
659 33
    }
660
661
    /**
662
     * Write a LABELSST record or a LABEL record. Which one depends on BIFF version
663
     * It differs from writeString by the writing of rich text strings.
664
     *
665
     * @param int $row Row index (0-based)
666
     * @param int $col Column index (0-based)
667
     * @param string $str The string
668
     * @param int   $xfIndex The XF format index for the cell
669
     * @param array $arrcRun Index to Font record and characters beginning
670
     */
671 9 View Code Duplication
    private function writeRichTextString($row, $col, $str, $xfIndex, $arrcRun)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
672
    {
673 9
        $record = 0x00FD; // Record identifier
674 9
        $length = 0x000A; // Bytes to follow
675 9
        $str = \PhpOffice\PhpSpreadsheet\Shared\StringHelper::UTF8toBIFF8UnicodeShort($str, $arrcRun);
676
677
        /* check if string is already present */
678 9
        if (!isset($this->stringTable[$str])) {
679 9
            $this->stringTable[$str] = $this->stringUnique++;
680
        }
681 9
        ++$this->stringTotal;
682
683 9
        $header = pack('vv', $record, $length);
684 9
        $data = pack('vvvV', $row, $col, $xfIndex, $this->stringTable[$str]);
685 9
        $this->append($header . $data);
686 9
    }
687
688
    /**
689
     * Write a string to the specified row and column (zero indexed).
690
     * NOTE: there is an Excel 5 defined limit of 255 characters.
691
     * $format is optional.
692
     * Returns  0 : normal termination
693
     *         -2 : row or column out of range
694
     *         -3 : long string truncated to 255 chars.
695
     *
696
     * @param int $row    Zero indexed row
697
     * @param int $col    Zero indexed column
698
     * @param string  $str    The string to write
699
     * @param mixed   $xfIndex The XF format index for the cell
700
     *
701
     * @return int
702
     */
703
    private function writeLabel($row, $col, $str, $xfIndex)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
704
    {
705
        $strlen = strlen($str);
706
        $record = 0x0204; // Record identifier
707
        $length = 0x0008 + $strlen; // Bytes to follow
708
709
        $str_error = 0;
710
711
        if ($strlen > $this->xlsStringMaxLength) { // LABEL must be < 255 chars
712
            $str = substr($str, 0, $this->xlsStringMaxLength);
713
            $length = 0x0008 + $this->xlsStringMaxLength;
714
            $strlen = $this->xlsStringMaxLength;
715
            $str_error = -3;
716
        }
717
718
        $header = pack('vv', $record, $length);
719
        $data = pack('vvvv', $row, $col, $xfIndex, $strlen);
720
        $this->append($header . $data . $str);
721
722
        return $str_error;
723
    }
724
725
    /**
726
     * Write a string to the specified row and column (zero indexed).
727
     * This is the BIFF8 version (no 255 chars limit).
728
     * $format is optional.
729
     * Returns  0 : normal termination
730
     *         -2 : row or column out of range
731
     *         -3 : long string truncated to 255 chars.
732
     *
733
     * @param int $row    Zero indexed row
734
     * @param int $col    Zero indexed column
735
     * @param string  $str    The string to write
736
     * @param mixed   $xfIndex The XF format index for the cell
737
     *
738
     * @return int
739
     */
740 33 View Code Duplication
    private function writeLabelSst($row, $col, $str, $xfIndex)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
741
    {
742 33
        $record = 0x00FD; // Record identifier
743 33
        $length = 0x000A; // Bytes to follow
744
745 33
        $str = \PhpOffice\PhpSpreadsheet\Shared\StringHelper::UTF8toBIFF8UnicodeLong($str);
746
747
        /* check if string is already present */
748 33
        if (!isset($this->stringTable[$str])) {
749 33
            $this->stringTable[$str] = $this->stringUnique++;
750
        }
751 33
        ++$this->stringTotal;
752
753 33
        $header = pack('vv', $record, $length);
754 33
        $data = pack('vvvV', $row, $col, $xfIndex, $this->stringTable[$str]);
755 33
        $this->append($header . $data);
756 33
    }
757
758
    /**
759
     * Writes a note associated with the cell given by the row and column.
760
     * NOTE records don't have a length limit.
761
     *
762
     * @param int $row    Zero indexed row
763
     * @param int $col    Zero indexed column
764
     * @param string  $note   The note to write
765
     */
766
    private function writeNote($row, $col, $note)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
767
    {
768
        $note_length = strlen($note);
769
        $record = 0x001C; // Record identifier
770
        $max_length = 2048; // Maximun length for a NOTE record
771
772
        // Length for this record is no more than 2048 + 6
773
        $length = 0x0006 + min($note_length, 2048);
774
        $header = pack('vv', $record, $length);
775
        $data = pack('vvv', $row, $col, $note_length);
776
        $this->append($header . $data . substr($note, 0, 2048));
777
778
        for ($i = $max_length; $i < $note_length; $i += $max_length) {
779
            $chunk = substr($note, $i, $max_length);
780
            $length = 0x0006 + strlen($chunk);
781
            $header = pack('vv', $record, $length);
782
            $data = pack('vvv', -1, 0, strlen($chunk));
783
            $this->append($header . $data . $chunk);
784
        }
785
786
        return 0;
787
    }
788
789
    /**
790
     * Write a blank cell to the specified row and column (zero indexed).
791
     * A blank cell is used to specify formatting without adding a string
792
     * or a number.
793
     *
794
     * A blank cell without a format serves no purpose. Therefore, we don't write
795
     * a BLANK record unless a format is specified.
796
     *
797
     * Returns  0 : normal termination (including no format)
798
     *         -1 : insufficient number of arguments
799
     *         -2 : row or column out of range
800
     *
801
     * @param int $row    Zero indexed row
802
     * @param int $col    Zero indexed column
803
     * @param mixed   $xfIndex The XF format index
804
     */
805 18 View Code Duplication
    public function writeBlank($row, $col, $xfIndex)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
806
    {
807 18
        $record = 0x0201; // Record identifier
808 18
        $length = 0x0006; // Number of bytes to follow
809
810 18
        $header = pack('vv', $record, $length);
811 18
        $data = pack('vvv', $row, $col, $xfIndex);
812 18
        $this->append($header . $data);
813
814 18
        return 0;
815
    }
816
817
    /**
818
     * Write a boolean or an error type to the specified row and column (zero indexed).
819
     *
820
     * @param int $row Row index (0-based)
821
     * @param int $col Column index (0-based)
822
     * @param int $value
823
     * @param bool $isError Error or Boolean?
824
     * @param int $xfIndex
825
     */
826 8 View Code Duplication
    private function writeBoolErr($row, $col, $value, $isError, $xfIndex)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
827
    {
828 8
        $record = 0x0205;
829 8
        $length = 8;
830
831 8
        $header = pack('vv', $record, $length);
832 8
        $data = pack('vvvCC', $row, $col, $xfIndex, $value, $isError);
833 8
        $this->append($header . $data);
834
835 8
        return 0;
836
    }
837
838
    /**
839
     * Write a formula to the specified row and column (zero indexed).
840
     * The textual representation of the formula is passed to the parser in
841
     * Parser.php which returns a packed binary string.
842
     *
843
     * Returns  0 : normal termination
844
     *         -1 : formula errors (bad formula)
845
     *         -2 : row or column out of range
846
     *
847
     * @param int $row     Zero indexed row
848
     * @param int $col     Zero indexed column
849
     * @param string  $formula The formula text string
850
     * @param mixed   $xfIndex  The XF format index
851
     * @param mixed   $calculatedValue  Calculated value
852
     *
853
     * @return int
854
     */
855 16
    private function writeFormula($row, $col, $formula, $xfIndex, $calculatedValue)
856
    {
857 16
        $record = 0x0006; // Record identifier
858
859
        // Initialize possible additional value for STRING record that should be written after the FORMULA record?
860 16
        $stringValue = null;
861
862
        // calculated value
863 16
        if (isset($calculatedValue)) {
864
            // Since we can't yet get the data type of the calculated value,
865
            // we use best effort to determine data type
866 16
            if (is_bool($calculatedValue)) {
867
                // Boolean value
868 3
                $num = pack('CCCvCv', 0x01, 0x00, (int) $calculatedValue, 0x00, 0x00, 0xFFFF);
869 16
            } elseif (is_int($calculatedValue) || is_float($calculatedValue)) {
870
                // Numeric value
871 14
                $num = pack('d', $calculatedValue);
872 12
            } elseif (is_string($calculatedValue)) {
873 12
                $errorCodes = \PhpOffice\PhpSpreadsheet\Cell\DataType::getErrorCodes();
874 12
                if (isset($errorCodes[$calculatedValue])) {
875
                    // Error value
876 4
                    $num = pack('CCCvCv', 0x02, 0x00, self::mapErrorCode($calculatedValue), 0x00, 0x00, 0xFFFF);
877 12
                } elseif ($calculatedValue === '') {
878
                    // Empty string (and BIFF8)
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...
879 5
                    $num = pack('CCCvCv', 0x03, 0x00, 0x00, 0x00, 0x00, 0xFFFF);
880
                } else {
881
                    // Non-empty string value (or empty string BIFF5)
882 7
                    $stringValue = $calculatedValue;
883 12
                    $num = pack('CCCvCv', 0x00, 0x00, 0x00, 0x00, 0x00, 0xFFFF);
884
                }
885
            } else {
886
                // We are really not supposed to reach here
887 16
                $num = pack('d', 0x00);
888
            }
889
        } else {
890
            $num = pack('d', 0x00);
891
        }
892
893 16
        $grbit = 0x03; // Option flags
894 16
        $unknown = 0x0000; // Must be zero
895
896
        // Strip the '=' or '@' sign at the beginning of the formula string
897 16
        if ($formula[0] == '=') {
898 16
            $formula = substr($formula, 1);
899
        } else {
900
            // Error handling
901
            $this->writeString($row, $col, 'Unrecognised character for formula');
0 ignored issues
show
Bug introduced by
The call to writeString() misses a required argument $xfIndex.

This check looks for function calls that miss required arguments.

Loading history...
902
903
            return -1;
904
        }
905
906
        // Parse the formula using the parser in Parser.php
907
        try {
908 16
            $error = $this->parser->parse($formula);
0 ignored issues
show
Unused Code introduced by
$error 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...
909 16
            $formula = $this->parser->toReversePolish();
910
911 16
            $formlen = strlen($formula); // Length of the binary string
912 16
            $length = 0x16 + $formlen; // Length of the record data
913
914 16
            $header = pack('vv', $record, $length);
915
916 16
            $data = pack('vvv', $row, $col, $xfIndex)
917 16
                        . $num
918 16
                        . pack('vVv', $grbit, $unknown, $formlen);
919 16
            $this->append($header . $data . $formula);
920
921
            // Append also a STRING record if necessary
922 16
            if ($stringValue !== null) {
923 7
                $this->writeStringRecord($stringValue);
924
            }
925
926 16
            return 0;
927 5
        } catch (\PhpOffice\PhpSpreadsheet\Exception $e) {
928
            // do nothing
929
        }
930 5
    }
931
932
    /**
933
     * Write a STRING record. This.
934
     *
935
     * @param string $stringValue
936
     */
937 7 View Code Duplication
    private function writeStringRecord($stringValue)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
938
    {
939 7
        $record = 0x0207; // Record identifier
940 7
        $data = \PhpOffice\PhpSpreadsheet\Shared\StringHelper::UTF8toBIFF8UnicodeLong($stringValue);
941
942 7
        $length = strlen($data);
943 7
        $header = pack('vv', $record, $length);
944
945 7
        $this->append($header . $data);
946 7
    }
947
948
    /**
949
     * Write a hyperlink.
950
     * This is comprised of two elements: the visible label and
951
     * the invisible link. The visible label is the same as the link unless an
952
     * alternative string is specified. The label is written using the
953
     * writeString() method. Therefore the 255 characters string limit applies.
954
     * $string and $format are optional.
955
     *
956
     * The hyperlink can be to a http, ftp, mail, internal sheet (not yet), or external
957
     * directory url.
958
     *
959
     * Returns  0 : normal termination
960
     *         -2 : row or column out of range
961
     *         -3 : long string truncated to 255 chars
962
     *
963
     * @param int $row    Row
964
     * @param int $col    Column
965
     * @param string  $url    URL string
966
     *
967
     * @return int
968
     */
969 7
    private function writeUrl($row, $col, $url)
970
    {
971
        // Add start row and col to arg list
972 7
        return $this->writeUrlRange($row, $col, $row, $col, $url);
973
    }
974
975
    /**
976
     * This is the more general form of writeUrl(). It allows a hyperlink to be
977
     * written to a range of cells. This function also decides the type of hyperlink
978
     * to be written. These are either, Web (http, ftp, mailto), Internal
979
     * (Sheet1!A1) or external ('c:\temp\foo.xls#Sheet1!A1').
980
     *
981
     * @see writeUrl()
982
     *
983
     * @param int $row1   Start row
984
     * @param int $col1   Start column
985
     * @param int $row2   End row
986
     * @param int $col2   End column
987
     * @param string  $url    URL string
988
     *
989
     * @return int
990
     */
991 7
    public function writeUrlRange($row1, $col1, $row2, $col2, $url)
992
    {
993
        // Check for internal/external sheet links or default to web link
994 7
        if (preg_match('[^internal:]', $url)) {
995 6
            return $this->writeUrlInternal($row1, $col1, $row2, $col2, $url);
996
        }
997 7
        if (preg_match('[^external:]', $url)) {
998
            return $this->writeUrlExternal($row1, $col1, $row2, $col2, $url);
999
        }
1000
1001 7
        return $this->writeUrlWeb($row1, $col1, $row2, $col2, $url);
1002
    }
1003
1004
    /**
1005
     * Used to write http, ftp and mailto hyperlinks.
1006
     * The link type ($options) is 0x03 is the same as absolute dir ref without
1007
     * sheet. However it is differentiated by the $unknown2 data stream.
1008
     *
1009
     * @see writeUrl()
1010
     *
1011
     * @param int $row1   Start row
1012
     * @param int $col1   Start column
1013
     * @param int $row2   End row
1014
     * @param int $col2   End column
1015
     * @param string  $url    URL string
1016
     *
1017
     * @return int
1018
     */
1019 7
    public function writeUrlWeb($row1, $col1, $row2, $col2, $url)
1020
    {
1021 7
        $record = 0x01B8; // Record identifier
1022 7
        $length = 0x00000; // Bytes to follow
0 ignored issues
show
Unused Code introduced by
$length 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...
1023
1024
        // Pack the undocumented parts of the hyperlink stream
1025 7
        $unknown1 = pack('H*', 'D0C9EA79F9BACE118C8200AA004BA90B02000000');
1026 7
        $unknown2 = pack('H*', 'E0C9EA79F9BACE118C8200AA004BA90B');
1027
1028
        // Pack the option flags
1029 7
        $options = pack('V', 0x03);
1030
1031
        // Convert URL to a null terminated wchar string
1032 7
        $url = implode("\0", preg_split("''", $url, -1, PREG_SPLIT_NO_EMPTY));
1033 7
        $url = $url . "\0\0\0";
1034
1035
        // Pack the length of the URL
1036 7
        $url_len = pack('V', strlen($url));
1037
1038
        // Calculate the data length
1039 7
        $length = 0x34 + strlen($url);
1040
1041
        // Pack the header data
1042 7
        $header = pack('vv', $record, $length);
1043 7
        $data = pack('vvvv', $row1, $row2, $col1, $col2);
1044
1045
        // Write the packed data
1046 7
        $this->append($header . $data . $unknown1 . $options . $unknown2 . $url_len . $url);
1047
1048 7
        return 0;
1049
    }
1050
1051
    /**
1052
     * Used to write internal reference hyperlinks such as "Sheet1!A1".
1053
     *
1054
     * @see writeUrl()
1055
     *
1056
     * @param int $row1   Start row
1057
     * @param int $col1   Start column
1058
     * @param int $row2   End row
1059
     * @param int $col2   End column
1060
     * @param string  $url    URL string
1061
     *
1062
     * @return int
1063
     */
1064 6
    public function writeUrlInternal($row1, $col1, $row2, $col2, $url)
1065
    {
1066 6
        $record = 0x01B8; // Record identifier
1067 6
        $length = 0x00000; // Bytes to follow
0 ignored issues
show
Unused Code introduced by
$length 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...
1068
1069
        // Strip URL type
1070 6
        $url = preg_replace('/^internal:/', '', $url);
1071
1072
        // Pack the undocumented parts of the hyperlink stream
1073 6
        $unknown1 = pack('H*', 'D0C9EA79F9BACE118C8200AA004BA90B02000000');
1074
1075
        // Pack the option flags
1076 6
        $options = pack('V', 0x08);
1077
1078
        // Convert the URL type and to a null terminated wchar string
1079 6
        $url .= "\0";
1080
1081
        // character count
1082 6
        $url_len = \PhpOffice\PhpSpreadsheet\Shared\StringHelper::countCharacters($url);
1083 6
        $url_len = pack('V', $url_len);
1084
1085 6
        $url = \PhpOffice\PhpSpreadsheet\Shared\StringHelper::convertEncoding($url, 'UTF-16LE', 'UTF-8');
1086
1087
        // Calculate the data length
1088 6
        $length = 0x24 + strlen($url);
1089
1090
        // Pack the header data
1091 6
        $header = pack('vv', $record, $length);
1092 6
        $data = pack('vvvv', $row1, $row2, $col1, $col2);
1093
1094
        // Write the packed data
1095 6
        $this->append($header . $data . $unknown1 . $options . $url_len . $url);
1096
1097 6
        return 0;
1098
    }
1099
1100
    /**
1101
     * Write links to external directory names such as 'c:\foo.xls',
1102
     * c:\foo.xls#Sheet1!A1', '../../foo.xls'. and '../../foo.xls#Sheet1!A1'.
1103
     *
1104
     * Note: Excel writes some relative links with the $dir_long string. We ignore
1105
     * these cases for the sake of simpler code.
1106
     *
1107
     * @see writeUrl()
1108
     *
1109
     * @param int $row1   Start row
1110
     * @param int $col1   Start column
1111
     * @param int $row2   End row
1112
     * @param int $col2   End column
1113
     * @param string  $url    URL string
1114
     *
1115
     * @return int
1116
     */
1117
    public function writeUrlExternal($row1, $col1, $row2, $col2, $url)
1118
    {
1119
        // Network drives are different. We will handle them separately
1120
        // MS/Novell network drives and shares start with \\
1121
        if (preg_match('[^external:\\\\]', $url)) {
1122
            return; //($this->writeUrlExternal_net($row1, $col1, $row2, $col2, $url, $str, $format));
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% 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...
1123
        }
1124
1125
        $record = 0x01B8; // Record identifier
1126
        $length = 0x00000; // Bytes to follow
0 ignored issues
show
Unused Code introduced by
$length 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...
1127
1128
        // Strip URL type and change Unix dir separator to Dos style (if needed)
1129
        //
1130
        $url = preg_replace('/^external:/', '', $url);
1131
        $url = preg_replace('/\//', '\\', $url);
1132
1133
        // Determine if the link is relative or absolute:
1134
        //   relative if link contains no dir separator, "somefile.xls"
1135
        //   relative if link starts with up-dir, "..\..\somefile.xls"
1136
        //   otherwise, absolute
1137
1138
        $absolute = 0x00; // relative path
1139
        if (preg_match('/^[A-Z]:/', $url)) {
1140
            $absolute = 0x02; // absolute path on Windows, e.g. C:\...
1141
        }
1142
        $link_type = 0x01 | $absolute;
1143
1144
        // Determine if the link contains a sheet reference and change some of the
1145
        // parameters accordingly.
1146
        // Split the dir name and sheet name (if it exists)
1147
        $dir_long = $url;
1148
        if (preg_match("/\#/", $url)) {
1149
            $link_type |= 0x08;
1150
        }
1151
1152
        // Pack the link type
1153
        $link_type = pack('V', $link_type);
1154
1155
        // Calculate the up-level dir count e.g.. (..\..\..\ == 3)
1156
        $up_count = preg_match_all("/\.\.\\\/", $dir_long, $useless);
1157
        $up_count = pack('v', $up_count);
1158
1159
        // Store the short dos dir name (null terminated)
1160
        $dir_short = preg_replace("/\.\.\\\/", '', $dir_long) . "\0";
1161
1162
        // Store the long dir name as a wchar string (non-null terminated)
1163
        $dir_long = $dir_long . "\0";
1164
1165
        // Pack the lengths of the dir strings
1166
        $dir_short_len = pack('V', strlen($dir_short));
1167
        $dir_long_len = pack('V', strlen($dir_long));
0 ignored issues
show
Unused Code introduced by
$dir_long_len 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...
1168
        $stream_len = pack('V', 0); //strlen($dir_long) + 0x06);
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% 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...
1169
1170
        // Pack the undocumented parts of the hyperlink stream
1171
        $unknown1 = pack('H*', 'D0C9EA79F9BACE118C8200AA004BA90B02000000');
1172
        $unknown2 = pack('H*', '0303000000000000C000000000000046');
1173
        $unknown3 = pack('H*', 'FFFFADDE000000000000000000000000000000000000000');
1174
        $unknown4 = pack('v', 0x03);
0 ignored issues
show
Unused Code introduced by
$unknown4 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...
1175
1176
        // Pack the main data stream
1177
        $data = pack('vvvv', $row1, $row2, $col1, $col2) .
1178
                          $unknown1 .
1179
                          $link_type .
1180
                          $unknown2 .
1181
                          $up_count .
1182
                          $dir_short_len .
1183
                          $dir_short .
1184
                          $unknown3 .
1185
                          $stream_len; /*.
1186
                          $dir_long_len .
1187
                          $unknown4     .
1188
                          $dir_long     .
1189
                          $sheet_len    .
1190
                          $sheet        ;*/
1191
1192
        // Pack the header data
1193
        $length = strlen($data);
1194
        $header = pack('vv', $record, $length);
1195
1196
        // Write the packed data
1197
        $this->append($header . $data);
1198
1199
        return 0;
1200
    }
1201
1202
    /**
1203
     * This method is used to set the height and format for a row.
1204
     *
1205
     * @param int $row    The row to set
1206
     * @param int $height Height we are giving to the row.
1207
     *                        Use null to set XF without setting height
1208
     * @param int $xfIndex  The optional cell style Xf index to apply to the columns
1209
     * @param bool    $hidden The optional hidden attribute
1210
     * @param int $level  The optional outline level for row, in range [0,7]
1211
     */
1212 37
    private function writeRow($row, $height, $xfIndex, $hidden = false, $level = 0)
1213
    {
1214 37
        $record = 0x0208; // Record identifier
1215 37
        $length = 0x0010; // Number of bytes to follow
1216
1217 37
        $colMic = 0x0000; // First defined column
1218 37
        $colMac = 0x0000; // Last defined column
1219 37
        $irwMac = 0x0000; // Used by Excel to optimise loading
1220 37
        $reserved = 0x0000; // Reserved
1221 37
        $grbit = 0x0000; // Option flags
1222 37
        $ixfe = $xfIndex;
1223
1224 37
        if ($height < 0) {
1225 36
            $height = null;
1226
        }
1227
1228
        // Use writeRow($row, null, $XF) to set XF format without setting height
1229 37
        if ($height != null) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $height of type null|integer against null; this is ambiguous if the integer can be zero. Consider using a strict comparison !== instead.
Loading history...
1230 6
            $miyRw = $height * 20; // row height
1231
        } else {
1232 36
            $miyRw = 0xff; // default row height is 256
1233
        }
1234
1235
        // Set the options flags. fUnsynced is used to show that the font and row
1236
        // heights are not compatible. This is usually the case for WriteExcel.
1237
        // The collapsed flag 0x10 doesn't seem to be used to indicate that a row
1238
        // is collapsed. Instead it is used to indicate that the previous row is
1239
        // collapsed. The zero height flag, 0x20, is used to collapse a row.
1240
1241 37
        $grbit |= $level;
1242 37
        if ($hidden) {
1243 2
            $grbit |= 0x0030;
1244
        }
1245 37
        if ($height !== null) {
1246 6
            $grbit |= 0x0040; // fUnsynced
1247
        }
1248 37
        if ($xfIndex !== 0xF) {
1249
            $grbit |= 0x0080;
1250
        }
1251 37
        $grbit |= 0x0100;
1252
1253 37
        $header = pack('vv', $record, $length);
1254 37
        $data = pack('vvvvvvvv', $row, $colMic, $colMac, $miyRw, $irwMac, $reserved, $grbit, $ixfe);
1255 37
        $this->append($header . $data);
1256 37
    }
1257
1258
    /**
1259
     * Writes Excel DIMENSIONS to define the area in which there is data.
1260
     */
1261 38
    private function writeDimensions()
1262
    {
1263 38
        $record = 0x0200; // Record identifier
1264
1265 38
        $length = 0x000E;
1266 38
        $data = pack('VVvvv', $this->firstRowIndex, $this->lastRowIndex + 1, $this->firstColumnIndex, $this->lastColumnIndex + 1, 0x0000); // reserved
1267
1268 38
        $header = pack('vv', $record, $length);
1269 38
        $this->append($header . $data);
1270 38
    }
1271
1272
    /**
1273
     * Write BIFF record Window2.
1274
     */
1275 38
    private function writeWindow2()
1276
    {
1277 38
        $record = 0x023E; // Record identifier
1278 38
        $length = 0x0012;
1279
1280 38
        $grbit = 0x00B6; // Option flags
0 ignored issues
show
Unused Code introduced by
$grbit 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...
1281 38
        $rwTop = 0x0000; // Top row visible in window
1282 38
        $colLeft = 0x0000; // Leftmost column visible in window
1283
1284
        // The options flags that comprise $grbit
1285 38
        $fDspFmla = 0; // 0 - bit
1286 38
        $fDspGrid = $this->phpSheet->getShowGridlines() ? 1 : 0; // 1
1287 38
        $fDspRwCol = $this->phpSheet->getShowRowColHeaders() ? 1 : 0; // 2
1288 38
        $fFrozen = $this->phpSheet->getFreezePane() ? 1 : 0; // 3
1289 38
        $fDspZeros = 1; // 4
1290 38
        $fDefaultHdr = 1; // 5
1291 38
        $fArabic = $this->phpSheet->getRightToLeft() ? 1 : 0; // 6
1292 38
        $fDspGuts = $this->outlineOn; // 7
1293 38
        $fFrozenNoSplit = 0; // 0 - bit
1294
        // no support in PhpSpreadsheet for selected sheet, therefore sheet is only selected if it is the active sheet
1295 38
        $fSelected = ($this->phpSheet === $this->phpSheet->getParent()->getActiveSheet()) ? 1 : 0;
1296 38
        $fPaged = 1; // 2
1297 38
        $fPageBreakPreview = $this->phpSheet->getSheetView()->getView() === \PhpOffice\PhpSpreadsheet\Worksheet\SheetView::SHEETVIEW_PAGE_BREAK_PREVIEW;
1298
1299 38
        $grbit = $fDspFmla;
1300 38
        $grbit |= $fDspGrid << 1;
1301 38
        $grbit |= $fDspRwCol << 2;
1302 38
        $grbit |= $fFrozen << 3;
1303 38
        $grbit |= $fDspZeros << 4;
1304 38
        $grbit |= $fDefaultHdr << 5;
1305 38
        $grbit |= $fArabic << 6;
1306 38
        $grbit |= $fDspGuts << 7;
1307 38
        $grbit |= $fFrozenNoSplit << 8;
1308 38
        $grbit |= $fSelected << 9;
1309 38
        $grbit |= $fPaged << 10;
1310 38
        $grbit |= $fPageBreakPreview << 11;
1311
1312 38
        $header = pack('vv', $record, $length);
1313 38
        $data = pack('vvv', $grbit, $rwTop, $colLeft);
1314
1315
        // FIXME !!!
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...
1316 38
        $rgbHdr = 0x0040; // Row/column heading and gridline color index
1317 38
        $zoom_factor_page_break = ($fPageBreakPreview ? $this->phpSheet->getSheetView()->getZoomScale() : 0x0000);
1318 38
        $zoom_factor_normal = $this->phpSheet->getSheetView()->getZoomScaleNormal();
1319
1320 38
        $data .= pack('vvvvV', $rgbHdr, 0x0000, $zoom_factor_page_break, $zoom_factor_normal, 0x00000000);
1321
1322 38
        $this->append($header . $data);
1323 38
    }
1324
1325
    /**
1326
     * Write BIFF record DEFAULTROWHEIGHT.
1327
     */
1328 38
    private function writeDefaultRowHeight()
1329
    {
1330 38
        $defaultRowHeight = $this->phpSheet->getDefaultRowDimension()->getRowHeight();
1331
1332 38
        if ($defaultRowHeight < 0) {
1333 35
            return;
1334
        }
1335
1336
        // convert to twips
1337 3
        $defaultRowHeight = (int) 20 * $defaultRowHeight;
1338
1339 3
        $record = 0x0225; // Record identifier
1340 3
        $length = 0x0004; // Number of bytes to follow
1341
1342 3
        $header = pack('vv', $record, $length);
1343 3
        $data = pack('vv', 1, $defaultRowHeight);
1344 3
        $this->append($header . $data);
1345 3
    }
1346
1347
    /**
1348
     * Write BIFF record DEFCOLWIDTH if COLINFO records are in use.
1349
     */
1350 38
    private function writeDefcol()
1351
    {
1352 38
        $defaultColWidth = 8;
1353
1354 38
        $record = 0x0055; // Record identifier
1355 38
        $length = 0x0002; // Number of bytes to follow
1356
1357 38
        $header = pack('vv', $record, $length);
1358 38
        $data = pack('v', $defaultColWidth);
1359 38
        $this->append($header . $data);
1360 38
    }
1361
1362
    /**
1363
     * Write BIFF record COLINFO to define column widths.
1364
     *
1365
     * Note: The SDK says the record length is 0x0B but Excel writes a 0x0C
1366
     * length record.
1367
     *
1368
     * @param array $col_array This is the only parameter received and is composed of the following:
1369
     *                0 => First formatted column,
1370
     *                1 => Last formatted column,
1371
     *                2 => Col width (8.43 is Excel default),
1372
     *                3 => The optional XF format of the column,
1373
     *                4 => Option flags.
1374
     *                5 => Optional outline level
1375
     */
1376 38
    private function writeColinfo($col_array)
1377
    {
1378 38
        if (isset($col_array[0])) {
1379 38
            $colFirst = $col_array[0];
1380
        }
1381 38
        if (isset($col_array[1])) {
1382 38
            $colLast = $col_array[1];
1383
        }
1384 38
        if (isset($col_array[2])) {
1385 38
            $coldx = $col_array[2];
1386
        } else {
1387
            $coldx = 8.43;
1388
        }
1389 38
        if (isset($col_array[3])) {
1390 38
            $xfIndex = $col_array[3];
1391
        } else {
1392
            $xfIndex = 15;
1393
        }
1394 38
        if (isset($col_array[4])) {
1395 38
            $grbit = $col_array[4];
1396
        } else {
1397
            $grbit = 0;
1398
        }
1399 38
        if (isset($col_array[5])) {
1400 38
            $level = $col_array[5];
1401
        } else {
1402
            $level = 0;
1403
        }
1404 38
        $record = 0x007D; // Record identifier
1405 38
        $length = 0x000C; // Number of bytes to follow
1406
1407 38
        $coldx *= 256; // Convert to units of 1/256 of a char
1408
1409 38
        $ixfe = $xfIndex;
1410 38
        $reserved = 0x0000; // Reserved
1411
1412 38
        $level = max(0, min($level, 7));
1413 38
        $grbit |= $level << 8;
1414
1415 38
        $header = pack('vv', $record, $length);
1416 38
        $data = pack('vvvvvv', $colFirst, $colLast, $coldx, $ixfe, $grbit, $reserved);
0 ignored issues
show
Bug introduced by
The variable $colFirst 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...
Bug introduced by
The variable $colLast 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...
1417 38
        $this->append($header . $data);
1418 38
    }
1419
1420
    /**
1421
     * Write BIFF record SELECTION.
1422
     */
1423 38
    private function writeSelection()
1424
    {
1425
        // look up the selected cell range
1426 38
        $selectedCells = $this->phpSheet->getSelectedCells();
0 ignored issues
show
Unused Code introduced by
$selectedCells 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...
1427 38
        $selectedCells = \PhpOffice\PhpSpreadsheet\Cell::splitRange($this->phpSheet->getSelectedCells());
1428 38
        $selectedCells = $selectedCells[0];
1429 38
        if (count($selectedCells) == 2) {
1430 13
            list($first, $last) = $selectedCells;
1431
        } else {
1432 31
            $first = $selectedCells[0];
1433 31
            $last = $selectedCells[0];
1434
        }
1435
1436 38
        list($colFirst, $rwFirst) = \PhpOffice\PhpSpreadsheet\Cell::coordinateFromString($first);
1437 38
        $colFirst = \PhpOffice\PhpSpreadsheet\Cell::columnIndexFromString($colFirst) - 1; // base 0 column index
1438 38
        --$rwFirst; // base 0 row index
1439
1440 38
        list($colLast, $rwLast) = \PhpOffice\PhpSpreadsheet\Cell::coordinateFromString($last);
1441 38
        $colLast = \PhpOffice\PhpSpreadsheet\Cell::columnIndexFromString($colLast) - 1; // base 0 column index
1442 38
        --$rwLast; // base 0 row index
1443
1444
        // make sure we are not out of bounds
1445 38
        $colFirst = min($colFirst, 255);
1446 38
        $colLast = min($colLast, 255);
1447
1448 38
        $rwFirst = min($rwFirst, 65535);
1449 38
        $rwLast = min($rwLast, 65535);
1450
1451 38
        $record = 0x001D; // Record identifier
1452 38
        $length = 0x000F; // Number of bytes to follow
1453
1454 38
        $pnn = $this->activePane; // Pane position
1455 38
        $rwAct = $rwFirst; // Active row
1456 38
        $colAct = $colFirst; // Active column
1457 38
        $irefAct = 0; // Active cell ref
1458 38
        $cref = 1; // Number of refs
1459
1460 38
        if (!isset($rwLast)) {
1461
            $rwLast = $rwFirst; // Last  row in reference
1462
        }
1463 38
        if (!isset($colLast)) {
1464
            $colLast = $colFirst; // Last  col in reference
1465
        }
1466
1467
        // Swap last row/col for first row/col as necessary
1468 38
        if ($rwFirst > $rwLast) {
1469
            list($rwFirst, $rwLast) = [$rwLast, $rwFirst];
1470
        }
1471
1472 38
        if ($colFirst > $colLast) {
1473
            list($colFirst, $colLast) = [$colLast, $colFirst];
1474
        }
1475
1476 38
        $header = pack('vv', $record, $length);
1477 38
        $data = pack('CvvvvvvCC', $pnn, $rwAct, $colAct, $irefAct, $cref, $rwFirst, $rwLast, $colFirst, $colLast);
1478 38
        $this->append($header . $data);
1479 38
    }
1480
1481
    /**
1482
     * Store the MERGEDCELLS records for all ranges of merged cells.
1483
     */
1484 38
    private function writeMergedCells()
1485
    {
1486 38
        $mergeCells = $this->phpSheet->getMergeCells();
1487 38
        $countMergeCells = count($mergeCells);
1488
1489 38
        if ($countMergeCells == 0) {
1490 37
            return;
1491
        }
1492
1493
        // maximum allowed number of merged cells per record
1494 10
        $maxCountMergeCellsPerRecord = 1027;
1495
1496
        // record identifier
1497 10
        $record = 0x00E5;
1498
1499
        // counter for total number of merged cells treated so far by the writer
1500 10
        $i = 0;
1501
1502
        // counter for number of merged cells written in record currently being written
1503 10
        $j = 0;
1504
1505
        // initialize record data
1506 10
        $recordData = '';
1507
1508
        // loop through the merged cells
1509 10
        foreach ($mergeCells as $mergeCell) {
1510 10
            ++$i;
1511 10
            ++$j;
1512
1513
            // extract the row and column indexes
1514 10
            $range = \PhpOffice\PhpSpreadsheet\Cell::splitRange($mergeCell);
0 ignored issues
show
Documentation introduced by
$mergeCell is of type array, 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...
1515 10
            list($first, $last) = $range[0];
1516 10
            list($firstColumn, $firstRow) = \PhpOffice\PhpSpreadsheet\Cell::coordinateFromString($first);
1517 10
            list($lastColumn, $lastRow) = \PhpOffice\PhpSpreadsheet\Cell::coordinateFromString($last);
1518
1519 10
            $recordData .= pack('vvvv', $firstRow - 1, $lastRow - 1, \PhpOffice\PhpSpreadsheet\Cell::columnIndexFromString($firstColumn) - 1, \PhpOffice\PhpSpreadsheet\Cell::columnIndexFromString($lastColumn) - 1);
1520
1521
            // flush record if we have reached limit for number of merged cells, or reached final merged cell
1522 10
            if ($j == $maxCountMergeCellsPerRecord or $i == $countMergeCells) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1523 10
                $recordData = pack('v', $j) . $recordData;
1524 10
                $length = strlen($recordData);
1525 10
                $header = pack('vv', $record, $length);
1526 10
                $this->append($header . $recordData);
1527
1528
                // initialize for next record, if any
1529 10
                $recordData = '';
1530 10
                $j = 0;
1531
            }
1532
        }
1533 10
    }
1534
1535
    /**
1536
     * Write SHEETLAYOUT record.
1537
     */
1538 38
    private function writeSheetLayout()
1539
    {
1540 38
        if (!$this->phpSheet->isTabColorSet()) {
1541 38
            return;
1542
        }
1543
1544 5
        $recordData = pack(
1545 5
            'vvVVVvv',
1546 5
            0x0862,
1547 5
            0x0000, // unused
1548 5
            0x00000000, // unused
1549 5
            0x00000000, // unused
1550 5
            0x00000014, // size of record data
1551 5
            $this->colors[$this->phpSheet->getTabColor()->getRGB()], // color index
1552 5
            0x0000        // unused
1553
        );
1554
1555 5
        $length = strlen($recordData);
1556
1557 5
        $record = 0x0862; // Record identifier
1558 5
        $header = pack('vv', $record, $length);
1559 5
        $this->append($header . $recordData);
1560 5
    }
1561
1562
    /**
1563
     * Write SHEETPROTECTION.
1564
     */
1565 38
    private function writeSheetProtection()
1566
    {
1567
        // record identifier
1568 38
        $record = 0x0867;
1569
1570
        // prepare options
1571 38
        $options = (int) !$this->phpSheet->getProtection()->getObjects()
1572 38
                    | (int) !$this->phpSheet->getProtection()->getScenarios() << 1
1573 38
                    | (int) !$this->phpSheet->getProtection()->getFormatCells() << 2
1574 38
                    | (int) !$this->phpSheet->getProtection()->getFormatColumns() << 3
1575 38
                    | (int) !$this->phpSheet->getProtection()->getFormatRows() << 4
1576 38
                    | (int) !$this->phpSheet->getProtection()->getInsertColumns() << 5
1577 38
                    | (int) !$this->phpSheet->getProtection()->getInsertRows() << 6
1578 38
                    | (int) !$this->phpSheet->getProtection()->getInsertHyperlinks() << 7
1579 38
                    | (int) !$this->phpSheet->getProtection()->getDeleteColumns() << 8
1580 38
                    | (int) !$this->phpSheet->getProtection()->getDeleteRows() << 9
1581 38
                    | (int) !$this->phpSheet->getProtection()->getSelectLockedCells() << 10
1582 38
                    | (int) !$this->phpSheet->getProtection()->getSort() << 11
1583 38
                    | (int) !$this->phpSheet->getProtection()->getAutoFilter() << 12
1584 38
                    | (int) !$this->phpSheet->getProtection()->getPivotTables() << 13
1585 38
                    | (int) !$this->phpSheet->getProtection()->getSelectUnlockedCells() << 14;
1586
1587
        // record data
1588 38
        $recordData = pack(
1589 38
            'vVVCVVvv',
1590 38
            0x0867, // repeated record identifier
1591 38
            0x0000, // not used
1592 38
            0x0000, // not used
1593 38
            0x00, // not used
1594 38
            0x01000200, // unknown data
1595 38
            0xFFFFFFFF, // unknown data
1596
            $options, // options
1597 38
            0x0000 // not used
1598
        );
1599
1600 38
        $length = strlen($recordData);
1601 38
        $header = pack('vv', $record, $length);
1602
1603 38
        $this->append($header . $recordData);
1604 38
    }
1605
1606
    /**
1607
     * Write BIFF record RANGEPROTECTION.
1608
     *
1609
     * Openoffice.org's Documentaion of the Microsoft Excel File Format uses term RANGEPROTECTION for these records
1610
     * Microsoft Office Excel 97-2007 Binary File Format Specification uses term FEAT for these records
1611
     */
1612 38
    private function writeRangeProtection()
1613
    {
1614 38
        foreach ($this->phpSheet->getProtectedCells() as $range => $password) {
1615
            // number of ranges, e.g. 'A1:B3 C20:D25'
1616 5
            $cellRanges = explode(' ', $range);
1617 5
            $cref = count($cellRanges);
1618
1619 5
            $recordData = pack(
1620 5
                'vvVVvCVvVv',
1621 5
                0x0868,
1622 5
                0x00,
1623 5
                0x0000,
1624 5
                0x0000,
1625 5
                0x02,
1626 5
                0x0,
1627 5
                0x0000,
1628
                $cref,
1629 5
                0x0000,
1630 5
                0x00
1631
            );
1632
1633 5
            foreach ($cellRanges as $cellRange) {
1634 5
                $recordData .= $this->writeBIFF8CellRangeAddressFixed($cellRange);
1635
            }
1636
1637
            // the rgbFeat structure
1638 5
            $recordData .= pack(
1639 5
                'VV',
1640 5
                0x0000,
1641
                hexdec($password)
1642
            );
1643
1644 5
            $recordData .= \PhpOffice\PhpSpreadsheet\Shared\StringHelper::UTF8toBIFF8UnicodeLong('p' . md5($recordData));
1645
1646 5
            $length = strlen($recordData);
1647
1648 5
            $record = 0x0868; // Record identifier
1649 5
            $header = pack('vv', $record, $length);
1650 5
            $this->append($header . $recordData);
1651
        }
1652 38
    }
1653
1654
    /**
1655
     * Write BIFF record EXTERNCOUNT to indicate the number of external sheet
1656
     * references in a worksheet.
1657
     *
1658
     * Excel only stores references to external sheets that are used in formulas.
1659
     * For simplicity we store references to all the sheets in the workbook
1660
     * regardless of whether they are used or not. This reduces the overall
1661
     * complexity and eliminates the need for a two way dialogue between the formula
1662
     * parser the worksheet objects.
1663
     *
1664
     * @param int $count The number of external sheet references in this worksheet
1665
     */
1666 View Code Duplication
    private function writeExterncount($count)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
Duplication introduced by
This method seems to be duplicated in 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...
1667
    {
1668
        $record = 0x0016; // Record identifier
1669
        $length = 0x0002; // Number of bytes to follow
1670
1671
        $header = pack('vv', $record, $length);
1672
        $data = pack('v', $count);
1673
        $this->append($header . $data);
1674
    }
1675
1676
    /**
1677
     * Writes the Excel BIFF EXTERNSHEET record. These references are used by
1678
     * formulas. A formula references a sheet name via an index. Since we store a
1679
     * reference to all of the external worksheets the EXTERNSHEET index is the same
1680
     * as the worksheet index.
1681
     *
1682
     * @param string $sheetname The name of a external worksheet
1683
     */
1684
    private function writeExternsheet($sheetname)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
1685
    {
1686
        $record = 0x0017; // Record identifier
1687
1688
        // References to the current sheet are encoded differently to references to
1689
        // external sheets.
1690
        //
1691
        if ($this->phpSheet->getTitle() == $sheetname) {
1692
            $sheetname = '';
1693
            $length = 0x02; // The following 2 bytes
1694
            $cch = 1; // The following byte
1695
            $rgch = 0x02; // Self reference
1696
        } else {
1697
            $length = 0x02 + strlen($sheetname);
1698
            $cch = strlen($sheetname);
1699
            $rgch = 0x03; // Reference to a sheet in the current workbook
1700
        }
1701
1702
        $header = pack('vv', $record, $length);
1703
        $data = pack('CC', $cch, $rgch);
1704
        $this->append($header . $data . $sheetname);
1705
    }
1706
1707
    /**
1708
     * Writes the Excel BIFF PANE record.
1709
     * The panes can either be frozen or thawed (unfrozen).
1710
     * Frozen panes are specified in terms of an integer number of rows and columns.
1711
     * Thawed panes are specified in terms of Excel's units for rows and columns.
1712
     */
1713 3
    private function writePanes()
1714
    {
1715 3
        $panes = [];
1716 3
        if ($freezePane = $this->phpSheet->getFreezePane()) {
1717 3
            list($column, $row) = \PhpOffice\PhpSpreadsheet\Cell::coordinateFromString($freezePane);
1718 3
            $panes[0] = $row - 1;
1719 3
            $panes[1] = \PhpOffice\PhpSpreadsheet\Cell::columnIndexFromString($column) - 1;
1720
        } else {
1721
            // thaw panes
1722
            return;
1723
        }
1724
1725 3
        $y = isset($panes[0]) ? $panes[0] : null;
1726 3
        $x = isset($panes[1]) ? $panes[1] : null;
1727 3
        $rwTop = isset($panes[2]) ? $panes[2] : null;
1728 3
        $colLeft = isset($panes[3]) ? $panes[3] : null;
1729 3
        if (count($panes) > 4) { // if Active pane was received
1730
            $pnnAct = $panes[4];
1731
        } else {
1732 3
            $pnnAct = null;
1733
        }
1734 3
        $record = 0x0041; // Record identifier
1735 3
        $length = 0x000A; // Number of bytes to follow
1736
1737
        // Code specific to frozen or thawed panes.
1738 3
        if ($this->phpSheet->getFreezePane()) {
1739
            // Set default values for $rwTop and $colLeft
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% 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...
1740 3
            if (!isset($rwTop)) {
1741 3
                $rwTop = $y;
1742
            }
1743 3
            if (!isset($colLeft)) {
1744 3
                $colLeft = $x;
1745
            }
1746
        } else {
1747
            // Set default values for $rwTop and $colLeft
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% 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...
1748
            if (!isset($rwTop)) {
1749
                $rwTop = 0;
1750
            }
1751
            if (!isset($colLeft)) {
1752
                $colLeft = 0;
1753
            }
1754
1755
            // Convert Excel's row and column units to the internal units.
1756
            // The default row height is 12.75
1757
            // The default column width is 8.43
1758
            // The following slope and intersection values were interpolated.
1759
            //
1760
            $y = 20 * $y + 255;
1761
            $x = 113.879 * $x + 390;
1762
        }
1763
1764
        // Determine which pane should be active. There is also the undocumented
1765
        // option to override this should it be necessary: may be removed later.
1766
        //
1767 3
        if (!isset($pnnAct)) {
1768 3
            if ($x != 0 && $y != 0) {
1769
                $pnnAct = 0; // Bottom right
1770
            }
1771 3
            if ($x != 0 && $y == 0) {
1772
                $pnnAct = 1; // Top right
1773
            }
1774 3
            if ($x == 0 && $y != 0) {
1775 3
                $pnnAct = 2; // Bottom left
1776
            }
1777 3
            if ($x == 0 && $y == 0) {
1778
                $pnnAct = 3; // Top left
1779
            }
1780
        }
1781
1782 3
        $this->activePane = $pnnAct; // Used in writeSelection
1783
1784 3
        $header = pack('vv', $record, $length);
1785 3
        $data = pack('vvvvv', $x, $y, $rwTop, $colLeft, $pnnAct);
1786 3
        $this->append($header . $data);
1787 3
    }
1788
1789
    /**
1790
     * Store the page setup SETUP BIFF record.
1791
     */
1792 38
    private function writeSetup()
1793
    {
1794 38
        $record = 0x00A1; // Record identifier
1795 38
        $length = 0x0022; // Number of bytes to follow
1796
1797 38
        $iPaperSize = $this->phpSheet->getPageSetup()->getPaperSize(); // Paper size
1798
1799 38
        $iScale = $this->phpSheet->getPageSetup()->getScale() ?
1800 38
            $this->phpSheet->getPageSetup()->getScale() : 100; // Print scaling factor
1801
1802 38
        $iPageStart = 0x01; // Starting page number
1803 38
        $iFitWidth = (int) $this->phpSheet->getPageSetup()->getFitToWidth(); // Fit to number of pages wide
1804 38
        $iFitHeight = (int) $this->phpSheet->getPageSetup()->getFitToHeight(); // Fit to number of pages high
1805 38
        $grbit = 0x00; // Option flags
0 ignored issues
show
Unused Code introduced by
$grbit 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...
1806 38
        $iRes = 0x0258; // Print resolution
1807 38
        $iVRes = 0x0258; // Vertical print resolution
1808
1809 38
        $numHdr = $this->phpSheet->getPageMargins()->getHeader(); // Header Margin
1810
1811 38
        $numFtr = $this->phpSheet->getPageMargins()->getFooter(); // Footer Margin
1812 38
        $iCopies = 0x01; // Number of copies
1813
1814 38
        $fLeftToRight = 0x0; // Print over then down
1815
1816
        // Page orientation
1817 38
        $fLandscape = ($this->phpSheet->getPageSetup()->getOrientation() == \PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::ORIENTATION_LANDSCAPE) ?
1818 38
            0x0 : 0x1;
1819
1820 38
        $fNoPls = 0x0; // Setup not read from printer
1821 38
        $fNoColor = 0x0; // Print black and white
1822 38
        $fDraft = 0x0; // Print draft quality
1823 38
        $fNotes = 0x0; // Print notes
1824 38
        $fNoOrient = 0x0; // Orientation not set
1825 38
        $fUsePage = 0x0; // Use custom starting page
1826
1827 38
        $grbit = $fLeftToRight;
1828 38
        $grbit |= $fLandscape << 1;
1829 38
        $grbit |= $fNoPls << 2;
1830 38
        $grbit |= $fNoColor << 3;
1831 38
        $grbit |= $fDraft << 4;
1832 38
        $grbit |= $fNotes << 5;
1833 38
        $grbit |= $fNoOrient << 6;
1834 38
        $grbit |= $fUsePage << 7;
1835
1836 38
        $numHdr = pack('d', $numHdr);
1837 38
        $numFtr = pack('d', $numFtr);
1838 38
        if (self::getByteOrder()) { // if it's Big Endian
1839
            $numHdr = strrev($numHdr);
1840
            $numFtr = strrev($numFtr);
1841
        }
1842
1843 38
        $header = pack('vv', $record, $length);
1844 38
        $data1 = pack('vvvvvvvv', $iPaperSize, $iScale, $iPageStart, $iFitWidth, $iFitHeight, $grbit, $iRes, $iVRes);
1845 38
        $data2 = $numHdr . $numFtr;
1846 38
        $data3 = pack('v', $iCopies);
1847 38
        $this->append($header . $data1 . $data2 . $data3);
1848 38
    }
1849
1850
    /**
1851
     * Store the header caption BIFF record.
1852
     */
1853 38 View Code Duplication
    private function writeHeader()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1854
    {
1855 38
        $record = 0x0014; // Record identifier
1856
1857
        /* removing for now
0 ignored issues
show
Unused Code Comprehensibility introduced by
45% 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...
1858
        // need to fix character count (multibyte!)
1859
        if (strlen($this->phpSheet->getHeaderFooter()->getOddHeader()) <= 255) {
1860
            $str      = $this->phpSheet->getHeaderFooter()->getOddHeader();       // header string
1861
        } else {
1862
            $str = '';
1863
        }
1864
        */
1865
1866 38
        $recordData = \PhpOffice\PhpSpreadsheet\Shared\StringHelper::UTF8toBIFF8UnicodeLong($this->phpSheet->getHeaderFooter()->getOddHeader());
1867 38
        $length = strlen($recordData);
1868
1869 38
        $header = pack('vv', $record, $length);
1870
1871 38
        $this->append($header . $recordData);
1872 38
    }
1873
1874
    /**
1875
     * Store the footer caption BIFF record.
1876
     */
1877 38 View Code Duplication
    private function writeFooter()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1878
    {
1879 38
        $record = 0x0015; // Record identifier
1880
1881
        /* removing for now
0 ignored issues
show
Unused Code Comprehensibility introduced by
45% 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...
1882
        // need to fix character count (multibyte!)
1883
        if (strlen($this->phpSheet->getHeaderFooter()->getOddFooter()) <= 255) {
1884
            $str = $this->phpSheet->getHeaderFooter()->getOddFooter();
1885
        } else {
1886
            $str = '';
1887
        }
1888
        */
1889
1890 38
        $recordData = \PhpOffice\PhpSpreadsheet\Shared\StringHelper::UTF8toBIFF8UnicodeLong($this->phpSheet->getHeaderFooter()->getOddFooter());
1891 38
        $length = strlen($recordData);
1892
1893 38
        $header = pack('vv', $record, $length);
1894
1895 38
        $this->append($header . $recordData);
1896 38
    }
1897
1898
    /**
1899
     * Store the horizontal centering HCENTER BIFF record.
1900
     */
1901 38 View Code Duplication
    private function writeHcenter()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1902
    {
1903 38
        $record = 0x0083; // Record identifier
1904 38
        $length = 0x0002; // Bytes to follow
1905
1906 38
        $fHCenter = $this->phpSheet->getPageSetup()->getHorizontalCentered() ? 1 : 0; // Horizontal centering
1907
1908 38
        $header = pack('vv', $record, $length);
1909 38
        $data = pack('v', $fHCenter);
1910
1911 38
        $this->append($header . $data);
1912 38
    }
1913
1914
    /**
1915
     * Store the vertical centering VCENTER BIFF record.
1916
     */
1917 38 View Code Duplication
    private function writeVcenter()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1918
    {
1919 38
        $record = 0x0084; // Record identifier
1920 38
        $length = 0x0002; // Bytes to follow
1921
1922 38
        $fVCenter = $this->phpSheet->getPageSetup()->getVerticalCentered() ? 1 : 0; // Horizontal centering
1923
1924 38
        $header = pack('vv', $record, $length);
1925 38
        $data = pack('v', $fVCenter);
1926 38
        $this->append($header . $data);
1927 38
    }
1928
1929
    /**
1930
     * Store the LEFTMARGIN BIFF record.
1931
     */
1932 38 View Code Duplication
    private function writeMarginLeft()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1933
    {
1934 38
        $record = 0x0026; // Record identifier
1935 38
        $length = 0x0008; // Bytes to follow
1936
1937 38
        $margin = $this->phpSheet->getPageMargins()->getLeft(); // Margin in inches
1938
1939 38
        $header = pack('vv', $record, $length);
1940 38
        $data = pack('d', $margin);
1941 38
        if (self::getByteOrder()) { // if it's Big Endian
1942
            $data = strrev($data);
1943
        }
1944
1945 38
        $this->append($header . $data);
1946 38
    }
1947
1948
    /**
1949
     * Store the RIGHTMARGIN BIFF record.
1950
     */
1951 38 View Code Duplication
    private function writeMarginRight()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1952
    {
1953 38
        $record = 0x0027; // Record identifier
1954 38
        $length = 0x0008; // Bytes to follow
1955
1956 38
        $margin = $this->phpSheet->getPageMargins()->getRight(); // Margin in inches
1957
1958 38
        $header = pack('vv', $record, $length);
1959 38
        $data = pack('d', $margin);
1960 38
        if (self::getByteOrder()) { // if it's Big Endian
1961
            $data = strrev($data);
1962
        }
1963
1964 38
        $this->append($header . $data);
1965 38
    }
1966
1967
    /**
1968
     * Store the TOPMARGIN BIFF record.
1969
     */
1970 38 View Code Duplication
    private function writeMarginTop()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1971
    {
1972 38
        $record = 0x0028; // Record identifier
1973 38
        $length = 0x0008; // Bytes to follow
1974
1975 38
        $margin = $this->phpSheet->getPageMargins()->getTop(); // Margin in inches
1976
1977 38
        $header = pack('vv', $record, $length);
1978 38
        $data = pack('d', $margin);
1979 38
        if (self::getByteOrder()) { // if it's Big Endian
1980
            $data = strrev($data);
1981
        }
1982
1983 38
        $this->append($header . $data);
1984 38
    }
1985
1986
    /**
1987
     * Store the BOTTOMMARGIN BIFF record.
1988
     */
1989 38 View Code Duplication
    private function writeMarginBottom()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1990
    {
1991 38
        $record = 0x0029; // Record identifier
1992 38
        $length = 0x0008; // Bytes to follow
1993
1994 38
        $margin = $this->phpSheet->getPageMargins()->getBottom(); // Margin in inches
1995
1996 38
        $header = pack('vv', $record, $length);
1997 38
        $data = pack('d', $margin);
1998 38
        if (self::getByteOrder()) { // if it's Big Endian
1999
            $data = strrev($data);
2000
        }
2001
2002 38
        $this->append($header . $data);
2003 38
    }
2004
2005
    /**
2006
     * Write the PRINTHEADERS BIFF record.
2007
     */
2008 38 View Code Duplication
    private function writePrintHeaders()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2009
    {
2010 38
        $record = 0x002a; // Record identifier
2011 38
        $length = 0x0002; // Bytes to follow
2012
2013 38
        $fPrintRwCol = $this->printHeaders; // Boolean flag
2014
2015 38
        $header = pack('vv', $record, $length);
2016 38
        $data = pack('v', $fPrintRwCol);
2017 38
        $this->append($header . $data);
2018 38
    }
2019
2020
    /**
2021
     * Write the PRINTGRIDLINES BIFF record. Must be used in conjunction with the
2022
     * GRIDSET record.
2023
     */
2024 38 View Code Duplication
    private function writePrintGridlines()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2025
    {
2026 38
        $record = 0x002b; // Record identifier
2027 38
        $length = 0x0002; // Bytes to follow
2028
2029 38
        $fPrintGrid = $this->phpSheet->getPrintGridlines() ? 1 : 0; // Boolean flag
2030
2031 38
        $header = pack('vv', $record, $length);
2032 38
        $data = pack('v', $fPrintGrid);
2033 38
        $this->append($header . $data);
2034 38
    }
2035
2036
    /**
2037
     * Write the GRIDSET BIFF record. Must be used in conjunction with the
2038
     * PRINTGRIDLINES record.
2039
     */
2040 38
    private function writeGridset()
2041
    {
2042 38
        $record = 0x0082; // Record identifier
2043 38
        $length = 0x0002; // Bytes to follow
2044
2045 38
        $fGridSet = !$this->phpSheet->getPrintGridlines(); // Boolean flag
2046
2047 38
        $header = pack('vv', $record, $length);
2048 38
        $data = pack('v', $fGridSet);
2049 38
        $this->append($header . $data);
2050 38
    }
2051
2052
    /**
2053
     * Write the AUTOFILTERINFO BIFF record. This is used to configure the number of autofilter select used in the sheet.
2054
     */
2055 3
    private function writeAutoFilterInfo()
2056
    {
2057 3
        $record = 0x009D; // Record identifier
2058 3
        $length = 0x0002; // Bytes to follow
2059
2060 3
        $rangeBounds = \PhpOffice\PhpSpreadsheet\Cell::rangeBoundaries($this->phpSheet->getAutoFilter()->getRange());
2061 3
        $iNumFilters = 1 + $rangeBounds[1][0] - $rangeBounds[0][0];
2062
2063 3
        $header = pack('vv', $record, $length);
2064 3
        $data = pack('v', $iNumFilters);
2065 3
        $this->append($header . $data);
2066 3
    }
2067
2068
    /**
2069
     * Write the GUTS BIFF record. This is used to configure the gutter margins
2070
     * where Excel outline symbols are displayed. The visibility of the gutters is
2071
     * controlled by a flag in WSBOOL.
2072
     *
2073
     * @see writeWsbool()
2074
     */
2075 38
    private function writeGuts()
2076
    {
2077 38
        $record = 0x0080; // Record identifier
2078 38
        $length = 0x0008; // Bytes to follow
2079
2080 38
        $dxRwGut = 0x0000; // Size of row gutter
2081 38
        $dxColGut = 0x0000; // Size of col gutter
2082
2083
        // determine maximum row outline level
2084 38
        $maxRowOutlineLevel = 0;
2085 38
        foreach ($this->phpSheet->getRowDimensions() as $rowDimension) {
2086 37
            $maxRowOutlineLevel = max($maxRowOutlineLevel, $rowDimension->getOutlineLevel());
2087
        }
2088
2089 38
        $col_level = 0;
2090
2091
        // Calculate the maximum column outline level. The equivalent calculation
2092
        // for the row outline level is carried out in writeRow().
2093 38
        $colcount = count($this->columnInfo);
2094 38
        for ($i = 0; $i < $colcount; ++$i) {
2095 38
            $col_level = max($this->columnInfo[$i][5], $col_level);
2096
        }
2097
2098
        // Set the limits for the outline levels (0 <= x <= 7).
2099 38
        $col_level = max(0, min($col_level, 7));
2100
2101
        // The displayed level is one greater than the max outline levels
2102 38
        if ($maxRowOutlineLevel) {
2103
            ++$maxRowOutlineLevel;
2104
        }
2105 38
        if ($col_level) {
2106 1
            ++$col_level;
2107
        }
2108
2109 38
        $header = pack('vv', $record, $length);
2110 38
        $data = pack('vvvv', $dxRwGut, $dxColGut, $maxRowOutlineLevel, $col_level);
2111
2112 38
        $this->append($header . $data);
2113 38
    }
2114
2115
    /**
2116
     * Write the WSBOOL BIFF record, mainly for fit-to-page. Used in conjunction
2117
     * with the SETUP record.
2118
     */
2119 38
    private function writeWsbool()
2120
    {
2121 38
        $record = 0x0081; // Record identifier
2122 38
        $length = 0x0002; // Bytes to follow
2123 38
        $grbit = 0x0000;
2124
2125
        // The only option that is of interest is the flag for fit to page. So we
2126
        // set all the options in one go.
2127
        //
2128
        // Set the option flags
2129 38
        $grbit |= 0x0001; // Auto page breaks visible
2130 38
        if ($this->outlineStyle) {
2131
            $grbit |= 0x0020; // Auto outline styles
2132
        }
2133 38
        if ($this->phpSheet->getShowSummaryBelow()) {
2134 38
            $grbit |= 0x0040; // Outline summary below
2135
        }
2136 38
        if ($this->phpSheet->getShowSummaryRight()) {
2137 38
            $grbit |= 0x0080; // Outline summary right
2138
        }
2139 38
        if ($this->phpSheet->getPageSetup()->getFitToPage()) {
2140
            $grbit |= 0x0100; // Page setup fit to page
2141
        }
2142 38
        if ($this->outlineOn) {
2143 38
            $grbit |= 0x0400; // Outline symbols displayed
2144
        }
2145
2146 38
        $header = pack('vv', $record, $length);
2147 38
        $data = pack('v', $grbit);
2148 38
        $this->append($header . $data);
2149 38
    }
2150
2151
    /**
2152
     * Write the HORIZONTALPAGEBREAKS and VERTICALPAGEBREAKS BIFF records.
2153
     */
2154 38
    private function writeBreaks()
2155
    {
2156
        // initialize
2157 38
        $vbreaks = [];
2158 38
        $hbreaks = [];
2159
2160 38
        foreach ($this->phpSheet->getBreaks() as $cell => $breakType) {
2161
            // Fetch coordinates
2162 1
            $coordinates = \PhpOffice\PhpSpreadsheet\Cell::coordinateFromString($cell);
2163
2164
            // Decide what to do by the type of break
2165
            switch ($breakType) {
2166 1
                case \PhpOffice\PhpSpreadsheet\Worksheet::BREAK_COLUMN:
2167
                    // Add to list of vertical breaks
2168
                    $vbreaks[] = \PhpOffice\PhpSpreadsheet\Cell::columnIndexFromString($coordinates[0]) - 1;
2169
                    break;
2170 1
                case \PhpOffice\PhpSpreadsheet\Worksheet::BREAK_ROW:
2171
                    // Add to list of horizontal breaks
2172 1
                    $hbreaks[] = $coordinates[1];
2173 1
                    break;
2174
                case \PhpOffice\PhpSpreadsheet\Worksheet::BREAK_NONE:
2175
                default:
2176
                    // Nothing to do
2177 1
                    break;
2178
            }
2179
        }
2180
2181
        //horizontal page breaks
2182 38
        if (!empty($hbreaks)) {
2183
            // Sort and filter array of page breaks
2184 1
            sort($hbreaks, SORT_NUMERIC);
2185 1
            if ($hbreaks[0] == 0) { // don't use first break if it's 0
2186
                array_shift($hbreaks);
2187
            }
2188
2189 1
            $record = 0x001b; // Record identifier
2190 1
            $cbrk = count($hbreaks); // Number of page breaks
2191 1
            $length = 2 + 6 * $cbrk; // Bytes to follow
2192
2193 1
            $header = pack('vv', $record, $length);
2194 1
            $data = pack('v', $cbrk);
2195
2196
            // Append each page break
2197 1
            foreach ($hbreaks as $hbreak) {
2198 1
                $data .= pack('vvv', $hbreak, 0x0000, 0x00ff);
2199
            }
2200
2201 1
            $this->append($header . $data);
2202
        }
2203
2204
        // vertical page breaks
2205 38
        if (!empty($vbreaks)) {
2206
            // 1000 vertical pagebreaks appears to be an internal Excel 5 limit.
2207
            // It is slightly higher in Excel 97/200, approx. 1026
2208
            $vbreaks = array_slice($vbreaks, 0, 1000);
2209
2210
            // Sort and filter array of page breaks
2211
            sort($vbreaks, SORT_NUMERIC);
2212
            if ($vbreaks[0] == 0) { // don't use first break if it's 0
2213
                array_shift($vbreaks);
2214
            }
2215
2216
            $record = 0x001a; // Record identifier
2217
            $cbrk = count($vbreaks); // Number of page breaks
2218
            $length = 2 + 6 * $cbrk; // Bytes to follow
2219
2220
            $header = pack('vv', $record, $length);
2221
            $data = pack('v', $cbrk);
2222
2223
            // Append each page break
2224
            foreach ($vbreaks as $vbreak) {
2225
                $data .= pack('vvv', $vbreak, 0x0000, 0xffff);
2226
            }
2227
2228
            $this->append($header . $data);
2229
        }
2230 38
    }
2231
2232
    /**
2233
     * Set the Biff PROTECT record to indicate that the worksheet is protected.
2234
     */
2235 38 View Code Duplication
    private function writeProtect()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2236
    {
2237
        // Exit unless sheet protection has been specified
2238 38
        if (!$this->phpSheet->getProtection()->getSheet()) {
2239 36
            return;
2240
        }
2241
2242 7
        $record = 0x0012; // Record identifier
2243 7
        $length = 0x0002; // Bytes to follow
2244
2245 7
        $fLock = 1; // Worksheet is protected
2246
2247 7
        $header = pack('vv', $record, $length);
2248 7
        $data = pack('v', $fLock);
2249
2250 7
        $this->append($header . $data);
2251 7
    }
2252
2253
    /**
2254
     * Write SCENPROTECT.
2255
     */
2256 38 View Code Duplication
    private function writeScenProtect()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2257
    {
2258
        // Exit if sheet protection is not active
2259 38
        if (!$this->phpSheet->getProtection()->getSheet()) {
2260 36
            return;
2261
        }
2262
2263
        // Exit if scenarios are not protected
2264 7
        if (!$this->phpSheet->getProtection()->getScenarios()) {
2265 7
            return;
2266
        }
2267
2268
        $record = 0x00DD; // Record identifier
2269
        $length = 0x0002; // Bytes to follow
2270
2271
        $header = pack('vv', $record, $length);
2272
        $data = pack('v', 1);
2273
2274
        $this->append($header . $data);
2275
    }
2276
2277
    /**
2278
     * Write OBJECTPROTECT.
2279
     */
2280 38 View Code Duplication
    private function writeObjectProtect()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2281
    {
2282
        // Exit if sheet protection is not active
2283 38
        if (!$this->phpSheet->getProtection()->getSheet()) {
2284 36
            return;
2285
        }
2286
2287
        // Exit if objects are not protected
2288 7
        if (!$this->phpSheet->getProtection()->getObjects()) {
2289 7
            return;
2290
        }
2291
2292
        $record = 0x0063; // Record identifier
2293
        $length = 0x0002; // Bytes to follow
2294
2295
        $header = pack('vv', $record, $length);
2296
        $data = pack('v', 1);
2297
2298
        $this->append($header . $data);
2299
    }
2300
2301
    /**
2302
     * Write the worksheet PASSWORD record.
2303
     */
2304 38
    private function writePassword()
2305
    {
2306
        // Exit unless sheet protection and password have been specified
2307 38
        if (!$this->phpSheet->getProtection()->getSheet() || !$this->phpSheet->getProtection()->getPassword()) {
2308 37
            return;
2309
        }
2310
2311 1
        $record = 0x0013; // Record identifier
2312 1
        $length = 0x0002; // Bytes to follow
2313
2314 1
        $wPassword = hexdec($this->phpSheet->getProtection()->getPassword()); // Encoded password
2315
2316 1
        $header = pack('vv', $record, $length);
2317 1
        $data = pack('v', $wPassword);
2318
2319 1
        $this->append($header . $data);
2320 1
    }
2321
2322
    /**
2323
     * Insert a 24bit bitmap image in a worksheet.
2324
     *
2325
     * @param int $row     The row we are going to insert the bitmap into
2326
     * @param int $col     The column we are going to insert the bitmap into
2327
     * @param mixed   $bitmap  The bitmap filename or GD-image resource
2328
     * @param int $x       the horizontal position (offset) of the image inside the cell
2329
     * @param int $y       the vertical position (offset) of the image inside the cell
2330
     * @param float   $scale_x The horizontal scale
2331
     * @param float   $scale_y The vertical scale
2332
     */
2333
    public function insertBitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1)
2334
    {
2335
        $bitmap_array = (is_resource($bitmap) ? $this->processBitmapGd($bitmap) : $this->processBitmap($bitmap));
2336
        list($width, $height, $size, $data) = $bitmap_array;
2337
2338
        // Scale the frame of the image.
2339
        $width *= $scale_x;
2340
        $height *= $scale_y;
2341
2342
        // Calculate the vertices of the image and write the OBJ record
2343
        $this->positionImage($col, $row, $x, $y, $width, $height);
2344
2345
        // Write the IMDATA record to store the bitmap data
2346
        $record = 0x007f;
2347
        $length = 8 + $size;
2348
        $cf = 0x09;
2349
        $env = 0x01;
2350
        $lcb = $size;
2351
2352
        $header = pack('vvvvV', $record, $length, $cf, $env, $lcb);
2353
        $this->append($header . $data);
2354
    }
2355
2356
    /**
2357
     * Calculate the vertices that define the position of the image as required by
2358
     * the OBJ record.
2359
     *
2360
     *         +------------+------------+
2361
     *         |     A      |      B     |
2362
     *   +-----+------------+------------+
2363
     *   |     |(x1,y1)     |            |
2364
     *   |  1  |(A1)._______|______      |
2365
     *   |     |    |              |     |
2366
     *   |     |    |              |     |
2367
     *   +-----+----|    BITMAP    |-----+
2368
     *   |     |    |              |     |
2369
     *   |  2  |    |______________.     |
2370
     *   |     |            |        (B2)|
2371
     *   |     |            |     (x2,y2)|
2372
     *   +---- +------------+------------+
2373
     *
2374
     * Example of a bitmap that covers some of the area from cell A1 to cell B2.
2375
     *
2376
     * Based on the width and height of the bitmap we need to calculate 8 vars:
2377
     *     $col_start, $row_start, $col_end, $row_end, $x1, $y1, $x2, $y2.
2378
     * The width and height of the cells are also variable and have to be taken into
2379
     * account.
2380
     * The values of $col_start and $row_start are passed in from the calling
2381
     * function. The values of $col_end and $row_end are calculated by subtracting
2382
     * the width and height of the bitmap from the width and height of the
2383
     * underlying cells.
2384
     * The vertices are expressed as a percentage of the underlying cell width as
2385
     * follows (rhs values are in pixels):
2386
     *
2387
     *       x1 = X / W *1024
2388
     *       y1 = Y / H *256
2389
     *       x2 = (X-1) / W *1024
2390
     *       y2 = (Y-1) / H *256
2391
     *
2392
     *       Where:  X is distance from the left side of the underlying cell
2393
     *               Y is distance from the top of the underlying cell
2394
     *               W is the width of the cell
2395
     *               H is the height of the cell
2396
     * The SDK incorrectly states that the height should be expressed as a
2397
     *        percentage of 1024.
2398
     *
2399
     * @param int $col_start Col containing upper left corner of object
2400
     * @param int $row_start Row containing top left corner of object
2401
     * @param int $x1        Distance to left side of object
2402
     * @param int $y1        Distance to top of object
2403
     * @param int $width     Width of image frame
2404
     * @param int $height    Height of image frame
2405
     */
2406
    public function positionImage($col_start, $row_start, $x1, $y1, $width, $height)
2407
    {
2408
        // Initialise end cell to the same as the start cell
2409
        $col_end = $col_start; // Col containing lower right corner of object
2410
        $row_end = $row_start; // Row containing bottom right corner of object
2411
2412
        // Zero the specified offset if greater than the cell dimensions
2413
        if ($x1 >= \PhpOffice\PhpSpreadsheet\Shared\Xls::sizeCol($this->phpSheet, \PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex($col_start))) {
2414
            $x1 = 0;
2415
        }
2416
        if ($y1 >= \PhpOffice\PhpSpreadsheet\Shared\Xls::sizeRow($this->phpSheet, $row_start + 1)) {
2417
            $y1 = 0;
2418
        }
2419
2420
        $width = $width + $x1 - 1;
2421
        $height = $height + $y1 - 1;
2422
2423
        // Subtract the underlying cell widths to find the end cell of the image
2424
        while ($width >= \PhpOffice\PhpSpreadsheet\Shared\Xls::sizeCol($this->phpSheet, \PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex($col_end))) {
2425
            $width -= \PhpOffice\PhpSpreadsheet\Shared\Xls::sizeCol($this->phpSheet, \PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex($col_end));
2426
            ++$col_end;
2427
        }
2428
2429
        // Subtract the underlying cell heights to find the end cell of the image
2430
        while ($height >= \PhpOffice\PhpSpreadsheet\Shared\Xls::sizeRow($this->phpSheet, $row_end + 1)) {
2431
            $height -= \PhpOffice\PhpSpreadsheet\Shared\Xls::sizeRow($this->phpSheet, $row_end + 1);
2432
            ++$row_end;
2433
        }
2434
2435
        // Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell
2436
        // with zero eight or width.
2437
        //
2438
        if (\PhpOffice\PhpSpreadsheet\Shared\Xls::sizeCol($this->phpSheet, \PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex($col_start)) == 0) {
2439
            return;
2440
        }
2441
        if (\PhpOffice\PhpSpreadsheet\Shared\Xls::sizeCol($this->phpSheet, \PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex($col_end)) == 0) {
2442
            return;
2443
        }
2444
        if (\PhpOffice\PhpSpreadsheet\Shared\Xls::sizeRow($this->phpSheet, $row_start + 1) == 0) {
2445
            return;
2446
        }
2447
        if (\PhpOffice\PhpSpreadsheet\Shared\Xls::sizeRow($this->phpSheet, $row_end + 1) == 0) {
2448
            return;
2449
        }
2450
2451
        // Convert the pixel values to the percentage value expected by Excel
2452
        $x1 = $x1 / \PhpOffice\PhpSpreadsheet\Shared\Xls::sizeCol($this->phpSheet, \PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex($col_start)) * 1024;
2453
        $y1 = $y1 / \PhpOffice\PhpSpreadsheet\Shared\Xls::sizeRow($this->phpSheet, $row_start + 1) * 256;
2454
        $x2 = $width / \PhpOffice\PhpSpreadsheet\Shared\Xls::sizeCol($this->phpSheet, \PhpOffice\PhpSpreadsheet\Cell::stringFromColumnIndex($col_end)) * 1024; // Distance to right side of object
2455
        $y2 = $height / \PhpOffice\PhpSpreadsheet\Shared\Xls::sizeRow($this->phpSheet, $row_end + 1) * 256; // Distance to bottom of object
2456
2457
        $this->writeObjPicture($col_start, $x1, $row_start, $y1, $col_end, $x2, $row_end, $y2);
2458
    }
2459
2460
    /**
2461
     * Store the OBJ record that precedes an IMDATA record. This could be generalise
2462
     * to support other Excel objects.
2463
     *
2464
     * @param int $colL Column containing upper left corner of object
2465
     * @param int $dxL  Distance from left side of cell
2466
     * @param int $rwT  Row containing top left corner of object
2467
     * @param int $dyT  Distance from top of cell
2468
     * @param int $colR Column containing lower right corner of object
2469
     * @param int $dxR  Distance from right of cell
2470
     * @param int $rwB  Row containing bottom right corner of object
2471
     * @param int $dyB  Distance from bottom of cell
2472
     */
2473
    private function writeObjPicture($colL, $dxL, $rwT, $dyT, $colR, $dxR, $rwB, $dyB)
2474
    {
2475
        $record = 0x005d; // Record identifier
2476
        $length = 0x003c; // Bytes to follow
2477
2478
        $cObj = 0x0001; // Count of objects in file (set to 1)
2479
        $OT = 0x0008; // Object type. 8 = Picture
2480
        $id = 0x0001; // Object ID
2481
        $grbit = 0x0614; // Option flags
2482
2483
        $cbMacro = 0x0000; // Length of FMLA structure
2484
        $Reserved1 = 0x0000; // Reserved
2485
        $Reserved2 = 0x0000; // Reserved
2486
2487
        $icvBack = 0x09; // Background colour
2488
        $icvFore = 0x09; // Foreground colour
2489
        $fls = 0x00; // Fill pattern
2490
        $fAuto = 0x00; // Automatic fill
2491
        $icv = 0x08; // Line colour
2492
        $lns = 0xff; // Line style
2493
        $lnw = 0x01; // Line weight
2494
        $fAutoB = 0x00; // Automatic border
2495
        $frs = 0x0000; // Frame style
2496
        $cf = 0x0009; // Image format, 9 = bitmap
2497
        $Reserved3 = 0x0000; // Reserved
2498
        $cbPictFmla = 0x0000; // Length of FMLA structure
2499
        $Reserved4 = 0x0000; // Reserved
2500
        $grbit2 = 0x0001; // Option flags
2501
        $Reserved5 = 0x0000; // Reserved
2502
2503
        $header = pack('vv', $record, $length);
2504
        $data = pack('V', $cObj);
2505
        $data .= pack('v', $OT);
2506
        $data .= pack('v', $id);
2507
        $data .= pack('v', $grbit);
2508
        $data .= pack('v', $colL);
2509
        $data .= pack('v', $dxL);
2510
        $data .= pack('v', $rwT);
2511
        $data .= pack('v', $dyT);
2512
        $data .= pack('v', $colR);
2513
        $data .= pack('v', $dxR);
2514
        $data .= pack('v', $rwB);
2515
        $data .= pack('v', $dyB);
2516
        $data .= pack('v', $cbMacro);
2517
        $data .= pack('V', $Reserved1);
2518
        $data .= pack('v', $Reserved2);
2519
        $data .= pack('C', $icvBack);
2520
        $data .= pack('C', $icvFore);
2521
        $data .= pack('C', $fls);
2522
        $data .= pack('C', $fAuto);
2523
        $data .= pack('C', $icv);
2524
        $data .= pack('C', $lns);
2525
        $data .= pack('C', $lnw);
2526
        $data .= pack('C', $fAutoB);
2527
        $data .= pack('v', $frs);
2528
        $data .= pack('V', $cf);
2529
        $data .= pack('v', $Reserved3);
2530
        $data .= pack('v', $cbPictFmla);
2531
        $data .= pack('v', $Reserved4);
2532
        $data .= pack('v', $grbit2);
2533
        $data .= pack('V', $Reserved5);
2534
2535
        $this->append($header . $data);
2536
    }
2537
2538
    /**
2539
     * Convert a GD-image into the internal format.
2540
     *
2541
     * @param resource $image The image to process
2542
     *
2543
     * @return array Array with data and properties of the bitmap
2544
     */
2545
    public function processBitmapGd($image)
2546
    {
2547
        $width = imagesx($image);
2548
        $height = imagesy($image);
2549
2550
        $data = pack('Vvvvv', 0x000c, $width, $height, 0x01, 0x18);
2551
        for ($j = $height; --$j;) {
2552
            for ($i = 0; $i < $width; ++$i) {
2553
                $color = imagecolorsforindex($image, imagecolorat($image, $i, $j));
2554
                foreach (['red', 'green', 'blue'] as $key) {
2555
                    $color[$key] = $color[$key] + round((255 - $color[$key]) * $color['alpha'] / 127);
2556
                }
2557
                $data .= chr($color['blue']) . chr($color['green']) . chr($color['red']);
2558
            }
2559
            if (3 * $width % 4) {
2560
                $data .= str_repeat("\x00", 4 - 3 * $width % 4);
2561
            }
2562
        }
2563
2564
        return [$width, $height, strlen($data), $data];
2565
    }
2566
2567
    /**
2568
     * Convert a 24 bit bitmap into the modified internal format used by Windows.
2569
     * This is described in BITMAPCOREHEADER and BITMAPCOREINFO structures in the
2570
     * MSDN library.
2571
     *
2572
     * @param string $bitmap The bitmap to process
2573
     *
2574
     * @return array Array with data and properties of the bitmap
2575
     */
2576
    public function processBitmap($bitmap)
2577
    {
2578
        // Open file.
2579
        $bmp_fd = @fopen($bitmap, 'rb');
2580
        if (!$bmp_fd) {
2581
            throw new \PhpOffice\PhpSpreadsheet\Writer\Exception("Couldn't import $bitmap");
2582
        }
2583
2584
        // Slurp the file into a string.
2585
        $data = fread($bmp_fd, filesize($bitmap));
2586
2587
        // Check that the file is big enough to be a bitmap.
2588
        if (strlen($data) <= 0x36) {
2589
            throw new \PhpOffice\PhpSpreadsheet\Writer\Exception("$bitmap doesn't contain enough data.\n");
2590
        }
2591
2592
        // The first 2 bytes are used to identify the bitmap.
2593
        $identity = unpack('A2ident', $data);
2594
        if ($identity['ident'] != 'BM') {
2595
            throw new \PhpOffice\PhpSpreadsheet\Writer\Exception("$bitmap doesn't appear to be a valid bitmap image.\n");
2596
        }
2597
2598
        // Remove bitmap data: ID.
2599
        $data = substr($data, 2);
2600
2601
        // Read and remove the bitmap size. This is more reliable than reading
2602
        // the data size at offset 0x22.
2603
        //
2604
        $size_array = unpack('Vsa', substr($data, 0, 4));
2605
        $size = $size_array['sa'];
2606
        $data = substr($data, 4);
2607
        $size -= 0x36; // Subtract size of bitmap header.
2608
        $size += 0x0C; // Add size of BIFF header.
2609
2610
        // Remove bitmap data: reserved, offset, header length.
2611
        $data = substr($data, 12);
2612
2613
        // Read and remove the bitmap width and height. Verify the sizes.
2614
        $width_and_height = unpack('V2', substr($data, 0, 8));
2615
        $width = $width_and_height[1];
2616
        $height = $width_and_height[2];
2617
        $data = substr($data, 8);
2618
        if ($width > 0xFFFF) {
2619
            throw new \PhpOffice\PhpSpreadsheet\Writer\Exception("$bitmap: largest image width supported is 65k.\n");
2620
        }
2621
        if ($height > 0xFFFF) {
2622
            throw new \PhpOffice\PhpSpreadsheet\Writer\Exception("$bitmap: largest image height supported is 65k.\n");
2623
        }
2624
2625
        // Read and remove the bitmap planes and bpp data. Verify them.
2626
        $planes_and_bitcount = unpack('v2', substr($data, 0, 4));
2627
        $data = substr($data, 4);
2628
        if ($planes_and_bitcount[2] != 24) { // Bitcount
2629
            throw new \PhpOffice\PhpSpreadsheet\Writer\Exception("$bitmap isn't a 24bit true color bitmap.\n");
2630
        }
2631
        if ($planes_and_bitcount[1] != 1) {
2632
            throw new \PhpOffice\PhpSpreadsheet\Writer\Exception("$bitmap: only 1 plane supported in bitmap image.\n");
2633
        }
2634
2635
        // Read and remove the bitmap compression. Verify compression.
2636
        $compression = unpack('Vcomp', substr($data, 0, 4));
2637
        $data = substr($data, 4);
2638
2639
        if ($compression['comp'] != 0) {
2640
            throw new \PhpOffice\PhpSpreadsheet\Writer\Exception("$bitmap: compression not supported in bitmap image.\n");
2641
        }
2642
2643
        // Remove bitmap data: data size, hres, vres, colours, imp. colours.
2644
        $data = substr($data, 20);
2645
2646
        // Add the BITMAPCOREHEADER data
2647
        $header = pack('Vvvvv', 0x000c, $width, $height, 0x01, 0x18);
2648
        $data = $header . $data;
2649
2650
        return [$width, $height, $size, $data];
2651
    }
2652
2653
    /**
2654
     * Store the window zoom factor. This should be a reduced fraction but for
2655
     * simplicity we will store all fractions with a numerator of 100.
2656
     */
2657 38 View Code Duplication
    private function writeZoom()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2658
    {
2659
        // If scale is 100 we don't need to write a record
2660 38
        if ($this->phpSheet->getSheetView()->getZoomScale() == 100) {
2661 38
            return;
2662
        }
2663
2664
        $record = 0x00A0; // Record identifier
2665
        $length = 0x0004; // Bytes to follow
2666
2667
        $header = pack('vv', $record, $length);
2668
        $data = pack('vv', $this->phpSheet->getSheetView()->getZoomScale(), 100);
2669
        $this->append($header . $data);
2670
    }
2671
2672
    /**
2673
     * Get Escher object.
2674
     *
2675
     * @return \PhpOffice\PhpSpreadsheet\Shared\Escher
2676
     */
2677
    public function getEscher()
2678
    {
2679
        return $this->escher;
2680
    }
2681
2682
    /**
2683
     * Set Escher object.
2684
     *
2685
     * @param \PhpOffice\PhpSpreadsheet\Shared\Escher $pValue
2686
     */
2687 10
    public function setEscher(\PhpOffice\PhpSpreadsheet\Shared\Escher $pValue = null)
2688
    {
2689 10
        $this->escher = $pValue;
2690 10
    }
2691
2692
    /**
2693
     * Write MSODRAWING record.
2694
     */
2695 38
    private function writeMsoDrawing()
2696
    {
2697
        // write the Escher stream if necessary
2698 38
        if (isset($this->escher)) {
2699 10
            $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xls\Escher($this->escher);
2700 10
            $data = $writer->close();
2701 10
            $spOffsets = $writer->getSpOffsets();
2702 10
            $spTypes = $writer->getSpTypes();
2703
            // write the neccesary MSODRAWING, OBJ records
2704
2705
            // split the Escher stream
2706 10
            $spOffsets[0] = 0;
2707 10
            $nm = count($spOffsets) - 1; // number of shapes excluding first shape
2708 10
            for ($i = 1; $i <= $nm; ++$i) {
2709
                // MSODRAWING record
2710 10
                $record = 0x00EC; // Record identifier
2711
2712
                // chunk of Escher stream for one shape
2713 10
                $dataChunk = substr($data, $spOffsets[$i - 1], $spOffsets[$i] - $spOffsets[$i - 1]);
2714
2715 10
                $length = strlen($dataChunk);
2716 10
                $header = pack('vv', $record, $length);
2717
2718 10
                $this->append($header . $dataChunk);
2719
2720
                // OBJ record
2721 10
                $record = 0x005D; // record identifier
2722 10
                $objData = '';
2723
2724
                // ftCmo
2725 10
                if ($spTypes[$i] == 0x00C9) {
2726
                    // Add ftCmo (common object data) subobject
2727
                    $objData .=
2728 3
                        pack(
2729 3
                            'vvvvvVVV',
2730 3
                            0x0015, // 0x0015 = ftCmo
2731 3
                            0x0012, // length of ftCmo data
2732 3
                            0x0014, // object type, 0x0014 = filter
2733
                            $i, // object id number, Excel seems to use 1-based index, local for the sheet
2734 3
                            0x2101, // option flags, 0x2001 is what OpenOffice.org uses
2735 3
                            0, // reserved
2736 3
                            0, // reserved
2737 3
                            0  // reserved
2738
                        );
2739
2740
                    // Add ftSbs Scroll bar subobject
2741 3
                    $objData .= pack('vv', 0x00C, 0x0014);
2742 3
                    $objData .= pack('H*', '0000000000000000640001000A00000010000100');
2743
                    // Add ftLbsData (List box data) subobject
2744 3
                    $objData .= pack('vv', 0x0013, 0x1FEE);
2745 3
                    $objData .= pack('H*', '00000000010001030000020008005700');
2746
                } else {
2747
                    // Add ftCmo (common object data) subobject
2748
                    $objData .=
2749 7
                        pack(
2750 7
                            'vvvvvVVV',
2751 7
                            0x0015, // 0x0015 = ftCmo
2752 7
                            0x0012, // length of ftCmo data
2753 7
                            0x0008, // object type, 0x0008 = picture
2754
                            $i, // object id number, Excel seems to use 1-based index, local for the sheet
2755 7
                            0x6011, // option flags, 0x6011 is what OpenOffice.org uses
2756 7
                            0, // reserved
2757 7
                            0, // reserved
2758 7
                            0  // reserved
2759
                        );
2760
                }
2761
2762
                // ftEnd
2763
                $objData .=
2764 10
                    pack(
2765 10
                        'vv',
2766 10
                        0x0000, // 0x0000 = ftEnd
2767 10
                        0x0000  // length of ftEnd data
2768
                    );
2769
2770 10
                $length = strlen($objData);
2771 10
                $header = pack('vv', $record, $length);
2772 10
                $this->append($header . $objData);
2773
            }
2774
        }
2775 38
    }
2776
2777
    /**
2778
     * Store the DATAVALIDATIONS and DATAVALIDATION records.
2779
     */
2780 38
    private function writeDataValidity()
2781
    {
2782
        // Datavalidation collection
2783 38
        $dataValidationCollection = $this->phpSheet->getDataValidationCollection();
2784
2785
        // Write data validations?
2786 38
        if (!empty($dataValidationCollection)) {
2787
            // DATAVALIDATIONS record
2788 2
            $record = 0x01B2; // Record identifier
2789 2
            $length = 0x0012; // Bytes to follow
2790
2791 2
            $grbit = 0x0000; // Prompt box at cell, no cached validity data at DV records
2792 2
            $horPos = 0x00000000; // Horizontal position of prompt box, if fixed position
2793 2
            $verPos = 0x00000000; // Vertical position of prompt box, if fixed position
2794 2
            $objId = 0xFFFFFFFF; // Object identifier of drop down arrow object, or -1 if not visible
2795
2796 2
            $header = pack('vv', $record, $length);
2797 2
            $data = pack('vVVVV', $grbit, $horPos, $verPos, $objId, count($dataValidationCollection));
2798 2
            $this->append($header . $data);
2799
2800
            // DATAVALIDATION records
2801 2
            $record = 0x01BE; // Record identifier
2802
2803 2
            foreach ($dataValidationCollection as $cellCoordinate => $dataValidation) {
2804
                // initialize record data
2805 2
                $data = '';
0 ignored issues
show
Unused Code introduced by
$data 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...
2806
2807
                // options
2808 2
                $options = 0x00000000;
2809
2810
                // data type
2811 2
                $type = $dataValidation->getType();
2812 View Code Duplication
                switch ($type) {
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...
2813 2
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_NONE:
2814
                        $type = 0x00;
2815
                        break;
2816 2
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_WHOLE:
2817 1
                        $type = 0x01;
2818 1
                        break;
2819 2
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_DECIMAL:
2820
                        $type = 0x02;
2821
                        break;
2822 2
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_LIST:
2823 2
                        $type = 0x03;
2824 2
                        break;
2825
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_DATE:
2826
                        $type = 0x04;
2827
                        break;
2828
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_TIME:
2829
                        $type = 0x05;
2830
                        break;
2831
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_TEXTLENGTH:
2832
                        $type = 0x06;
2833
                        break;
2834
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_CUSTOM:
2835
                        $type = 0x07;
2836
                        break;
2837
                }
2838 2
                $options |= $type << 0;
2839
2840
                // error style
2841 2
                $errorStyle = $dataValidation->getType();
2842 View Code Duplication
                switch ($errorStyle) {
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...
2843 2
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::STYLE_STOP:
2844
                        $errorStyle = 0x00;
2845
                        break;
2846 2
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::STYLE_WARNING:
2847
                        $errorStyle = 0x01;
2848
                        break;
2849 2
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::STYLE_INFORMATION:
2850
                        $errorStyle = 0x02;
2851
                        break;
2852
                }
2853 2
                $options |= $errorStyle << 4;
2854
2855
                // explicit formula?
2856 2
                if ($type == 0x03 && preg_match('/^\".*\"$/', $dataValidation->getFormula1())) {
2857 1
                    $options |= 0x01 << 7;
2858
                }
2859
2860
                // empty cells allowed
2861 2
                $options |= $dataValidation->getAllowBlank() << 8;
2862
2863
                // show drop down
2864 2
                $options |= (!$dataValidation->getShowDropDown()) << 9;
2865
2866
                // show input message
2867 2
                $options |= $dataValidation->getShowInputMessage() << 18;
2868
2869
                // show error message
2870 2
                $options |= $dataValidation->getShowErrorMessage() << 19;
2871
2872
                // condition operator
2873 2
                $operator = $dataValidation->getOperator();
2874 View Code Duplication
                switch ($operator) {
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...
2875 2
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::OPERATOR_BETWEEN:
2876
                        $operator = 0x00;
2877
                        break;
2878 2
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::OPERATOR_NOTBETWEEN:
2879
                        $operator = 0x01;
2880
                        break;
2881 2
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::OPERATOR_EQUAL:
2882
                        $operator = 0x02;
2883
                        break;
2884 2
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::OPERATOR_NOTEQUAL:
2885
                        $operator = 0x03;
2886
                        break;
2887 2
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::OPERATOR_GREATERTHAN:
2888
                        $operator = 0x04;
2889
                        break;
2890 2
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::OPERATOR_LESSTHAN:
2891
                        $operator = 0x05;
2892
                        break;
2893 2
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::OPERATOR_GREATERTHANOREQUAL:
2894
                        $operator = 0x06;
2895
                        break;
2896 2
                    case \PhpOffice\PhpSpreadsheet\Cell\DataValidation::OPERATOR_LESSTHANOREQUAL:
2897
                        $operator = 0x07;
2898
                        break;
2899
                }
2900 2
                $options |= $operator << 20;
2901
2902 2
                $data = pack('V', $options);
2903
2904
                // prompt title
2905 2
                $promptTitle = $dataValidation->getPromptTitle() !== '' ?
2906 2
                    $dataValidation->getPromptTitle() : chr(0);
2907 2
                $data .= \PhpOffice\PhpSpreadsheet\Shared\StringHelper::UTF8toBIFF8UnicodeLong($promptTitle);
2908
2909
                // error title
2910 2
                $errorTitle = $dataValidation->getErrorTitle() !== '' ?
2911 2
                    $dataValidation->getErrorTitle() : chr(0);
2912 2
                $data .= \PhpOffice\PhpSpreadsheet\Shared\StringHelper::UTF8toBIFF8UnicodeLong($errorTitle);
2913
2914
                // prompt text
2915 2
                $prompt = $dataValidation->getPrompt() !== '' ?
2916 2
                    $dataValidation->getPrompt() : chr(0);
2917 2
                $data .= \PhpOffice\PhpSpreadsheet\Shared\StringHelper::UTF8toBIFF8UnicodeLong($prompt);
2918
2919
                // error text
2920 2
                $error = $dataValidation->getError() !== '' ?
2921 2
                    $dataValidation->getError() : chr(0);
2922 2
                $data .= \PhpOffice\PhpSpreadsheet\Shared\StringHelper::UTF8toBIFF8UnicodeLong($error);
2923
2924
                // formula 1
2925
                try {
2926 2
                    $formula1 = $dataValidation->getFormula1();
2927 2
                    if ($type == 0x03) { // list type
2928 2
                        $formula1 = str_replace(',', chr(0), $formula1);
2929
                    }
2930 2
                    $this->parser->parse($formula1);
2931 1
                    $formula1 = $this->parser->toReversePolish();
2932 1
                    $sz1 = strlen($formula1);
2933 2
                } catch (\PhpOffice\PhpSpreadsheet\Exception $e) {
2934 2
                    $sz1 = 0;
2935 2
                    $formula1 = '';
2936
                }
2937 2
                $data .= pack('vv', $sz1, 0x0000);
2938 2
                $data .= $formula1;
2939
2940
                // formula 2
2941
                try {
2942 2
                    $formula2 = $dataValidation->getFormula2();
2943 2
                    if ($formula2 === '') {
2944 2
                        throw new \PhpOffice\PhpSpreadsheet\Writer\Exception('No formula2');
2945
                    }
2946 1
                    $this->parser->parse($formula2);
2947
                    $formula2 = $this->parser->toReversePolish();
2948
                    $sz2 = strlen($formula2);
2949 2
                } catch (\PhpOffice\PhpSpreadsheet\Exception $e) {
2950 2
                    $sz2 = 0;
2951 2
                    $formula2 = '';
2952
                }
2953 2
                $data .= pack('vv', $sz2, 0x0000);
2954 2
                $data .= $formula2;
2955
2956
                // cell range address list
2957 2
                $data .= pack('v', 0x0001);
2958 2
                $data .= $this->writeBIFF8CellRangeAddressFixed($cellCoordinate);
2959
2960 2
                $length = strlen($data);
2961 2
                $header = pack('vv', $record, $length);
2962
2963 2
                $this->append($header . $data);
2964
            }
2965
        }
2966 38
    }
2967
2968
    /**
2969
     * Map Error code.
2970
     *
2971
     * @param string $errorCode
2972
     *
2973
     * @return int
2974
     */
2975 4
    private static function mapErrorCode($errorCode)
2976
    {
2977
        switch ($errorCode) {
2978 4
            case '#NULL!':
2979
                return 0x00;
2980 4
            case '#DIV/0!':
2981 3
                return 0x07;
2982 2
            case '#VALUE!':
2983 1
                return 0x0F;
2984 1
            case '#REF!':
2985
                return 0x17;
2986 1
            case '#NAME?':
2987
                return 0x1D;
2988 1
            case '#NUM!':
2989
                return 0x24;
2990 1
            case '#N/A':
2991 1
                return 0x2A;
2992
        }
2993
2994
        return 0;
2995
    }
2996
2997
    /**
2998
     * Write PLV Record.
2999
     */
3000 38
    private function writePageLayoutView()
3001
    {
3002 38
        $record = 0x088B; // Record identifier
3003 38
        $length = 0x0010; // Bytes to follow
3004
3005 38
        $rt = 0x088B; // 2
3006 38
        $grbitFrt = 0x0000; // 2
3007 38
        $reserved = 0x0000000000000000; // 8
0 ignored issues
show
Unused Code introduced by
$reserved 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...
3008 38
        $wScalvePLV = $this->phpSheet->getSheetView()->getZoomScale(); // 2
3009
3010
        // The options flags that comprise $grbit
3011 38
        if ($this->phpSheet->getSheetView()->getView() == \PhpOffice\PhpSpreadsheet\Worksheet\SheetView::SHEETVIEW_PAGE_LAYOUT) {
3012 1
            $fPageLayoutView = 1;
3013
        } else {
3014 37
            $fPageLayoutView = 0;
3015
        }
3016 38
        $fRulerVisible = 0;
3017 38
        $fWhitespaceHidden = 0;
3018
3019 38
        $grbit = $fPageLayoutView; // 2
3020 38
        $grbit |= $fRulerVisible << 1;
3021 38
        $grbit |= $fWhitespaceHidden << 3;
3022
3023 38
        $header = pack('vv', $record, $length);
3024 38
        $data = pack('vvVVvv', $rt, $grbitFrt, 0x00000000, 0x00000000, $wScalvePLV, $grbit);
3025 38
        $this->append($header . $data);
3026 38
    }
3027
3028
    /**
3029
     * Write CFRule Record.
3030
     *
3031
     * @param \PhpOffice\PhpSpreadsheet\Style\Conditional $conditional
3032
     */
3033 2
    private function writeCFRule(\PhpOffice\PhpSpreadsheet\Style\Conditional $conditional)
3034
    {
3035 2
        $record = 0x01B1; // Record identifier
3036
3037
        // $type : Type of the CF
3038
        // $operatorType : Comparison operator
3039 2
        if ($conditional->getConditionType() == \PhpOffice\PhpSpreadsheet\Style\Conditional::CONDITION_EXPRESSION) {
3040
            $type = 0x02;
3041
            $operatorType = 0x00;
3042 2
        } elseif ($conditional->getConditionType() == \PhpOffice\PhpSpreadsheet\Style\Conditional::CONDITION_CELLIS) {
3043 2
            $type = 0x01;
3044
3045 2
            switch ($conditional->getOperatorType()) {
3046 2
                case \PhpOffice\PhpSpreadsheet\Style\Conditional::OPERATOR_NONE:
3047
                    $operatorType = 0x00;
3048
                    break;
3049 2
                case \PhpOffice\PhpSpreadsheet\Style\Conditional::OPERATOR_EQUAL:
3050
                    $operatorType = 0x03;
3051
                    break;
3052 2
                case \PhpOffice\PhpSpreadsheet\Style\Conditional::OPERATOR_GREATERTHAN:
3053
                    $operatorType = 0x05;
3054
                    break;
3055 2
                case \PhpOffice\PhpSpreadsheet\Style\Conditional::OPERATOR_GREATERTHANOREQUAL:
3056 2
                    $operatorType = 0x07;
3057 2
                    break;
3058 2
                case \PhpOffice\PhpSpreadsheet\Style\Conditional::OPERATOR_LESSTHAN:
3059 2
                    $operatorType = 0x06;
3060 2
                    break;
3061 1
                case \PhpOffice\PhpSpreadsheet\Style\Conditional::OPERATOR_LESSTHANOREQUAL:
3062
                    $operatorType = 0x08;
3063
                    break;
3064 1
                case \PhpOffice\PhpSpreadsheet\Style\Conditional::OPERATOR_NOTEQUAL:
3065
                    $operatorType = 0x04;
3066
                    break;
3067 1
                case \PhpOffice\PhpSpreadsheet\Style\Conditional::OPERATOR_BETWEEN:
3068 1
                    $operatorType = 0x01;
3069 1
                    break;
3070
                    // not OPERATOR_NOTBETWEEN 0x02
3071
            }
3072
        }
3073
3074
        // $szValue1 : size of the formula data for first value or formula
3075
        // $szValue2 : size of the formula data for second value or formula
3076 2
        $arrConditions = $conditional->getConditions();
3077 2
        $numConditions = count($arrConditions);
3078 2
        if ($numConditions == 1) {
3079 2
            $szValue1 = ($arrConditions[0] <= 65535 ? 3 : 0x0000);
3080 2
            $szValue2 = 0x0000;
3081 2
            $operand1 = pack('Cv', 0x1E, $arrConditions[0]);
3082 2
            $operand2 = null;
3083 1
        } elseif ($numConditions == 2 && ($conditional->getOperatorType() == \PhpOffice\PhpSpreadsheet\Style\Conditional::OPERATOR_BETWEEN)) {
3084 1
            $szValue1 = ($arrConditions[0] <= 65535 ? 3 : 0x0000);
3085 1
            $szValue2 = ($arrConditions[1] <= 65535 ? 3 : 0x0000);
3086 1
            $operand1 = pack('Cv', 0x1E, $arrConditions[0]);
3087 1
            $operand2 = pack('Cv', 0x1E, $arrConditions[1]);
3088
        } else {
3089
            $szValue1 = 0x0000;
3090
            $szValue2 = 0x0000;
3091
            $operand1 = null;
3092
            $operand2 = null;
3093
        }
3094
3095
        // $flags : Option flags
3096
        // Alignment
3097 2
        $bAlignHz = ($conditional->getStyle()->getAlignment()->getHorizontal() == null ? 1 : 0);
3098 2
        $bAlignVt = ($conditional->getStyle()->getAlignment()->getVertical() == null ? 1 : 0);
3099 2
        $bAlignWrapTx = ($conditional->getStyle()->getAlignment()->getWrapText() == false ? 1 : 0);
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
3100 2
        $bTxRotation = ($conditional->getStyle()->getAlignment()->getTextRotation() == null ? 1 : 0);
3101 2
        $bIndent = ($conditional->getStyle()->getAlignment()->getIndent() == 0 ? 1 : 0);
3102 2
        $bShrinkToFit = ($conditional->getStyle()->getAlignment()->getShrinkToFit() == false ? 1 : 0);
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
3103 2
        if ($bAlignHz == 0 || $bAlignVt == 0 || $bAlignWrapTx == 0 || $bTxRotation == 0 || $bIndent == 0 || $bShrinkToFit == 0) {
3104
            $bFormatAlign = 1;
3105
        } else {
3106 2
            $bFormatAlign = 0;
3107
        }
3108
        // Protection
3109 2
        $bProtLocked = ($conditional->getStyle()->getProtection()->getLocked() == null ? 1 : 0);
3110 2
        $bProtHidden = ($conditional->getStyle()->getProtection()->getHidden() == null ? 1 : 0);
3111 2
        if ($bProtLocked == 0 || $bProtHidden == 0) {
3112
            $bFormatProt = 1;
3113
        } else {
3114 2
            $bFormatProt = 0;
3115
        }
3116
        // Border
3117 2
        $bBorderLeft = ($conditional->getStyle()->getBorders()->getLeft()->getColor()->getARGB() == \PhpOffice\PhpSpreadsheet\Style\Color::COLOR_BLACK
3118 2
                        && $conditional->getStyle()->getBorders()->getLeft()->getBorderStyle() == \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_NONE ? 1 : 0);
3119 2
        $bBorderRight = ($conditional->getStyle()->getBorders()->getRight()->getColor()->getARGB() == \PhpOffice\PhpSpreadsheet\Style\Color::COLOR_BLACK
3120 2
                        && $conditional->getStyle()->getBorders()->getRight()->getBorderStyle() == \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_NONE ? 1 : 0);
3121 2
        $bBorderTop = ($conditional->getStyle()->getBorders()->getTop()->getColor()->getARGB() == \PhpOffice\PhpSpreadsheet\Style\Color::COLOR_BLACK
3122 2
                        && $conditional->getStyle()->getBorders()->getTop()->getBorderStyle() == \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_NONE ? 1 : 0);
3123 2
        $bBorderBottom = ($conditional->getStyle()->getBorders()->getBottom()->getColor()->getARGB() == \PhpOffice\PhpSpreadsheet\Style\Color::COLOR_BLACK
3124 2
                        && $conditional->getStyle()->getBorders()->getBottom()->getBorderStyle() == \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_NONE ? 1 : 0);
3125 2
        if ($bBorderLeft == 0 || $bBorderRight == 0 || $bBorderTop == 0 || $bBorderBottom == 0) {
3126
            $bFormatBorder = 1;
3127
        } else {
3128 2
            $bFormatBorder = 0;
3129
        }
3130
        // Pattern
3131 2
        $bFillStyle = ($conditional->getStyle()->getFill()->getFillType() == null ? 0 : 1);
3132 2
        $bFillColor = ($conditional->getStyle()->getFill()->getStartColor()->getARGB() == null ? 0 : 1);
3133 2
        $bFillColorBg = ($conditional->getStyle()->getFill()->getEndColor()->getARGB() == null ? 0 : 1);
3134 2
        if ($bFillStyle == 0 || $bFillColor == 0 || $bFillColorBg == 0) {
3135 2
            $bFormatFill = 1;
3136
        } else {
3137
            $bFormatFill = 0;
3138
        }
3139
        // Font
3140 2
        if ($conditional->getStyle()->getFont()->getName() != null
3141 2
            || $conditional->getStyle()->getFont()->getSize() != null
3142 2
            || $conditional->getStyle()->getFont()->getBold() != null
3143 2
            || $conditional->getStyle()->getFont()->getItalic() != null
3144 1
            || $conditional->getStyle()->getFont()->getSuperScript() != null
3145 1
            || $conditional->getStyle()->getFont()->getSubScript() != null
3146 1
            || $conditional->getStyle()->getFont()->getUnderline() != null
3147 1
            || $conditional->getStyle()->getFont()->getStrikethrough() != null
3148 2
            || $conditional->getStyle()->getFont()->getColor()->getARGB() != null) {
3149 2
            $bFormatFont = 1;
3150
        } else {
3151
            $bFormatFont = 0;
3152
        }
3153
        // Alignment
3154 2
        $flags = 0;
3155 2
        $flags |= (1 == $bAlignHz ? 0x00000001 : 0);
3156 2
        $flags |= (1 == $bAlignVt ? 0x00000002 : 0);
3157 2
        $flags |= (1 == $bAlignWrapTx ? 0x00000004 : 0);
3158 2
        $flags |= (1 == $bTxRotation ? 0x00000008 : 0);
3159
        // Justify last line flag
3160 2
        $flags |= (1 == 1 ? 0x00000010 : 0);
3161 2
        $flags |= (1 == $bIndent ? 0x00000020 : 0);
3162 2
        $flags |= (1 == $bShrinkToFit ? 0x00000040 : 0);
3163
        // Default
3164 2
        $flags |= (1 == 1 ? 0x00000080 : 0);
3165
        // Protection
3166 2
        $flags |= (1 == $bProtLocked ? 0x00000100 : 0);
3167 2
        $flags |= (1 == $bProtHidden ? 0x00000200 : 0);
3168
        // Border
3169 2
        $flags |= (1 == $bBorderLeft ? 0x00000400 : 0);
3170 2
        $flags |= (1 == $bBorderRight ? 0x00000800 : 0);
3171 2
        $flags |= (1 == $bBorderTop ? 0x00001000 : 0);
3172 2
        $flags |= (1 == $bBorderBottom ? 0x00002000 : 0);
3173 2
        $flags |= (1 == 1 ? 0x00004000 : 0); // Top left to Bottom right border
3174 2
        $flags |= (1 == 1 ? 0x00008000 : 0); // Bottom left to Top right border
3175
        // Pattern
3176 2
        $flags |= (1 == $bFillStyle ? 0x00010000 : 0);
3177 2
        $flags |= (1 == $bFillColor ? 0x00020000 : 0);
3178 2
        $flags |= (1 == $bFillColorBg ? 0x00040000 : 0);
3179 2
        $flags |= (1 == 1 ? 0x00380000 : 0);
3180
        // Font
3181 2
        $flags |= (1 == $bFormatFont ? 0x04000000 : 0);
3182
        // Alignment:
3183 2
        $flags |= (1 == $bFormatAlign ? 0x08000000 : 0);
3184
        // Border
3185 2
        $flags |= (1 == $bFormatBorder ? 0x10000000 : 0);
3186
        // Pattern
3187 2
        $flags |= (1 == $bFormatFill ? 0x20000000 : 0);
3188
        // Protection
3189 2
        $flags |= (1 == $bFormatProt ? 0x40000000 : 0);
3190
        // Text direction
3191 2
        $flags |= (1 == 0 ? 0x80000000 : 0);
3192
3193
        // Data Blocks
3194 2
        if ($bFormatFont == 1) {
3195
            // Font Name
3196 2
            if ($conditional->getStyle()->getFont()->getName() == null) {
3197 2
                $dataBlockFont = pack('VVVVVVVV', 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
3198 2
                $dataBlockFont .= pack('VVVVVVVV', 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
3199
            } else {
3200
                $dataBlockFont = \PhpOffice\PhpSpreadsheet\Shared\StringHelper::UTF8toBIFF8UnicodeLong($conditional->getStyle()->getFont()->getName());
3201
            }
3202
            // Font Size
3203 2
            if ($conditional->getStyle()->getFont()->getSize() == null) {
3204 2
                $dataBlockFont .= pack('V', 20 * 11);
3205
            } else {
3206
                $dataBlockFont .= pack('V', 20 * $conditional->getStyle()->getFont()->getSize());
3207
            }
3208
            // Font Options
3209 2
            $dataBlockFont .= pack('V', 0);
3210
            // Font weight
3211 2
            if ($conditional->getStyle()->getFont()->getBold() == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
3212 1
                $dataBlockFont .= pack('v', 0x02BC);
3213
            } else {
3214 2
                $dataBlockFont .= pack('v', 0x0190);
3215
            }
3216
            // Escapement type
3217 2
            if ($conditional->getStyle()->getFont()->getSubScript() == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
3218
                $dataBlockFont .= pack('v', 0x02);
3219
                $fontEscapement = 0;
3220 2
            } elseif ($conditional->getStyle()->getFont()->getSuperScript() == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
3221
                $dataBlockFont .= pack('v', 0x01);
3222
                $fontEscapement = 0;
3223
            } else {
3224 2
                $dataBlockFont .= pack('v', 0x00);
3225 2
                $fontEscapement = 1;
3226
            }
3227
            // Underline type
3228 2
            switch ($conditional->getStyle()->getFont()->getUnderline()) {
3229 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_NONE:
3230
                    $dataBlockFont .= pack('C', 0x00);
3231
                    $fontUnderline = 0;
3232
                    break;
3233 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_DOUBLE:
3234
                    $dataBlockFont .= pack('C', 0x02);
3235
                    $fontUnderline = 0;
3236
                    break;
3237 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_DOUBLEACCOUNTING:
3238
                    $dataBlockFont .= pack('C', 0x22);
3239
                    $fontUnderline = 0;
3240
                    break;
3241 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_SINGLE:
3242
                    $dataBlockFont .= pack('C', 0x01);
3243
                    $fontUnderline = 0;
3244
                    break;
3245 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_SINGLEACCOUNTING:
3246
                    $dataBlockFont .= pack('C', 0x21);
3247
                    $fontUnderline = 0;
3248
                    break;
3249
                default:
3250 2
                    $dataBlockFont .= pack('C', 0x00);
3251 2
                    $fontUnderline = 1;
3252 2
                    break;
3253
            }
3254
            // Not used (3)
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% 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...
3255 2
            $dataBlockFont .= pack('vC', 0x0000, 0x00);
3256
            // Font color index
3257 2 View Code Duplication
            switch ($conditional->getStyle()->getFont()->getColor()->getRGB()) {
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...
3258 2
                case '000000':
3259
                    $colorIdx = 0x08;
3260
                    break;
3261 2
                case 'FFFFFF':
3262
                    $colorIdx = 0x09;
3263
                    break;
3264 2
                case 'FF0000':
3265 2
                    $colorIdx = 0x0A;
3266 2
                    break;
3267 2
                case '00FF00':
3268 2
                    $colorIdx = 0x0B;
3269 2
                    break;
3270 1
                case '0000FF':
3271
                    $colorIdx = 0x0C;
3272
                    break;
3273 1
                case 'FFFF00':
3274 1
                    $colorIdx = 0x0D;
3275 1
                    break;
3276
                case 'FF00FF':
3277
                    $colorIdx = 0x0E;
3278
                    break;
3279
                case '00FFFF':
3280
                    $colorIdx = 0x0F;
3281
                    break;
3282
                case '800000':
3283
                    $colorIdx = 0x10;
3284
                    break;
3285
                case '008000':
3286
                    $colorIdx = 0x11;
3287
                    break;
3288
                case '000080':
3289
                    $colorIdx = 0x12;
3290
                    break;
3291
                case '808000':
3292
                    $colorIdx = 0x13;
3293
                    break;
3294
                case '800080':
3295
                    $colorIdx = 0x14;
3296
                    break;
3297
                case '008080':
3298
                    $colorIdx = 0x15;
3299
                    break;
3300
                case 'C0C0C0':
3301
                    $colorIdx = 0x16;
3302
                    break;
3303
                case '808080':
3304
                    $colorIdx = 0x17;
3305
                    break;
3306
                case '9999FF':
3307
                    $colorIdx = 0x18;
3308
                    break;
3309
                case '993366':
3310
                    $colorIdx = 0x19;
3311
                    break;
3312
                case 'FFFFCC':
3313
                    $colorIdx = 0x1A;
3314
                    break;
3315
                case 'CCFFFF':
3316
                    $colorIdx = 0x1B;
3317
                    break;
3318
                case '660066':
3319
                    $colorIdx = 0x1C;
3320
                    break;
3321
                case 'FF8080':
3322
                    $colorIdx = 0x1D;
3323
                    break;
3324
                case '0066CC':
3325
                    $colorIdx = 0x1E;
3326
                    break;
3327
                case 'CCCCFF':
3328
                    $colorIdx = 0x1F;
3329
                    break;
3330
                case '000080':
3331
                    $colorIdx = 0x20;
3332
                    break;
3333
                case 'FF00FF':
3334
                    $colorIdx = 0x21;
3335
                    break;
3336
                case 'FFFF00':
3337
                    $colorIdx = 0x22;
3338
                    break;
3339
                case '00FFFF':
3340
                    $colorIdx = 0x23;
3341
                    break;
3342
                case '800080':
3343
                    $colorIdx = 0x24;
3344
                    break;
3345
                case '800000':
3346
                    $colorIdx = 0x25;
3347
                    break;
3348
                case '008080':
3349
                    $colorIdx = 0x26;
3350
                    break;
3351
                case '0000FF':
3352
                    $colorIdx = 0x27;
3353
                    break;
3354
                case '00CCFF':
3355
                    $colorIdx = 0x28;
3356
                    break;
3357
                case 'CCFFFF':
3358
                    $colorIdx = 0x29;
3359
                    break;
3360
                case 'CCFFCC':
3361
                    $colorIdx = 0x2A;
3362
                    break;
3363
                case 'FFFF99':
3364
                    $colorIdx = 0x2B;
3365
                    break;
3366
                case '99CCFF':
3367
                    $colorIdx = 0x2C;
3368
                    break;
3369
                case 'FF99CC':
3370
                    $colorIdx = 0x2D;
3371
                    break;
3372
                case 'CC99FF':
3373
                    $colorIdx = 0x2E;
3374
                    break;
3375
                case 'FFCC99':
3376
                    $colorIdx = 0x2F;
3377
                    break;
3378
                case '3366FF':
3379
                    $colorIdx = 0x30;
3380
                    break;
3381
                case '33CCCC':
3382
                    $colorIdx = 0x31;
3383
                    break;
3384
                case '99CC00':
3385
                    $colorIdx = 0x32;
3386
                    break;
3387
                case 'FFCC00':
3388
                    $colorIdx = 0x33;
3389
                    break;
3390
                case 'FF9900':
3391
                    $colorIdx = 0x34;
3392
                    break;
3393
                case 'FF6600':
3394
                    $colorIdx = 0x35;
3395
                    break;
3396
                case '666699':
3397
                    $colorIdx = 0x36;
3398
                    break;
3399
                case '969696':
3400
                    $colorIdx = 0x37;
3401
                    break;
3402
                case '003366':
3403
                    $colorIdx = 0x38;
3404
                    break;
3405
                case '339966':
3406
                    $colorIdx = 0x39;
3407
                    break;
3408
                case '003300':
3409
                    $colorIdx = 0x3A;
3410
                    break;
3411
                case '333300':
3412
                    $colorIdx = 0x3B;
3413
                    break;
3414
                case '993300':
3415
                    $colorIdx = 0x3C;
3416
                    break;
3417
                case '993366':
3418
                    $colorIdx = 0x3D;
3419
                    break;
3420
                case '333399':
3421
                    $colorIdx = 0x3E;
3422
                    break;
3423
                case '333333':
3424
                    $colorIdx = 0x3F;
3425
                    break;
3426
                default:
3427
                    $colorIdx = 0x00;
3428
                    break;
3429
            }
3430 2
            $dataBlockFont .= pack('V', $colorIdx);
3431
            // Not used (4)
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% 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...
3432 2
            $dataBlockFont .= pack('V', 0x00000000);
3433
            // Options flags for modified font attributes
3434 2
            $optionsFlags = 0;
3435 2
            $optionsFlagsBold = ($conditional->getStyle()->getFont()->getBold() == null ? 1 : 0);
3436 2
            $optionsFlags |= (1 == $optionsFlagsBold ? 0x00000002 : 0);
3437 2
            $optionsFlags |= (1 == 1 ? 0x00000008 : 0);
3438 2
            $optionsFlags |= (1 == 1 ? 0x00000010 : 0);
3439 2
            $optionsFlags |= (1 == 0 ? 0x00000020 : 0);
3440 2
            $optionsFlags |= (1 == 1 ? 0x00000080 : 0);
3441 2
            $dataBlockFont .= pack('V', $optionsFlags);
3442
            // Escapement type
3443 2
            $dataBlockFont .= pack('V', $fontEscapement);
3444
            // Underline type
3445 2
            $dataBlockFont .= pack('V', $fontUnderline);
3446
            // Always
3447 2
            $dataBlockFont .= pack('V', 0x00000000);
3448
            // Always
3449 2
            $dataBlockFont .= pack('V', 0x00000000);
3450
            // Not used (8)
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% 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...
3451 2
            $dataBlockFont .= pack('VV', 0x00000000, 0x00000000);
3452
            // Always
3453 2
            $dataBlockFont .= pack('v', 0x0001);
3454
        }
3455 2
        if ($bFormatAlign == 1) {
3456
            $blockAlign = 0;
3457
            // Alignment and text break
3458
            switch ($conditional->getStyle()->getAlignment()->getHorizontal()) {
3459
                case \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_GENERAL:
3460
                    $blockAlign = 0;
3461
                    break;
3462
                case \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_LEFT:
3463
                    $blockAlign = 1;
3464
                    break;
3465
                case \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_RIGHT:
3466
                    $blockAlign = 3;
3467
                    break;
3468
                case \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER:
3469
                    $blockAlign = 2;
3470
                    break;
3471
                case \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER_CONTINUOUS:
3472
                    $blockAlign = 6;
3473
                    break;
3474
                case \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_JUSTIFY:
3475
                    $blockAlign = 5;
3476
                    break;
3477
            }
3478
            if ($conditional->getStyle()->getAlignment()->getWrapText() == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
3479
                $blockAlign |= 1 << 3;
3480
            } else {
3481
                $blockAlign |= 0 << 3;
3482
            }
3483
            switch ($conditional->getStyle()->getAlignment()->getVertical()) {
3484
                case \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_BOTTOM:
3485
                    $blockAlign = 2 << 4;
3486
                    break;
3487
                case \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_TOP:
3488
                    $blockAlign = 0 << 4;
3489
                    break;
3490
                case \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER:
3491
                    $blockAlign = 1 << 4;
3492
                    break;
3493
                case \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_JUSTIFY:
3494
                    $blockAlign = 3 << 4;
3495
                    break;
3496
            }
3497
            $blockAlign |= 0 << 7;
3498
3499
            // Text rotation angle
3500
            $blockRotation = $conditional->getStyle()->getAlignment()->getTextRotation();
3501
3502
            // Indentation
3503
            $blockIndent = $conditional->getStyle()->getAlignment()->getIndent();
3504
            if ($conditional->getStyle()->getAlignment()->getShrinkToFit() == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
3505
                $blockIndent |= 1 << 4;
3506
            } else {
3507
                $blockIndent |= 0 << 4;
3508
            }
3509
            $blockIndent |= 0 << 6;
3510
3511
            // Relative indentation
3512
            $blockIndentRelative = 255;
3513
3514
            $dataBlockAlign = pack('CCvvv', $blockAlign, $blockRotation, $blockIndent, $blockIndentRelative, 0x0000);
3515
        }
3516 2
        if ($bFormatBorder == 1) {
3517
            $blockLineStyle = 0;
3518
            switch ($conditional->getStyle()->getBorders()->getLeft()->getBorderStyle()) {
3519
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_NONE:
3520
                    $blockLineStyle |= 0x00;
3521
                    break;
3522
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN:
3523
                    $blockLineStyle |= 0x01;
3524
                    break;
3525
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUM:
3526
                    $blockLineStyle |= 0x02;
3527
                    break;
3528
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DASHED:
3529
                    $blockLineStyle |= 0x03;
3530
                    break;
3531
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DOTTED:
3532
                    $blockLineStyle |= 0x04;
3533
                    break;
3534
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THICK:
3535
                    $blockLineStyle |= 0x05;
3536
                    break;
3537
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DOUBLE:
3538
                    $blockLineStyle |= 0x06;
3539
                    break;
3540
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_HAIR:
3541
                    $blockLineStyle |= 0x07;
3542
                    break;
3543
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUMDASHED:
3544
                    $blockLineStyle |= 0x08;
3545
                    break;
3546
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DASHDOT:
3547
                    $blockLineStyle |= 0x09;
3548
                    break;
3549
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUMDASHDOT:
3550
                    $blockLineStyle |= 0x0A;
3551
                    break;
3552
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DASHDOTDOT:
3553
                    $blockLineStyle |= 0x0B;
3554
                    break;
3555
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUMDASHDOTDOT:
3556
                    $blockLineStyle |= 0x0C;
3557
                    break;
3558
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_SLANTDASHDOT:
3559
                    $blockLineStyle |= 0x0D;
3560
                    break;
3561
            }
3562 View Code Duplication
            switch ($conditional->getStyle()->getBorders()->getRight()->getBorderStyle()) {
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...
3563
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_NONE:
3564
                    $blockLineStyle |= 0x00 << 4;
3565
                    break;
3566
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN:
3567
                    $blockLineStyle |= 0x01 << 4;
3568
                    break;
3569
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUM:
3570
                    $blockLineStyle |= 0x02 << 4;
3571
                    break;
3572
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DASHED:
3573
                    $blockLineStyle |= 0x03 << 4;
3574
                    break;
3575
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DOTTED:
3576
                    $blockLineStyle |= 0x04 << 4;
3577
                    break;
3578
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THICK:
3579
                    $blockLineStyle |= 0x05 << 4;
3580
                    break;
3581
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DOUBLE:
3582
                    $blockLineStyle |= 0x06 << 4;
3583
                    break;
3584
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_HAIR:
3585
                    $blockLineStyle |= 0x07 << 4;
3586
                    break;
3587
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUMDASHED:
3588
                    $blockLineStyle |= 0x08 << 4;
3589
                    break;
3590
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DASHDOT:
3591
                    $blockLineStyle |= 0x09 << 4;
3592
                    break;
3593
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUMDASHDOT:
3594
                    $blockLineStyle |= 0x0A << 4;
3595
                    break;
3596
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DASHDOTDOT:
3597
                    $blockLineStyle |= 0x0B << 4;
3598
                    break;
3599
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUMDASHDOTDOT:
3600
                    $blockLineStyle |= 0x0C << 4;
3601
                    break;
3602
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_SLANTDASHDOT:
3603
                    $blockLineStyle |= 0x0D << 4;
3604
                    break;
3605
            }
3606 View Code Duplication
            switch ($conditional->getStyle()->getBorders()->getTop()->getBorderStyle()) {
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...
3607
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_NONE:
3608
                    $blockLineStyle |= 0x00 << 8;
3609
                    break;
3610
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN:
3611
                    $blockLineStyle |= 0x01 << 8;
3612
                    break;
3613
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUM:
3614
                    $blockLineStyle |= 0x02 << 8;
3615
                    break;
3616
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DASHED:
3617
                    $blockLineStyle |= 0x03 << 8;
3618
                    break;
3619
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DOTTED:
3620
                    $blockLineStyle |= 0x04 << 8;
3621
                    break;
3622
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THICK:
3623
                    $blockLineStyle |= 0x05 << 8;
3624
                    break;
3625
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DOUBLE:
3626
                    $blockLineStyle |= 0x06 << 8;
3627
                    break;
3628
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_HAIR:
3629
                    $blockLineStyle |= 0x07 << 8;
3630
                    break;
3631
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUMDASHED:
3632
                    $blockLineStyle |= 0x08 << 8;
3633
                    break;
3634
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DASHDOT:
3635
                    $blockLineStyle |= 0x09 << 8;
3636
                    break;
3637
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUMDASHDOT:
3638
                    $blockLineStyle |= 0x0A << 8;
3639
                    break;
3640
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DASHDOTDOT:
3641
                    $blockLineStyle |= 0x0B << 8;
3642
                    break;
3643
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUMDASHDOTDOT:
3644
                    $blockLineStyle |= 0x0C << 8;
3645
                    break;
3646
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_SLANTDASHDOT:
3647
                    $blockLineStyle |= 0x0D << 8;
3648
                    break;
3649
            }
3650 View Code Duplication
            switch ($conditional->getStyle()->getBorders()->getBottom()->getBorderStyle()) {
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...
3651
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_NONE:
3652
                    $blockLineStyle |= 0x00 << 12;
3653
                    break;
3654
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN:
3655
                    $blockLineStyle |= 0x01 << 12;
3656
                    break;
3657
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUM:
3658
                    $blockLineStyle |= 0x02 << 12;
3659
                    break;
3660
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DASHED:
3661
                    $blockLineStyle |= 0x03 << 12;
3662
                    break;
3663
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DOTTED:
3664
                    $blockLineStyle |= 0x04 << 12;
3665
                    break;
3666
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THICK:
3667
                    $blockLineStyle |= 0x05 << 12;
3668
                    break;
3669
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DOUBLE:
3670
                    $blockLineStyle |= 0x06 << 12;
3671
                    break;
3672
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_HAIR:
3673
                    $blockLineStyle |= 0x07 << 12;
3674
                    break;
3675
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUMDASHED:
3676
                    $blockLineStyle |= 0x08 << 12;
3677
                    break;
3678
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DASHDOT:
3679
                    $blockLineStyle |= 0x09 << 12;
3680
                    break;
3681
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUMDASHDOT:
3682
                    $blockLineStyle |= 0x0A << 12;
3683
                    break;
3684
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DASHDOTDOT:
3685
                    $blockLineStyle |= 0x0B << 12;
3686
                    break;
3687
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUMDASHDOTDOT:
3688
                    $blockLineStyle |= 0x0C << 12;
3689
                    break;
3690
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_SLANTDASHDOT:
3691
                    $blockLineStyle |= 0x0D << 12;
3692
                    break;
3693
            }
3694
            //@todo writeCFRule() => $blockLineStyle => Index Color for left line
3695
            //@todo writeCFRule() => $blockLineStyle => Index Color for right line
3696
            //@todo writeCFRule() => $blockLineStyle => Top-left to bottom-right on/off
3697
            //@todo writeCFRule() => $blockLineStyle => Bottom-left to top-right on/off
3698
            $blockColor = 0;
3699
            //@todo writeCFRule() => $blockColor => Index Color for top line
3700
            //@todo writeCFRule() => $blockColor => Index Color for bottom line
3701
            //@todo writeCFRule() => $blockColor => Index Color for diagonal line
3702 View Code Duplication
            switch ($conditional->getStyle()->getBorders()->getDiagonal()->getBorderStyle()) {
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...
3703
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_NONE:
3704
                    $blockColor |= 0x00 << 21;
3705
                    break;
3706
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN:
3707
                    $blockColor |= 0x01 << 21;
3708
                    break;
3709
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUM:
3710
                    $blockColor |= 0x02 << 21;
3711
                    break;
3712
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DASHED:
3713
                    $blockColor |= 0x03 << 21;
3714
                    break;
3715
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DOTTED:
3716
                    $blockColor |= 0x04 << 21;
3717
                    break;
3718
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THICK:
3719
                    $blockColor |= 0x05 << 21;
3720
                    break;
3721
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DOUBLE:
3722
                    $blockColor |= 0x06 << 21;
3723
                    break;
3724
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_HAIR:
3725
                    $blockColor |= 0x07 << 21;
3726
                    break;
3727
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUMDASHED:
3728
                    $blockColor |= 0x08 << 21;
3729
                    break;
3730
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DASHDOT:
3731
                    $blockColor |= 0x09 << 21;
3732
                    break;
3733
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUMDASHDOT:
3734
                    $blockColor |= 0x0A << 21;
3735
                    break;
3736
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DASHDOTDOT:
3737
                    $blockColor |= 0x0B << 21;
3738
                    break;
3739
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUMDASHDOTDOT:
3740
                    $blockColor |= 0x0C << 21;
3741
                    break;
3742
                case \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_SLANTDASHDOT:
3743
                    $blockColor |= 0x0D << 21;
3744
                    break;
3745
            }
3746
            $dataBlockBorder = pack('vv', $blockLineStyle, $blockColor);
3747
        }
3748 2
        if ($bFormatFill == 1) {
3749
            // Fill Patern Style
3750 2
            $blockFillPatternStyle = 0;
0 ignored issues
show
Unused Code introduced by
$blockFillPatternStyle 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...
3751 2
            switch ($conditional->getStyle()->getFill()->getFillType()) {
3752 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_NONE:
3753
                    $blockFillPatternStyle = 0x00;
3754
                    break;
3755 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID:
3756
                    $blockFillPatternStyle = 0x01;
3757
                    break;
3758 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_MEDIUMGRAY:
3759
                    $blockFillPatternStyle = 0x02;
3760
                    break;
3761 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_DARKGRAY:
3762
                    $blockFillPatternStyle = 0x03;
3763
                    break;
3764 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_LIGHTGRAY:
3765
                    $blockFillPatternStyle = 0x04;
3766
                    break;
3767 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_DARKHORIZONTAL:
3768
                    $blockFillPatternStyle = 0x05;
3769
                    break;
3770 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_DARKVERTICAL:
3771
                    $blockFillPatternStyle = 0x06;
3772
                    break;
3773 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_DARKDOWN:
3774
                    $blockFillPatternStyle = 0x07;
3775
                    break;
3776 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_DARKUP:
3777
                    $blockFillPatternStyle = 0x08;
3778
                    break;
3779 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_DARKGRID:
3780
                    $blockFillPatternStyle = 0x09;
3781
                    break;
3782 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_DARKTRELLIS:
3783
                    $blockFillPatternStyle = 0x0A;
3784
                    break;
3785 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_LIGHTHORIZONTAL:
3786
                    $blockFillPatternStyle = 0x0B;
3787
                    break;
3788 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_LIGHTVERTICAL:
3789
                    $blockFillPatternStyle = 0x0C;
3790
                    break;
3791 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_LIGHTDOWN:
3792
                    $blockFillPatternStyle = 0x0D;
3793
                    break;
3794 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_LIGHTUP:
3795
                    $blockFillPatternStyle = 0x0E;
3796
                    break;
3797 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_LIGHTGRID:
3798
                    $blockFillPatternStyle = 0x0F;
3799
                    break;
3800 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_LIGHTTRELLIS:
3801
                    $blockFillPatternStyle = 0x10;
3802
                    break;
3803 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_GRAY125:
3804
                    $blockFillPatternStyle = 0x11;
3805
                    break;
3806 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_GRAY0625:
3807
                    $blockFillPatternStyle = 0x12;
3808
                    break;
3809 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_GRADIENT_LINEAR:
3810
                    $blockFillPatternStyle = 0x00;
3811
                    break; // does not exist in BIFF8
3812 2
                case \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_GRADIENT_PATH:
3813
                    $blockFillPatternStyle = 0x00;
3814
                    break; // does not exist in BIFF8
3815
                default:
3816 2
                    $blockFillPatternStyle = 0x00;
3817 2
                    break;
3818
            }
3819
            // Color
3820 2 View Code Duplication
            switch ($conditional->getStyle()->getFill()->getStartColor()->getRGB()) {
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...
3821 2
                case '000000':
3822
                    $colorIdxBg = 0x08;
3823
                    break;
3824 2
                case 'FFFFFF':
3825
                    $colorIdxBg = 0x09;
3826
                    break;
3827 2
                case 'FF0000':
3828
                    $colorIdxBg = 0x0A;
3829
                    break;
3830 2
                case '00FF00':
3831
                    $colorIdxBg = 0x0B;
3832
                    break;
3833 2
                case '0000FF':
3834
                    $colorIdxBg = 0x0C;
3835
                    break;
3836 2
                case 'FFFF00':
3837
                    $colorIdxBg = 0x0D;
3838
                    break;
3839 2
                case 'FF00FF':
3840
                    $colorIdxBg = 0x0E;
3841
                    break;
3842 2
                case '00FFFF':
3843
                    $colorIdxBg = 0x0F;
3844
                    break;
3845 2
                case '800000':
3846
                    $colorIdxBg = 0x10;
3847
                    break;
3848 2
                case '008000':
3849
                    $colorIdxBg = 0x11;
3850
                    break;
3851 2
                case '000080':
3852
                    $colorIdxBg = 0x12;
3853
                    break;
3854 2
                case '808000':
3855
                    $colorIdxBg = 0x13;
3856
                    break;
3857 2
                case '800080':
3858
                    $colorIdxBg = 0x14;
3859
                    break;
3860 2
                case '008080':
3861
                    $colorIdxBg = 0x15;
3862
                    break;
3863 2
                case 'C0C0C0':
3864
                    $colorIdxBg = 0x16;
3865
                    break;
3866 2
                case '808080':
3867
                    $colorIdxBg = 0x17;
3868
                    break;
3869 2
                case '9999FF':
3870
                    $colorIdxBg = 0x18;
3871
                    break;
3872 2
                case '993366':
3873
                    $colorIdxBg = 0x19;
3874
                    break;
3875 2
                case 'FFFFCC':
3876
                    $colorIdxBg = 0x1A;
3877
                    break;
3878 2
                case 'CCFFFF':
3879
                    $colorIdxBg = 0x1B;
3880
                    break;
3881 2
                case '660066':
3882
                    $colorIdxBg = 0x1C;
3883
                    break;
3884 2
                case 'FF8080':
3885
                    $colorIdxBg = 0x1D;
3886
                    break;
3887 2
                case '0066CC':
3888
                    $colorIdxBg = 0x1E;
3889
                    break;
3890 2
                case 'CCCCFF':
3891
                    $colorIdxBg = 0x1F;
3892
                    break;
3893 2
                case '000080':
3894
                    $colorIdxBg = 0x20;
3895
                    break;
3896 2
                case 'FF00FF':
3897
                    $colorIdxBg = 0x21;
3898
                    break;
3899 2
                case 'FFFF00':
3900
                    $colorIdxBg = 0x22;
3901
                    break;
3902 2
                case '00FFFF':
3903
                    $colorIdxBg = 0x23;
3904
                    break;
3905 2
                case '800080':
3906
                    $colorIdxBg = 0x24;
3907
                    break;
3908 2
                case '800000':
3909
                    $colorIdxBg = 0x25;
3910
                    break;
3911 2
                case '008080':
3912
                    $colorIdxBg = 0x26;
3913
                    break;
3914 2
                case '0000FF':
3915
                    $colorIdxBg = 0x27;
3916
                    break;
3917 2
                case '00CCFF':
3918
                    $colorIdxBg = 0x28;
3919
                    break;
3920 2
                case 'CCFFFF':
3921
                    $colorIdxBg = 0x29;
3922
                    break;
3923 2
                case 'CCFFCC':
3924
                    $colorIdxBg = 0x2A;
3925
                    break;
3926 2
                case 'FFFF99':
3927
                    $colorIdxBg = 0x2B;
3928
                    break;
3929 2
                case '99CCFF':
3930
                    $colorIdxBg = 0x2C;
3931
                    break;
3932 2
                case 'FF99CC':
3933
                    $colorIdxBg = 0x2D;
3934
                    break;
3935 2
                case 'CC99FF':
3936
                    $colorIdxBg = 0x2E;
3937
                    break;
3938 2
                case 'FFCC99':
3939
                    $colorIdxBg = 0x2F;
3940
                    break;
3941 2
                case '3366FF':
3942
                    $colorIdxBg = 0x30;
3943
                    break;
3944 2
                case '33CCCC':
3945
                    $colorIdxBg = 0x31;
3946
                    break;
3947 2
                case '99CC00':
3948
                    $colorIdxBg = 0x32;
3949
                    break;
3950 2
                case 'FFCC00':
3951
                    $colorIdxBg = 0x33;
3952
                    break;
3953 2
                case 'FF9900':
3954
                    $colorIdxBg = 0x34;
3955
                    break;
3956 2
                case 'FF6600':
3957
                    $colorIdxBg = 0x35;
3958
                    break;
3959 2
                case '666699':
3960
                    $colorIdxBg = 0x36;
3961
                    break;
3962 2
                case '969696':
3963
                    $colorIdxBg = 0x37;
3964
                    break;
3965 2
                case '003366':
3966
                    $colorIdxBg = 0x38;
3967
                    break;
3968 2
                case '339966':
3969
                    $colorIdxBg = 0x39;
3970
                    break;
3971 2
                case '003300':
3972
                    $colorIdxBg = 0x3A;
3973
                    break;
3974 2
                case '333300':
3975
                    $colorIdxBg = 0x3B;
3976
                    break;
3977 2
                case '993300':
3978
                    $colorIdxBg = 0x3C;
3979
                    break;
3980 2
                case '993366':
3981
                    $colorIdxBg = 0x3D;
3982
                    break;
3983 2
                case '333399':
3984
                    $colorIdxBg = 0x3E;
3985
                    break;
3986 2
                case '333333':
3987
                    $colorIdxBg = 0x3F;
3988
                    break;
3989
                default:
3990 2
                          $colorIdxBg = 0x41;
3991 2
                    break;
3992
            }
3993
            // Fg Color
3994 2 View Code Duplication
            switch ($conditional->getStyle()->getFill()->getEndColor()->getRGB()) {
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...
3995 2
                case '000000':
3996
                    $colorIdxFg = 0x08;
3997
                    break;
3998 2
                case 'FFFFFF':
3999
                    $colorIdxFg = 0x09;
4000
                    break;
4001 2
                case 'FF0000':
4002
                    $colorIdxFg = 0x0A;
4003
                    break;
4004 2
                case '00FF00':
4005
                    $colorIdxFg = 0x0B;
4006
                    break;
4007 2
                case '0000FF':
4008
                    $colorIdxFg = 0x0C;
4009
                    break;
4010 2
                case 'FFFF00':
4011
                    $colorIdxFg = 0x0D;
4012
                    break;
4013 2
                case 'FF00FF':
4014
                    $colorIdxFg = 0x0E;
4015
                    break;
4016 2
                case '00FFFF':
4017
                    $colorIdxFg = 0x0F;
4018
                    break;
4019 2
                case '800000':
4020
                    $colorIdxFg = 0x10;
4021
                    break;
4022 2
                case '008000':
4023
                    $colorIdxFg = 0x11;
4024
                    break;
4025 2
                case '000080':
4026
                    $colorIdxFg = 0x12;
4027
                    break;
4028 2
                case '808000':
4029
                    $colorIdxFg = 0x13;
4030
                    break;
4031 2
                case '800080':
4032
                    $colorIdxFg = 0x14;
4033
                    break;
4034 2
                case '008080':
4035
                    $colorIdxFg = 0x15;
4036
                    break;
4037 2
                case 'C0C0C0':
4038
                    $colorIdxFg = 0x16;
4039
                    break;
4040 2
                case '808080':
4041
                    $colorIdxFg = 0x17;
4042
                    break;
4043 2
                case '9999FF':
4044
                    $colorIdxFg = 0x18;
4045
                    break;
4046 2
                case '993366':
4047
                    $colorIdxFg = 0x19;
4048
                    break;
4049 2
                case 'FFFFCC':
4050
                    $colorIdxFg = 0x1A;
4051
                    break;
4052 2
                case 'CCFFFF':
4053
                    $colorIdxFg = 0x1B;
4054
                    break;
4055 2
                case '660066':
4056
                    $colorIdxFg = 0x1C;
4057
                    break;
4058 2
                case 'FF8080':
4059
                    $colorIdxFg = 0x1D;
4060
                    break;
4061 2
                case '0066CC':
4062
                    $colorIdxFg = 0x1E;
4063
                    break;
4064 2
                case 'CCCCFF':
4065
                    $colorIdxFg = 0x1F;
4066
                    break;
4067 2
                case '000080':
4068
                    $colorIdxFg = 0x20;
4069
                    break;
4070 2
                case 'FF00FF':
4071
                    $colorIdxFg = 0x21;
4072
                    break;
4073 2
                case 'FFFF00':
4074
                    $colorIdxFg = 0x22;
4075
                    break;
4076 2
                case '00FFFF':
4077
                    $colorIdxFg = 0x23;
4078
                    break;
4079 2
                case '800080':
4080
                    $colorIdxFg = 0x24;
4081
                    break;
4082 2
                case '800000':
4083
                    $colorIdxFg = 0x25;
4084
                    break;
4085 2
                case '008080':
4086
                    $colorIdxFg = 0x26;
4087
                    break;
4088 2
                case '0000FF':
4089
                    $colorIdxFg = 0x27;
4090
                    break;
4091 2
                case '00CCFF':
4092
                    $colorIdxFg = 0x28;
4093
                    break;
4094 2
                case 'CCFFFF':
4095
                    $colorIdxFg = 0x29;
4096
                    break;
4097 2
                case 'CCFFCC':
4098
                    $colorIdxFg = 0x2A;
4099
                    break;
4100 2
                case 'FFFF99':
4101
                    $colorIdxFg = 0x2B;
4102
                    break;
4103 2
                case '99CCFF':
4104
                    $colorIdxFg = 0x2C;
4105
                    break;
4106 2
                case 'FF99CC':
4107
                    $colorIdxFg = 0x2D;
4108
                    break;
4109 2
                case 'CC99FF':
4110
                    $colorIdxFg = 0x2E;
4111
                    break;
4112 2
                case 'FFCC99':
4113
                    $colorIdxFg = 0x2F;
4114
                    break;
4115 2
                case '3366FF':
4116
                    $colorIdxFg = 0x30;
4117
                    break;
4118 2
                case '33CCCC':
4119
                    $colorIdxFg = 0x31;
4120
                    break;
4121 2
                case '99CC00':
4122
                    $colorIdxFg = 0x32;
4123
                    break;
4124 2
                case 'FFCC00':
4125
                    $colorIdxFg = 0x33;
4126
                    break;
4127 2
                case 'FF9900':
4128
                    $colorIdxFg = 0x34;
4129
                    break;
4130 2
                case 'FF6600':
4131
                    $colorIdxFg = 0x35;
4132
                    break;
4133 2
                case '666699':
4134
                    $colorIdxFg = 0x36;
4135
                    break;
4136 2
                case '969696':
4137
                    $colorIdxFg = 0x37;
4138
                    break;
4139 2
                case '003366':
4140
                    $colorIdxFg = 0x38;
4141
                    break;
4142 2
                case '339966':
4143
                    $colorIdxFg = 0x39;
4144
                    break;
4145 2
                case '003300':
4146
                    $colorIdxFg = 0x3A;
4147
                    break;
4148 2
                case '333300':
4149
                    $colorIdxFg = 0x3B;
4150
                    break;
4151 2
                case '993300':
4152
                    $colorIdxFg = 0x3C;
4153
                    break;
4154 2
                case '993366':
4155
                    $colorIdxFg = 0x3D;
4156
                    break;
4157 2
                case '333399':
4158
                    $colorIdxFg = 0x3E;
4159
                    break;
4160 2
                case '333333':
4161
                    $colorIdxFg = 0x3F;
4162
                    break;
4163
                default:
4164 2
                          $colorIdxFg = 0x40;
4165 2
                    break;
4166
            }
4167 2
            $dataBlockFill = pack('v', $blockFillPatternStyle);
4168 2
            $dataBlockFill .= pack('v', $colorIdxFg | ($colorIdxBg << 7));
4169
        }
4170 2
        if ($bFormatProt == 1) {
4171
            $dataBlockProtection = 0;
4172
            if ($conditional->getStyle()->getProtection()->getLocked() == \PhpOffice\PhpSpreadsheet\Style\Protection::PROTECTION_PROTECTED) {
4173
                $dataBlockProtection = 1;
4174
            }
4175
            if ($conditional->getStyle()->getProtection()->getHidden() == \PhpOffice\PhpSpreadsheet\Style\Protection::PROTECTION_PROTECTED) {
4176
                $dataBlockProtection = 1 << 1;
4177
            }
4178
        }
4179
4180 2
        $data = pack('CCvvVv', $type, $operatorType, $szValue1, $szValue2, $flags, 0x0000);
0 ignored issues
show
Bug introduced by
The variable $type 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...
Bug introduced by
The variable $operatorType 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...
4181 2
        if ($bFormatFont == 1) { // Block Formatting : OK
4182 2
            $data .= $dataBlockFont;
0 ignored issues
show
Bug introduced by
The variable $dataBlockFont 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...
4183
        }
4184 2
        if ($bFormatAlign == 1) {
4185
            $data .= $dataBlockAlign;
0 ignored issues
show
Bug introduced by
The variable $dataBlockAlign 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...
4186
        }
4187 2
        if ($bFormatBorder == 1) {
4188
            $data .= $dataBlockBorder;
0 ignored issues
show
Bug introduced by
The variable $dataBlockBorder 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...
4189
        }
4190 2
        if ($bFormatFill == 1) { // Block Formatting : OK
4191 2
            $data .= $dataBlockFill;
0 ignored issues
show
Bug introduced by
The variable $dataBlockFill 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...
4192
        }
4193 2
        if ($bFormatProt == 1) {
4194
            $data .= $dataBlockProtection;
0 ignored issues
show
Bug introduced by
The variable $dataBlockProtection 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...
4195
        }
4196 2
        if (!is_null($operand1)) {
4197 2
            $data .= $operand1;
4198
        }
4199 2
        if (!is_null($operand2)) {
4200 1
            $data .= $operand2;
4201
        }
4202 2
        $header = pack('vv', $record, strlen($data));
4203 2
        $this->append($header . $data);
4204 2
    }
4205
4206
    /**
4207
     * Write CFHeader record.
4208
     */
4209 2
    private function writeCFHeader()
4210
    {
4211 2
        $record = 0x01B0; // Record identifier
4212 2
        $length = 0x0016; // Bytes to follow
4213
4214 2
        $numColumnMin = null;
4215 2
        $numColumnMax = null;
4216 2
        $numRowMin = null;
4217 2
        $numRowMax = null;
4218 2
        $arrConditional = [];
4219 2
        foreach ($this->phpSheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) {
4220 2
            foreach ($conditionalStyles as $conditional) {
4221 2
                if ($conditional->getConditionType() == \PhpOffice\PhpSpreadsheet\Style\Conditional::CONDITION_EXPRESSION
4222 2
                        || $conditional->getConditionType() == \PhpOffice\PhpSpreadsheet\Style\Conditional::CONDITION_CELLIS) {
4223 2
                    if (!in_array($conditional->getHashCode(), $arrConditional)) {
4224 2
                        $arrConditional[] = $conditional->getHashCode();
4225
                    }
4226
                    // Cells
4227 2
                    $arrCoord = \PhpOffice\PhpSpreadsheet\Cell::coordinateFromString($cellCoordinate);
4228 2
                    if (!is_numeric($arrCoord[0])) {
4229 2
                        $arrCoord[0] = \PhpOffice\PhpSpreadsheet\Cell::columnIndexFromString($arrCoord[0]);
4230
                    }
4231 2
                    if (is_null($numColumnMin) || ($numColumnMin > $arrCoord[0])) {
4232 2
                        $numColumnMin = $arrCoord[0];
4233
                    }
4234 2
                    if (is_null($numColumnMax) || ($numColumnMax < $arrCoord[0])) {
4235 2
                        $numColumnMax = $arrCoord[0];
4236
                    }
4237 2
                    if (is_null($numRowMin) || ($numRowMin > $arrCoord[1])) {
4238 2
                        $numRowMin = $arrCoord[1];
4239
                    }
4240 2
                    if (is_null($numRowMax) || ($numRowMax < $arrCoord[1])) {
4241 2
                        $numRowMax = $arrCoord[1];
4242
                    }
4243
                }
4244
            }
4245
        }
4246 2
        $needRedraw = 1;
4247 2
        $cellRange = pack('vvvv', $numRowMin - 1, $numRowMax - 1, $numColumnMin - 1, $numColumnMax - 1);
4248
4249 2
        $header = pack('vv', $record, $length);
4250 2
        $data = pack('vv', count($arrConditional), $needRedraw);
4251 2
        $data .= $cellRange;
4252 2
        $data .= pack('v', 0x0001);
4253 2
        $data .= $cellRange;
4254 2
        $this->append($header . $data);
4255 2
    }
4256
}
4257