Completed
Push — develop ( febbe8...0477e6 )
by Adrien
25:31 queued 16:01
created

Worksheet::writeCFRule()   F

Complexity

Conditions 387
Paths 0

Size

Total Lines 1172
Code Lines 1066

Duplication

Lines 695
Ratio 59.3 %

Code Coverage

Tests 313
CRAP Score 52177.2082

Importance

Changes 0
Metric Value
cc 387
eloc 1066
nc 0
nop 1
dl 695
loc 1172
ccs 313
cts 1050
cp 0.298
crap 52177.2082
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Writer\Xls;
4
5
use PhpOffice\PhpSpreadsheet\Cell;
6
use PhpOffice\PhpSpreadsheet\Cell\DataValidation;
7
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
8
use PhpOffice\PhpSpreadsheet\RichText;
9
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
10
use PhpOffice\PhpSpreadsheet\Shared\Xls;
11
use PhpOffice\PhpSpreadsheet\Style\Alignment;
12
use PhpOffice\PhpSpreadsheet\Style\Border;
13
use PhpOffice\PhpSpreadsheet\Style\Color;
14
use PhpOffice\PhpSpreadsheet\Style\Conditional;
15
use PhpOffice\PhpSpreadsheet\Style\Fill;
16
use PhpOffice\PhpSpreadsheet\Style\Protection;
17
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
18
use PhpOffice\PhpSpreadsheet\Worksheet\SheetView;
19
use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;
20
21
/**
22
 * Copyright (c) 2006 - 2015 PhpSpreadsheet.
23
 *
24
 * This library is free software; you can redistribute it and/or
25
 * modify it under the terms of the GNU Lesser General Public
26
 * License as published by the Free Software Foundation; either
27
 * version 2.1 of the License, or (at your option) any later version.
28
 *
29
 * This library is distributed in the hope that it will be useful,
30
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
32
 * Lesser General Public License for more details.
33
 *
34
 * You should have received a copy of the GNU Lesser General Public
35
 * License along with this library; if not, write to the Free Software
36
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
37
 *
38
 * @category   PhpSpreadsheet
39
 *
40
 * @copyright  Copyright (c) 2006 - 2015 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
41
 * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
42
 */
43
44
// Original file header of PEAR::Spreadsheet_Excel_Writer_Worksheet (used as the base for this class):
45
// -----------------------------------------------------------------------------------------
46
// /*
47
// *  Module written/ported by Xavier Noguer <[email protected]>
48
// *
49
// *  The majority of this is _NOT_ my code.  I simply ported it from the
50
// *  PERL Spreadsheet::WriteExcel module.
51
// *
52
// *  The author of the Spreadsheet::WriteExcel module is John McNamara
53
// *  <[email protected]>
54
// *
55
// *  I _DO_ maintain this code, and John McNamara has nothing to do with the
56
// *  porting of this code to PHP.  Any questions directly related to this
57
// *  class library should be directed to me.
58
// *
59
// *  License Information:
60
// *
61
// *    Spreadsheet_Excel_Writer:  A library for generating Excel Spreadsheets
62
// *    Copyright (c) 2002-2003 Xavier Noguer [email protected]
63
// *
64
// *    This library is free software; you can redistribute it and/or
65
// *    modify it under the terms of the GNU Lesser General Public
66
// *    License as published by the Free Software Foundation; either
67
// *    version 2.1 of the License, or (at your option) any later version.
68
// *
69
// *    This library is distributed in the hope that it will be useful,
70
// *    but WITHOUT ANY WARRANTY; without even the implied warranty of
71
// *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
72
// *    Lesser General Public License for more details.
73
// *
74
// *    You should have received a copy of the GNU Lesser General Public
75
// *    License along with this library; if not, write to the Free Software
76
// *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
77
// */
78
class Worksheet extends BIFFwriter
79
{
80
    /**
81
     * Formula parser.
82
     *
83
     * @var \PhpOffice\PhpSpreadsheet\Writer\Xls\Parser
84
     */
85
    private $parser;
86
87
    /**
88
     * Maximum number of characters for a string (LABEL record in BIFF5).
89
     *
90
     * @var int
91
     */
92
    private $xlsStringMaxLength;
93
94
    /**
95
     * Array containing format information for columns.
96
     *
97
     * @var array
98
     */
99
    private $columnInfo;
100
101
    /**
102
     * Array containing the selected area for the worksheet.
103
     *
104
     * @var array
105
     */
106
    private $selection;
107
108
    /**
109
     * The active pane for the worksheet.
110
     *
111
     * @var int
112
     */
113
    private $activePane;
114
115
    /**
116
     * Whether to use outline.
117
     *
118
     * @var int
119
     */
120
    private $outlineOn;
121
122
    /**
123
     * Auto outline styles.
124
     *
125
     * @var bool
126
     */
127
    private $outlineStyle;
128
129
    /**
130
     * Whether to have outline summary below.
131
     *
132
     * @var bool
133
     */
134
    private $outlineBelow;
135
136
    /**
137
     * Whether to have outline summary at the right.
138
     *
139
     * @var bool
140
     */
141
    private $outlineRight;
142
143
    /**
144
     * Reference to the total number of strings in the workbook.
145
     *
146
     * @var int
147
     */
148
    private $stringTotal;
149
150
    /**
151
     * Reference to the number of unique strings in the workbook.
152
     *
153
     * @var int
154
     */
155
    private $stringUnique;
156
157
    /**
158
     * Reference to the array containing all the unique strings in the workbook.
159
     *
160
     * @var array
161
     */
162
    private $stringTable;
163
164
    /**
165
     * Color cache.
166
     */
167
    private $colors;
168
169
    /**
170
     * Index of first used row (at least 0).
171
     *
172
     * @var int
173
     */
174
    private $firstRowIndex;
175
176
    /**
177
     * Index of last used row. (no used rows means -1).
178
     *
179
     * @var int
180
     */
181
    private $lastRowIndex;
182
183
    /**
184
     * Index of first used column (at least 0).
185
     *
186
     * @var int
187
     */
188
    private $firstColumnIndex;
189
190
    /**
191
     * Index of last used column (no used columns means -1).
192
     *
193
     * @var int
194
     */
195
    private $lastColumnIndex;
196
197
    /**
198
     * Sheet object.
199
     *
200
     * @var \PhpOffice\PhpSpreadsheet\Worksheet
201
     */
202
    public $phpSheet;
203
204
    /**
205
     * Count cell style Xfs.
206
     *
207
     * @var int
208
     */
209
    private $countCellStyleXfs;
210
211
    /**
212
     * Escher object corresponding to MSODRAWING.
213
     *
214
     * @var \PhpOffice\PhpSpreadsheet\Shared\Escher
215
     */
216
    private $escher;
217
218
    /**
219
     * Array of font hashes associated to FONT records index.
220
     *
221
     * @var array
222
     */
223
    public $fontHashIndex;
224
225
    /**
226
     * @var bool
227
     */
228
    private $preCalculateFormulas;
229
230
    /**
231
     * @var int
232
     */
233
    private $printHeaders;
234
235
    /**
236
     * Constructor.
237
     *
238
     * @param int &$str_total Total number of strings
239
     * @param int &$str_unique Total number of unique strings
240
     * @param array &$str_table String Table
241
     * @param array &$colors Colour Table
242
     * @param mixed $parser The formula parser created for the Workbook
243
     * @param bool $preCalculateFormulas Flag indicating whether formulas should be calculated or just written
244
     * @param string $phpSheet The worksheet to write
245
     * @param \PhpOffice\PhpSpreadsheet\Worksheet $phpSheet
246
     */
247 39
    public function __construct(&$str_total, &$str_unique, &$str_table, &$colors, $parser, $preCalculateFormulas, $phpSheet)
248
    {
249
        // It needs to call its parent's constructor explicitly
250 39
        parent::__construct();
251
252 39
        $this->preCalculateFormulas = $preCalculateFormulas;
253 39
        $this->stringTotal = &$str_total;
254 39
        $this->stringUnique = &$str_unique;
255 39
        $this->stringTable = &$str_table;
256 39
        $this->colors = &$colors;
257 39
        $this->parser = $parser;
258
259 39
        $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...
260
261 39
        $this->xlsStringMaxLength = 255;
262 39
        $this->columnInfo = [];
263 39
        $this->selection = [0, 0, 0, 0];
264 39
        $this->activePane = 3;
265
266 39
        $this->printHeaders = 0;
267
268 39
        $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...
269 39
        $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...
270 39
        $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...
271 39
        $this->outlineOn = 1;
272
273 39
        $this->fontHashIndex = [];
274
275
        // calculate values for DIMENSIONS record
276 39
        $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...
277 39
        $minC = 'A';
278
279 39
        $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...
280 39
        $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...
281
282
        // Determine lowest and highest column and row
283 39
        $this->lastRowIndex = ($maxR > 65535) ? 65535 : $maxR;
284
285 39
        $this->firstColumnIndex = Cell::columnIndexFromString($minC);
286 39
        $this->lastColumnIndex = Cell::columnIndexFromString($maxC);
287
288
//        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...
289 39
        if ($this->lastColumnIndex > 255) {
290
            $this->lastColumnIndex = 255;
291
        }
292
293 39
        $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...
294 39
    }
295
296
    /**
297
     * Add data to the beginning of the workbook (note the reverse order)
298
     * and to the end of the workbook.
299
     *
300
     * @see \PhpOffice\PhpSpreadsheet\Writer\Xls\Workbook::storeWorkbook()
301
     */
302 39
    public function close()
303
    {
304 39
        $phpSheet = $this->phpSheet;
305
306
        // Write BOF record
307 39
        $this->storeBof(0x0010);
308
309
        // Write PRINTHEADERS
310 39
        $this->writePrintHeaders();
311
312
        // Write PRINTGRIDLINES
313 39
        $this->writePrintGridlines();
314
315
        // Write GRIDSET
316 39
        $this->writeGridset();
317
318
        // Calculate column widths
319 39
        $phpSheet->calculateColumnWidths();
320
321
        // Column dimensions
322 39
        if (($defaultWidth = $phpSheet->getDefaultColumnDimension()->getWidth()) < 0) {
323 38
            $defaultWidth = \PhpOffice\PhpSpreadsheet\Shared\Font::getDefaultColumnWidthByFont($phpSheet->getParent()->getDefaultStyle()->getFont());
324
        }
325
326 39
        $columnDimensions = $phpSheet->getColumnDimensions();
327 39
        $maxCol = $this->lastColumnIndex - 1;
328 39
        for ($i = 0; $i <= $maxCol; ++$i) {
329 39
            $hidden = 0;
330 39
            $level = 0;
331 39
            $xfIndex = 15; // there are 15 cell style Xfs
332
333 39
            $width = $defaultWidth;
334
335 39
            $columnLetter = Cell::stringFromColumnIndex($i);
336 39
            if (isset($columnDimensions[$columnLetter])) {
337 19
                $columnDimension = $columnDimensions[$columnLetter];
338 19
                if ($columnDimension->getWidth() >= 0) {
339 19
                    $width = $columnDimension->getWidth();
340
                }
341 19
                $hidden = $columnDimension->getVisible() ? 0 : 1;
342 19
                $level = $columnDimension->getOutlineLevel();
343 19
                $xfIndex = $columnDimension->getXfIndex() + 15; // there are 15 cell style Xfs
344
            }
345
346
            // Components of columnInfo:
347
            // $firstcol first column on the range
348
            // $lastcol  last column on the range
349
            // $width    width to set
350
            // $xfIndex  The optional cell style Xf index to apply to the columns
351
            // $hidden   The optional hidden atribute
352
            // $level    The optional outline level
353 39
            $this->columnInfo[] = [$i, $i, $width, $xfIndex, $hidden, $level];
354
        }
355
356
        // Write GUTS
357 39
        $this->writeGuts();
358
359
        // Write DEFAULTROWHEIGHT
360 39
        $this->writeDefaultRowHeight();
361
        // Write WSBOOL
362 39
        $this->writeWsbool();
363
        // Write horizontal and vertical page breaks
364 39
        $this->writeBreaks();
365
        // Write page header
366 39
        $this->writeHeader();
367
        // Write page footer
368 39
        $this->writeFooter();
369
        // Write page horizontal centering
370 39
        $this->writeHcenter();
371
        // Write page vertical centering
372 39
        $this->writeVcenter();
373
        // Write left margin
374 39
        $this->writeMarginLeft();
375
        // Write right margin
376 39
        $this->writeMarginRight();
377
        // Write top margin
378 39
        $this->writeMarginTop();
379
        // Write bottom margin
380 39
        $this->writeMarginBottom();
381
        // Write page setup
382 39
        $this->writeSetup();
383
        // Write sheet protection
384 39
        $this->writeProtect();
385
        // Write SCENPROTECT
386 39
        $this->writeScenProtect();
387
        // Write OBJECTPROTECT
388 39
        $this->writeObjectProtect();
389
        // Write sheet password
390 39
        $this->writePassword();
391
        // Write DEFCOLWIDTH record
392 39
        $this->writeDefcol();
393
394
        // Write the COLINFO records if they exist
395 39
        if (!empty($this->columnInfo)) {
396 39
            $colcount = count($this->columnInfo);
397 39
            for ($i = 0; $i < $colcount; ++$i) {
398 39
                $this->writeColinfo($this->columnInfo[$i]);
399
            }
400
        }
401 39
        $autoFilterRange = $phpSheet->getAutoFilter()->getRange();
402 39
        if (!empty($autoFilterRange)) {
403
            // Write AUTOFILTERINFO
404 3
            $this->writeAutoFilterInfo();
405
        }
406
407
        // Write sheet dimensions
408 39
        $this->writeDimensions();
409
410
        // Row dimensions
411 39
        foreach ($phpSheet->getRowDimensions() as $rowDimension) {
412 38
            $xfIndex = $rowDimension->getXfIndex() + 15; // there are 15 cellXfs
413 38
            $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...
414
        }
415
416
        // Write Cells
417 39
        foreach ($phpSheet->getCoordinates() as $coordinate) {
418 39
            $cell = $phpSheet->getCell($coordinate);
419 39
            $row = $cell->getRow() - 1;
420 39
            $column = Cell::columnIndexFromString($cell->getColumn()) - 1;
421
422
            // Don't break Excel break the code!
423 39
            if ($row > 65535 || $column > 255) {
424
                throw new WriterException('Rows or columns overflow! Excel5 has limit to 65535 rows and 255 columns. Use XLSX instead.');
425
            }
426
427
            // Write cell value
428 39
            $xfIndex = $cell->getXfIndex() + 15; // there are 15 cell style Xfs
429
430 39
            $cVal = $cell->getValue();
431 39
            if ($cVal instanceof RichText) {
432 9
                $arrcRun = [];
433 9
                $str_len = 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...
434 9
                $str_pos = 0;
435 9
                $elements = $cVal->getRichTextElements();
436 9
                foreach ($elements as $element) {
437
                    // FONT Index
438 9
                    if ($element instanceof RichText\Run) {
439 9
                        $str_fontidx = $this->fontHashIndex[$element->getFont()->getHashCode()];
440
                    } else {
441 8
                        $str_fontidx = 0;
442
                    }
443 9
                    $arrcRun[] = ['strlen' => $str_pos, 'fontidx' => $str_fontidx];
444
                    // Position FROM
445 9
                    $str_pos += StringHelper::countCharacters($element->getText(), 'UTF-8');
446
                }
447 9
                $this->writeRichTextString($row, $column, $cVal->getPlainText(), $xfIndex, $arrcRun);
448
            } else {
449 38
                switch ($cell->getDatatype()) {
450 38
                    case Cell\DataType::TYPE_STRING:
451 31
                    case Cell\DataType::TYPE_NULL:
452 36
                        if ($cVal === '' || $cVal === null) {
453 19
                            $this->writeBlank($row, $column, $xfIndex);
454
                        } else {
455 34
                            $this->writeString($row, $column, $cVal, $xfIndex);
456
                        }
457 36
                        break;
458 26
                    case Cell\DataType::TYPE_NUMERIC:
459 23
                        $this->writeNumber($row, $column, $cVal, $xfIndex);
460 23
                        break;
461 18
                    case Cell\DataType::TYPE_FORMULA:
462 16
                        $calculatedValue = $this->preCalculateFormulas ?
463 16
                            $cell->getCalculatedValue() : null;
464 16
                        $this->writeFormula($row, $column, $cVal, $xfIndex, $calculatedValue);
465 16
                        break;
466 8
                    case Cell\DataType::TYPE_BOOL:
467 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...
468 8
                        break;
469
                    case Cell\DataType::TYPE_ERROR:
470
                        $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...
471 39
                        break;
472
                }
473
            }
474
        }
475
476
        // Append
477 39
        $this->writeMsoDrawing();
478
479
        // Write WINDOW2 record
480 39
        $this->writeWindow2();
481
482
        // Write PLV record
483 39
        $this->writePageLayoutView();
484
485
        // Write ZOOM record
486 39
        $this->writeZoom();
487 39
        if ($phpSheet->getFreezePane()) {
488 3
            $this->writePanes();
489
        }
490
491
        // Write SELECTION record
492 39
        $this->writeSelection();
493
494
        // Write MergedCellsTable Record
495 39
        $this->writeMergedCells();
496
497
        // Hyperlinks
498 39
        foreach ($phpSheet->getHyperLinkCollection() as $coordinate => $hyperlink) {
499 8
            list($column, $row) = Cell::coordinateFromString($coordinate);
500
501 8
            $url = $hyperlink->getUrl();
502
503 8
            if (strpos($url, 'sheet://') !== false) {
504
                // internal to current workbook
505 6
                $url = str_replace('sheet://', 'internal:', $url);
506 8
            } 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...
507
                // URL
508
            } else {
509
                // external (local file)
510
                $url = 'external:' . $url;
511
            }
512
513 8
            $this->writeUrl($row - 1, Cell::columnIndexFromString($column) - 1, $url);
514
        }
515
516 39
        $this->writeDataValidity();
517 39
        $this->writeSheetLayout();
518
519
        // Write SHEETPROTECTION record
520 39
        $this->writeSheetProtection();
521 39
        $this->writeRangeProtection();
522
523 39
        $arrConditionalStyles = $phpSheet->getConditionalStylesCollection();
524 39
        if (!empty($arrConditionalStyles)) {
525 2
            $arrConditional = [];
526
            // @todo CFRule & CFHeader
527
            // Write CFHEADER record
528 2
            $this->writeCFHeader();
529
            // Write ConditionalFormattingTable records
530 2
            foreach ($arrConditionalStyles as $cellCoordinate => $conditionalStyles) {
531 2
                foreach ($conditionalStyles as $conditional) {
532 2
                    if ($conditional->getConditionType() == Conditional::CONDITION_EXPRESSION
533 2
                        || $conditional->getConditionType() == Conditional::CONDITION_CELLIS) {
534 2
                        if (!isset($arrConditional[$conditional->getHashCode()])) {
535
                            // This hash code has been handled
536 2
                            $arrConditional[$conditional->getHashCode()] = true;
537
538
                            // Write CFRULE record
539 2
                            $this->writeCFRule($conditional);
540
                        }
541
                    }
542
                }
543
            }
544
        }
545
546 39
        $this->storeEof();
547 39
    }
548
549
    /**
550
     * Write a cell range address in BIFF8
551
     * always fixed range
552
     * See section 2.5.14 in OpenOffice.org's Documentation of the Microsoft Excel File Format.
553
     *
554
     * @param string $range E.g. 'A1' or 'A1:B6'
555
     *
556
     * @return string Binary data
557
     */
558 7
    private function writeBIFF8CellRangeAddressFixed($range)
559
    {
560 7
        $explodes = explode(':', $range);
561
562
        // extract first cell, e.g. 'A1'
563 7
        $firstCell = $explodes[0];
564
565
        // extract last cell, e.g. 'B6'
566 7
        if (count($explodes) == 1) {
567 2
            $lastCell = $firstCell;
568
        } else {
569 5
            $lastCell = $explodes[1];
570
        }
571
572 7
        $firstCellCoordinates = 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...
573 7
        $lastCellCoordinates = 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...
574
575 7
        return pack('vvvv', $firstCellCoordinates[1] - 1, $lastCellCoordinates[1] - 1, Cell::columnIndexFromString($firstCellCoordinates[0]) - 1, Cell::columnIndexFromString($lastCellCoordinates[0]) - 1);
576
    }
577
578
    /**
579
     * Retrieves data from memory in one chunk, or from disk in $buffer
580
     * sized chunks.
581
     *
582
     * @return string The data
583
     */
584 39
    public function getData()
585
    {
586 39
        $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...
587
588
        // Return data stored in memory
589 39
        if (isset($this->_data)) {
590 39
            $tmp = $this->_data;
591 39
            unset($this->_data);
592
593 39
            return $tmp;
594
        }
595
        // No data to return
596
        return false;
597
    }
598
599
    /**
600
     * Set the option to print the row and column headers on the printed page.
601
     *
602
     * @param int $print Whether to print the headers or not. Defaults to 1 (print).
603
     */
604
    public function printRowColHeaders($print = 1)
605
    {
606
        $this->printHeaders = $print;
607
    }
608
609
    /**
610
     * This method sets the properties for outlining and grouping. The defaults
611
     * correspond to Excel's defaults.
612
     *
613
     * @param bool $visible
614
     * @param bool $symbols_below
615
     * @param bool $symbols_right
616
     * @param bool $auto_style
617
     */
618
    public function setOutline($visible = true, $symbols_below = true, $symbols_right = true, $auto_style = false)
619
    {
620
        $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...
621
        $this->outlineBelow = $symbols_below;
622
        $this->outlineRight = $symbols_right;
623
        $this->outlineStyle = $auto_style;
624
625
        // Ensure this is a boolean vale for Window2
626
        if ($this->outlineOn) {
627
            $this->outlineOn = 1;
628
        }
629
    }
630
631
    /**
632
     * Write a double to the specified row and column (zero indexed).
633
     * An integer can be written as a double. Excel will display an
634
     * integer. $format is optional.
635
     *
636
     * Returns  0 : normal termination
637
     *         -2 : row or column out of range
638
     *
639
     * @param int $row Zero indexed row
640
     * @param int $col Zero indexed column
641
     * @param float $num The number to write
642
     * @param mixed $xfIndex The optional XF format
643
     *
644
     * @return int
645
     */
646 23
    private function writeNumber($row, $col, $num, $xfIndex)
647
    {
648 23
        $record = 0x0203; // Record identifier
649 23
        $length = 0x000E; // Number of bytes to follow
650
651 23
        $header = pack('vv', $record, $length);
652 23
        $data = pack('vvv', $row, $col, $xfIndex);
653 23
        $xl_double = pack('d', $num);
654 23
        if (self::getByteOrder()) { // if it's Big Endian
655
            $xl_double = strrev($xl_double);
656
        }
657
658 23
        $this->append($header . $data . $xl_double);
659
660 23
        return 0;
661
    }
662
663
    /**
664
     * Write a LABELSST record or a LABEL record. Which one depends on BIFF version.
665
     *
666
     * @param int $row Row index (0-based)
667
     * @param int $col Column index (0-based)
668
     * @param string $str The string
669
     * @param int $xfIndex Index to XF record
670
     */
671 34
    private function writeString($row, $col, $str, $xfIndex)
672
    {
673 34
        $this->writeLabelSst($row, $col, $str, $xfIndex);
674 34
    }
675
676
    /**
677
     * Write a LABELSST record or a LABEL record. Which one depends on BIFF version
678
     * It differs from writeString by the writing of rich text strings.
679
     *
680
     * @param int $row Row index (0-based)
681
     * @param int $col Column index (0-based)
682
     * @param string $str The string
683
     * @param int $xfIndex The XF format index for the cell
684
     * @param array $arrcRun Index to Font record and characters beginning
685
     */
686 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...
687
    {
688 9
        $record = 0x00FD; // Record identifier
689 9
        $length = 0x000A; // Bytes to follow
690 9
        $str = StringHelper::UTF8toBIFF8UnicodeShort($str, $arrcRun);
691
692
        /* check if string is already present */
693 9
        if (!isset($this->stringTable[$str])) {
694 9
            $this->stringTable[$str] = $this->stringUnique++;
695
        }
696 9
        ++$this->stringTotal;
697
698 9
        $header = pack('vv', $record, $length);
699 9
        $data = pack('vvvV', $row, $col, $xfIndex, $this->stringTable[$str]);
700 9
        $this->append($header . $data);
701 9
    }
702
703
    /**
704
     * Write a string to the specified row and column (zero indexed).
705
     * NOTE: there is an Excel 5 defined limit of 255 characters.
706
     * $format is optional.
707
     * Returns  0 : normal termination
708
     *         -2 : row or column out of range
709
     *         -3 : long string truncated to 255 chars.
710
     *
711
     * @param int $row Zero indexed row
712
     * @param int $col Zero indexed column
713
     * @param string $str The string to write
714
     * @param mixed $xfIndex The XF format index for the cell
715
     *
716
     * @return int
717
     */
718
    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...
719
    {
720
        $strlen = strlen($str);
721
        $record = 0x0204; // Record identifier
722
        $length = 0x0008 + $strlen; // Bytes to follow
723
724
        $str_error = 0;
725
726
        if ($strlen > $this->xlsStringMaxLength) { // LABEL must be < 255 chars
727
            $str = substr($str, 0, $this->xlsStringMaxLength);
728
            $length = 0x0008 + $this->xlsStringMaxLength;
729
            $strlen = $this->xlsStringMaxLength;
730
            $str_error = -3;
731
        }
732
733
        $header = pack('vv', $record, $length);
734
        $data = pack('vvvv', $row, $col, $xfIndex, $strlen);
735
        $this->append($header . $data . $str);
736
737
        return $str_error;
738
    }
739
740
    /**
741
     * Write a string to the specified row and column (zero indexed).
742
     * This is the BIFF8 version (no 255 chars limit).
743
     * $format is optional.
744
     * Returns  0 : normal termination
745
     *         -2 : row or column out of range
746
     *         -3 : long string truncated to 255 chars.
747
     *
748
     * @param int $row Zero indexed row
749
     * @param int $col Zero indexed column
750
     * @param string $str The string to write
751
     * @param mixed $xfIndex The XF format index for the cell
752
     *
753
     * @return int
754
     */
755 34 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...
756
    {
757 34
        $record = 0x00FD; // Record identifier
758 34
        $length = 0x000A; // Bytes to follow
759
760 34
        $str = StringHelper::UTF8toBIFF8UnicodeLong($str);
761
762
        /* check if string is already present */
763 34
        if (!isset($this->stringTable[$str])) {
764 34
            $this->stringTable[$str] = $this->stringUnique++;
765
        }
766 34
        ++$this->stringTotal;
767
768 34
        $header = pack('vv', $record, $length);
769 34
        $data = pack('vvvV', $row, $col, $xfIndex, $this->stringTable[$str]);
770 34
        $this->append($header . $data);
771 34
    }
772
773
    /**
774
     * Writes a note associated with the cell given by the row and column.
775
     * NOTE records don't have a length limit.
776
     *
777
     * @param int $row Zero indexed row
778
     * @param int $col Zero indexed column
779
     * @param string $note The note to write
780
     */
781
    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...
782
    {
783
        $note_length = strlen($note);
784
        $record = 0x001C; // Record identifier
785
        $max_length = 2048; // Maximun length for a NOTE record
786
787
        // Length for this record is no more than 2048 + 6
788
        $length = 0x0006 + min($note_length, 2048);
789
        $header = pack('vv', $record, $length);
790
        $data = pack('vvv', $row, $col, $note_length);
791
        $this->append($header . $data . substr($note, 0, 2048));
792
793
        for ($i = $max_length; $i < $note_length; $i += $max_length) {
794
            $chunk = substr($note, $i, $max_length);
795
            $length = 0x0006 + strlen($chunk);
796
            $header = pack('vv', $record, $length);
797
            $data = pack('vvv', -1, 0, strlen($chunk));
798
            $this->append($header . $data . $chunk);
799
        }
800
801
        return 0;
802
    }
803
804
    /**
805
     * Write a blank cell to the specified row and column (zero indexed).
806
     * A blank cell is used to specify formatting without adding a string
807
     * or a number.
808
     *
809
     * A blank cell without a format serves no purpose. Therefore, we don't write
810
     * a BLANK record unless a format is specified.
811
     *
812
     * Returns  0 : normal termination (including no format)
813
     *         -1 : insufficient number of arguments
814
     *         -2 : row or column out of range
815
     *
816
     * @param int $row Zero indexed row
817
     * @param int $col Zero indexed column
818
     * @param mixed $xfIndex The XF format index
819
     */
820 19 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...
821
    {
822 19
        $record = 0x0201; // Record identifier
823 19
        $length = 0x0006; // Number of bytes to follow
824
825 19
        $header = pack('vv', $record, $length);
826 19
        $data = pack('vvv', $row, $col, $xfIndex);
827 19
        $this->append($header . $data);
828
829 19
        return 0;
830
    }
831
832
    /**
833
     * Write a boolean or an error type to the specified row and column (zero indexed).
834
     *
835
     * @param int $row Row index (0-based)
836
     * @param int $col Column index (0-based)
837
     * @param int $value
838
     * @param bool $isError Error or Boolean?
839
     * @param int $xfIndex
840
     */
841 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...
842
    {
843 8
        $record = 0x0205;
844 8
        $length = 8;
845
846 8
        $header = pack('vv', $record, $length);
847 8
        $data = pack('vvvCC', $row, $col, $xfIndex, $value, $isError);
848 8
        $this->append($header . $data);
849
850 8
        return 0;
851
    }
852
853
    /**
854
     * Write a formula to the specified row and column (zero indexed).
855
     * The textual representation of the formula is passed to the parser in
856
     * Parser.php which returns a packed binary string.
857
     *
858
     * Returns  0 : normal termination
859
     *         -1 : formula errors (bad formula)
860
     *         -2 : row or column out of range
861
     *
862
     * @param int $row Zero indexed row
863
     * @param int $col Zero indexed column
864
     * @param string $formula The formula text string
865
     * @param mixed $xfIndex The XF format index
866
     * @param mixed $calculatedValue Calculated value
867
     *
868
     * @return int
869
     */
870 16
    private function writeFormula($row, $col, $formula, $xfIndex, $calculatedValue)
871
    {
872 16
        $record = 0x0006; // Record identifier
873
874
        // Initialize possible additional value for STRING record that should be written after the FORMULA record?
875 16
        $stringValue = null;
876
877
        // calculated value
878 16
        if (isset($calculatedValue)) {
879
            // Since we can't yet get the data type of the calculated value,
880
            // we use best effort to determine data type
881 16
            if (is_bool($calculatedValue)) {
882
                // Boolean value
883 3
                $num = pack('CCCvCv', 0x01, 0x00, (int) $calculatedValue, 0x00, 0x00, 0xFFFF);
884 16
            } elseif (is_int($calculatedValue) || is_float($calculatedValue)) {
885
                // Numeric value
886 14
                $num = pack('d', $calculatedValue);
887 12
            } elseif (is_string($calculatedValue)) {
888 12
                $errorCodes = Cell\DataType::getErrorCodes();
889 12
                if (isset($errorCodes[$calculatedValue])) {
890
                    // Error value
891 4
                    $num = pack('CCCvCv', 0x02, 0x00, self::mapErrorCode($calculatedValue), 0x00, 0x00, 0xFFFF);
892 12
                } elseif ($calculatedValue === '') {
893
                    // 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...
894 5
                    $num = pack('CCCvCv', 0x03, 0x00, 0x00, 0x00, 0x00, 0xFFFF);
895
                } else {
896
                    // Non-empty string value (or empty string BIFF5)
897 7
                    $stringValue = $calculatedValue;
898 12
                    $num = pack('CCCvCv', 0x00, 0x00, 0x00, 0x00, 0x00, 0xFFFF);
899
                }
900
            } else {
901
                // We are really not supposed to reach here
902 16
                $num = pack('d', 0x00);
903
            }
904
        } else {
905
            $num = pack('d', 0x00);
906
        }
907
908 16
        $grbit = 0x03; // Option flags
909 16
        $unknown = 0x0000; // Must be zero
910
911
        // Strip the '=' or '@' sign at the beginning of the formula string
912 16
        if ($formula[0] == '=') {
913 16
            $formula = substr($formula, 1);
914
        } else {
915
            // Error handling
916
            $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...
917
918
            return -1;
919
        }
920
921
        // Parse the formula using the parser in Parser.php
922
        try {
923 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...
924 16
            $formula = $this->parser->toReversePolish();
925
926 16
            $formlen = strlen($formula); // Length of the binary string
927 16
            $length = 0x16 + $formlen; // Length of the record data
928
929 16
            $header = pack('vv', $record, $length);
930
931 16
            $data = pack('vvv', $row, $col, $xfIndex)
932 16
                        . $num
933 16
                        . pack('vVv', $grbit, $unknown, $formlen);
934 16
            $this->append($header . $data . $formula);
935
936
            // Append also a STRING record if necessary
937 16
            if ($stringValue !== null) {
938 7
                $this->writeStringRecord($stringValue);
939
            }
940
941 16
            return 0;
942 5
        } catch (PhpSpreadsheetException $e) {
943
            // do nothing
944
        }
945 5
    }
946
947
    /**
948
     * Write a STRING record. This.
949
     *
950
     * @param string $stringValue
951
     */
952 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...
953
    {
954 7
        $record = 0x0207; // Record identifier
955 7
        $data = StringHelper::UTF8toBIFF8UnicodeLong($stringValue);
956
957 7
        $length = strlen($data);
958 7
        $header = pack('vv', $record, $length);
959
960 7
        $this->append($header . $data);
961 7
    }
962
963
    /**
964
     * Write a hyperlink.
965
     * This is comprised of two elements: the visible label and
966
     * the invisible link. The visible label is the same as the link unless an
967
     * alternative string is specified. The label is written using the
968
     * writeString() method. Therefore the 255 characters string limit applies.
969
     * $string and $format are optional.
970
     *
971
     * The hyperlink can be to a http, ftp, mail, internal sheet (not yet), or external
972
     * directory url.
973
     *
974
     * Returns  0 : normal termination
975
     *         -2 : row or column out of range
976
     *         -3 : long string truncated to 255 chars
977
     *
978
     * @param int $row Row
979
     * @param int $col Column
980
     * @param string $url URL string
981
     *
982
     * @return int
983
     */
984 8
    private function writeUrl($row, $col, $url)
985
    {
986
        // Add start row and col to arg list
987 8
        return $this->writeUrlRange($row, $col, $row, $col, $url);
988
    }
989
990
    /**
991
     * This is the more general form of writeUrl(). It allows a hyperlink to be
992
     * written to a range of cells. This function also decides the type of hyperlink
993
     * to be written. These are either, Web (http, ftp, mailto), Internal
994
     * (Sheet1!A1) or external ('c:\temp\foo.xls#Sheet1!A1').
995
     *
996
     * @see writeUrl()
997
     *
998
     * @param int $row1 Start row
999
     * @param int $col1 Start column
1000
     * @param int $row2 End row
1001
     * @param int $col2 End column
1002
     * @param string $url URL string
1003
     *
1004
     * @return int
1005
     */
1006 8
    public function writeUrlRange($row1, $col1, $row2, $col2, $url)
1007
    {
1008
        // Check for internal/external sheet links or default to web link
1009 8
        if (preg_match('[^internal:]', $url)) {
1010 6
            return $this->writeUrlInternal($row1, $col1, $row2, $col2, $url);
1011
        }
1012 8
        if (preg_match('[^external:]', $url)) {
1013
            return $this->writeUrlExternal($row1, $col1, $row2, $col2, $url);
1014
        }
1015
1016 8
        return $this->writeUrlWeb($row1, $col1, $row2, $col2, $url);
1017
    }
1018
1019
    /**
1020
     * Used to write http, ftp and mailto hyperlinks.
1021
     * The link type ($options) is 0x03 is the same as absolute dir ref without
1022
     * sheet. However it is differentiated by the $unknown2 data stream.
1023
     *
1024
     * @see writeUrl()
1025
     *
1026
     * @param int $row1 Start row
1027
     * @param int $col1 Start column
1028
     * @param int $row2 End row
1029
     * @param int $col2 End column
1030
     * @param string $url URL string
1031
     *
1032
     * @return int
1033
     */
1034 8
    public function writeUrlWeb($row1, $col1, $row2, $col2, $url)
1035
    {
1036 8
        $record = 0x01B8; // Record identifier
1037 8
        $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...
1038
1039
        // Pack the undocumented parts of the hyperlink stream
1040 8
        $unknown1 = pack('H*', 'D0C9EA79F9BACE118C8200AA004BA90B02000000');
1041 8
        $unknown2 = pack('H*', 'E0C9EA79F9BACE118C8200AA004BA90B');
1042
1043
        // Pack the option flags
1044 8
        $options = pack('V', 0x03);
1045
1046
        // Convert URL to a null terminated wchar string
1047 8
        $url = implode("\0", preg_split("''", $url, -1, PREG_SPLIT_NO_EMPTY));
1048 8
        $url = $url . "\0\0\0";
1049
1050
        // Pack the length of the URL
1051 8
        $url_len = pack('V', strlen($url));
1052
1053
        // Calculate the data length
1054 8
        $length = 0x34 + strlen($url);
1055
1056
        // Pack the header data
1057 8
        $header = pack('vv', $record, $length);
1058 8
        $data = pack('vvvv', $row1, $row2, $col1, $col2);
1059
1060
        // Write the packed data
1061 8
        $this->append($header . $data . $unknown1 . $options . $unknown2 . $url_len . $url);
1062
1063 8
        return 0;
1064
    }
1065
1066
    /**
1067
     * Used to write internal reference hyperlinks such as "Sheet1!A1".
1068
     *
1069
     * @see writeUrl()
1070
     *
1071
     * @param int $row1 Start row
1072
     * @param int $col1 Start column
1073
     * @param int $row2 End row
1074
     * @param int $col2 End column
1075
     * @param string $url URL string
1076
     *
1077
     * @return int
1078
     */
1079 6
    public function writeUrlInternal($row1, $col1, $row2, $col2, $url)
1080
    {
1081 6
        $record = 0x01B8; // Record identifier
1082 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...
1083
1084
        // Strip URL type
1085 6
        $url = preg_replace('/^internal:/', '', $url);
1086
1087
        // Pack the undocumented parts of the hyperlink stream
1088 6
        $unknown1 = pack('H*', 'D0C9EA79F9BACE118C8200AA004BA90B02000000');
1089
1090
        // Pack the option flags
1091 6
        $options = pack('V', 0x08);
1092
1093
        // Convert the URL type and to a null terminated wchar string
1094 6
        $url .= "\0";
1095
1096
        // character count
1097 6
        $url_len = StringHelper::countCharacters($url);
1098 6
        $url_len = pack('V', $url_len);
1099
1100 6
        $url = StringHelper::convertEncoding($url, 'UTF-16LE', 'UTF-8');
1101
1102
        // Calculate the data length
1103 6
        $length = 0x24 + strlen($url);
1104
1105
        // Pack the header data
1106 6
        $header = pack('vv', $record, $length);
1107 6
        $data = pack('vvvv', $row1, $row2, $col1, $col2);
1108
1109
        // Write the packed data
1110 6
        $this->append($header . $data . $unknown1 . $options . $url_len . $url);
1111
1112 6
        return 0;
1113
    }
1114
1115
    /**
1116
     * Write links to external directory names such as 'c:\foo.xls',
1117
     * c:\foo.xls#Sheet1!A1', '../../foo.xls'. and '../../foo.xls#Sheet1!A1'.
1118
     *
1119
     * Note: Excel writes some relative links with the $dir_long string. We ignore
1120
     * these cases for the sake of simpler code.
1121
     *
1122
     * @see writeUrl()
1123
     *
1124
     * @param int $row1 Start row
1125
     * @param int $col1 Start column
1126
     * @param int $row2 End row
1127
     * @param int $col2 End column
1128
     * @param string $url URL string
1129
     *
1130
     * @return int
1131
     */
1132
    public function writeUrlExternal($row1, $col1, $row2, $col2, $url)
1133
    {
1134
        // Network drives are different. We will handle them separately
1135
        // MS/Novell network drives and shares start with \\
1136
        if (preg_match('[^external:\\\\]', $url)) {
1137
            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...
1138
        }
1139
1140
        $record = 0x01B8; // Record identifier
1141
        $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...
1142
1143
        // Strip URL type and change Unix dir separator to Dos style (if needed)
1144
        //
1145
        $url = preg_replace('/^external:/', '', $url);
1146
        $url = preg_replace('/\//', '\\', $url);
1147
1148
        // Determine if the link is relative or absolute:
1149
        //   relative if link contains no dir separator, "somefile.xls"
1150
        //   relative if link starts with up-dir, "..\..\somefile.xls"
1151
        //   otherwise, absolute
1152
1153
        $absolute = 0x00; // relative path
1154
        if (preg_match('/^[A-Z]:/', $url)) {
1155
            $absolute = 0x02; // absolute path on Windows, e.g. C:\...
1156
        }
1157
        $link_type = 0x01 | $absolute;
1158
1159
        // Determine if the link contains a sheet reference and change some of the
1160
        // parameters accordingly.
1161
        // Split the dir name and sheet name (if it exists)
1162
        $dir_long = $url;
1163
        if (preg_match("/\#/", $url)) {
1164
            $link_type |= 0x08;
1165
        }
1166
1167
        // Pack the link type
1168
        $link_type = pack('V', $link_type);
1169
1170
        // Calculate the up-level dir count e.g.. (..\..\..\ == 3)
1171
        $up_count = preg_match_all("/\.\.\\\/", $dir_long, $useless);
1172
        $up_count = pack('v', $up_count);
1173
1174
        // Store the short dos dir name (null terminated)
1175
        $dir_short = preg_replace("/\.\.\\\/", '', $dir_long) . "\0";
1176
1177
        // Store the long dir name as a wchar string (non-null terminated)
1178
        $dir_long = $dir_long . "\0";
1179
1180
        // Pack the lengths of the dir strings
1181
        $dir_short_len = pack('V', strlen($dir_short));
1182
        $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...
1183
        $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...
1184
1185
        // Pack the undocumented parts of the hyperlink stream
1186
        $unknown1 = pack('H*', 'D0C9EA79F9BACE118C8200AA004BA90B02000000');
1187
        $unknown2 = pack('H*', '0303000000000000C000000000000046');
1188
        $unknown3 = pack('H*', 'FFFFADDE000000000000000000000000000000000000000');
1189
        $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...
1190
1191
        // Pack the main data stream
1192
        $data = pack('vvvv', $row1, $row2, $col1, $col2) .
1193
                            $unknown1 .
1194
                            $link_type .
1195
                            $unknown2 .
1196
                            $up_count .
1197
                            $dir_short_len .
1198
                            $dir_short .
1199
                            $unknown3 .
1200
                            $stream_len; /*.
1201
                          $dir_long_len .
1202
                          $unknown4     .
1203
                          $dir_long     .
1204
                          $sheet_len    .
1205
                          $sheet        ;*/
1206
1207
        // Pack the header data
1208
        $length = strlen($data);
1209
        $header = pack('vv', $record, $length);
1210
1211
        // Write the packed data
1212
        $this->append($header . $data);
1213
1214
        return 0;
1215
    }
1216
1217
    /**
1218
     * This method is used to set the height and format for a row.
1219
     *
1220
     * @param int $row The row to set
1221
     * @param int $height Height we are giving to the row.
1222
     *                        Use null to set XF without setting height
1223
     * @param int $xfIndex The optional cell style Xf index to apply to the columns
1224
     * @param bool $hidden The optional hidden attribute
1225
     * @param int $level The optional outline level for row, in range [0,7]
1226
     */
1227 38
    private function writeRow($row, $height, $xfIndex, $hidden = false, $level = 0)
1228
    {
1229 38
        $record = 0x0208; // Record identifier
1230 38
        $length = 0x0010; // Number of bytes to follow
1231
1232 38
        $colMic = 0x0000; // First defined column
1233 38
        $colMac = 0x0000; // Last defined column
1234 38
        $irwMac = 0x0000; // Used by Excel to optimise loading
1235 38
        $reserved = 0x0000; // Reserved
1236 38
        $grbit = 0x0000; // Option flags
1237 38
        $ixfe = $xfIndex;
1238
1239 38
        if ($height < 0) {
1240 37
            $height = null;
1241
        }
1242
1243
        // Use writeRow($row, null, $XF) to set XF format without setting height
1244 38
        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...
1245 6
            $miyRw = $height * 20; // row height
1246
        } else {
1247 37
            $miyRw = 0xff; // default row height is 256
1248
        }
1249
1250
        // Set the options flags. fUnsynced is used to show that the font and row
1251
        // heights are not compatible. This is usually the case for WriteExcel.
1252
        // The collapsed flag 0x10 doesn't seem to be used to indicate that a row
1253
        // is collapsed. Instead it is used to indicate that the previous row is
1254
        // collapsed. The zero height flag, 0x20, is used to collapse a row.
1255
1256 38
        $grbit |= $level;
1257 38
        if ($hidden) {
1258 2
            $grbit |= 0x0030;
1259
        }
1260 38
        if ($height !== null) {
1261 6
            $grbit |= 0x0040; // fUnsynced
1262
        }
1263 38
        if ($xfIndex !== 0xF) {
1264
            $grbit |= 0x0080;
1265
        }
1266 38
        $grbit |= 0x0100;
1267
1268 38
        $header = pack('vv', $record, $length);
1269 38
        $data = pack('vvvvvvvv', $row, $colMic, $colMac, $miyRw, $irwMac, $reserved, $grbit, $ixfe);
1270 38
        $this->append($header . $data);
1271 38
    }
1272
1273
    /**
1274
     * Writes Excel DIMENSIONS to define the area in which there is data.
1275
     */
1276 39
    private function writeDimensions()
1277
    {
1278 39
        $record = 0x0200; // Record identifier
1279
1280 39
        $length = 0x000E;
1281 39
        $data = pack('VVvvv', $this->firstRowIndex, $this->lastRowIndex + 1, $this->firstColumnIndex, $this->lastColumnIndex + 1, 0x0000); // reserved
1282
1283 39
        $header = pack('vv', $record, $length);
1284 39
        $this->append($header . $data);
1285 39
    }
1286
1287
    /**
1288
     * Write BIFF record Window2.
1289
     */
1290 39
    private function writeWindow2()
1291
    {
1292 39
        $record = 0x023E; // Record identifier
1293 39
        $length = 0x0012;
1294
1295 39
        $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...
1296 39
        $rwTop = 0x0000; // Top row visible in window
1297 39
        $colLeft = 0x0000; // Leftmost column visible in window
1298
1299
        // The options flags that comprise $grbit
1300 39
        $fDspFmla = 0; // 0 - bit
1301 39
        $fDspGrid = $this->phpSheet->getShowGridlines() ? 1 : 0; // 1
1302 39
        $fDspRwCol = $this->phpSheet->getShowRowColHeaders() ? 1 : 0; // 2
1303 39
        $fFrozen = $this->phpSheet->getFreezePane() ? 1 : 0; // 3
1304 39
        $fDspZeros = 1; // 4
1305 39
        $fDefaultHdr = 1; // 5
1306 39
        $fArabic = $this->phpSheet->getRightToLeft() ? 1 : 0; // 6
1307 39
        $fDspGuts = $this->outlineOn; // 7
1308 39
        $fFrozenNoSplit = 0; // 0 - bit
1309
        // no support in PhpSpreadsheet for selected sheet, therefore sheet is only selected if it is the active sheet
1310 39
        $fSelected = ($this->phpSheet === $this->phpSheet->getParent()->getActiveSheet()) ? 1 : 0;
1311 39
        $fPaged = 1; // 2
1312 39
        $fPageBreakPreview = $this->phpSheet->getSheetView()->getView() === SheetView::SHEETVIEW_PAGE_BREAK_PREVIEW;
1313
1314 39
        $grbit = $fDspFmla;
1315 39
        $grbit |= $fDspGrid << 1;
1316 39
        $grbit |= $fDspRwCol << 2;
1317 39
        $grbit |= $fFrozen << 3;
1318 39
        $grbit |= $fDspZeros << 4;
1319 39
        $grbit |= $fDefaultHdr << 5;
1320 39
        $grbit |= $fArabic << 6;
1321 39
        $grbit |= $fDspGuts << 7;
1322 39
        $grbit |= $fFrozenNoSplit << 8;
1323 39
        $grbit |= $fSelected << 9;
1324 39
        $grbit |= $fPaged << 10;
1325 39
        $grbit |= $fPageBreakPreview << 11;
1326
1327 39
        $header = pack('vv', $record, $length);
1328 39
        $data = pack('vvv', $grbit, $rwTop, $colLeft);
1329
1330
        // 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...
1331 39
        $rgbHdr = 0x0040; // Row/column heading and gridline color index
1332 39
        $zoom_factor_page_break = ($fPageBreakPreview ? $this->phpSheet->getSheetView()->getZoomScale() : 0x0000);
1333 39
        $zoom_factor_normal = $this->phpSheet->getSheetView()->getZoomScaleNormal();
1334
1335 39
        $data .= pack('vvvvV', $rgbHdr, 0x0000, $zoom_factor_page_break, $zoom_factor_normal, 0x00000000);
1336
1337 39
        $this->append($header . $data);
1338 39
    }
1339
1340
    /**
1341
     * Write BIFF record DEFAULTROWHEIGHT.
1342
     */
1343 39
    private function writeDefaultRowHeight()
1344
    {
1345 39
        $defaultRowHeight = $this->phpSheet->getDefaultRowDimension()->getRowHeight();
1346
1347 39
        if ($defaultRowHeight < 0) {
1348 36
            return;
1349
        }
1350
1351
        // convert to twips
1352 3
        $defaultRowHeight = (int) 20 * $defaultRowHeight;
1353
1354 3
        $record = 0x0225; // Record identifier
1355 3
        $length = 0x0004; // Number of bytes to follow
1356
1357 3
        $header = pack('vv', $record, $length);
1358 3
        $data = pack('vv', 1, $defaultRowHeight);
1359 3
        $this->append($header . $data);
1360 3
    }
1361
1362
    /**
1363
     * Write BIFF record DEFCOLWIDTH if COLINFO records are in use.
1364
     */
1365 39
    private function writeDefcol()
1366
    {
1367 39
        $defaultColWidth = 8;
1368
1369 39
        $record = 0x0055; // Record identifier
1370 39
        $length = 0x0002; // Number of bytes to follow
1371
1372 39
        $header = pack('vv', $record, $length);
1373 39
        $data = pack('v', $defaultColWidth);
1374 39
        $this->append($header . $data);
1375 39
    }
1376
1377
    /**
1378
     * Write BIFF record COLINFO to define column widths.
1379
     *
1380
     * Note: The SDK says the record length is 0x0B but Excel writes a 0x0C
1381
     * length record.
1382
     *
1383
     * @param array $col_array This is the only parameter received and is composed of the following:
1384
     *                0 => First formatted column,
1385
     *                1 => Last formatted column,
1386
     *                2 => Col width (8.43 is Excel default),
1387
     *                3 => The optional XF format of the column,
1388
     *                4 => Option flags.
1389
     *                5 => Optional outline level
1390
     */
1391 39
    private function writeColinfo($col_array)
1392
    {
1393 39
        if (isset($col_array[0])) {
1394 39
            $colFirst = $col_array[0];
1395
        }
1396 39
        if (isset($col_array[1])) {
1397 39
            $colLast = $col_array[1];
1398
        }
1399 39
        if (isset($col_array[2])) {
1400 39
            $coldx = $col_array[2];
1401
        } else {
1402
            $coldx = 8.43;
1403
        }
1404 39
        if (isset($col_array[3])) {
1405 39
            $xfIndex = $col_array[3];
1406
        } else {
1407
            $xfIndex = 15;
1408
        }
1409 39
        if (isset($col_array[4])) {
1410 39
            $grbit = $col_array[4];
1411
        } else {
1412
            $grbit = 0;
1413
        }
1414 39
        if (isset($col_array[5])) {
1415 39
            $level = $col_array[5];
1416
        } else {
1417
            $level = 0;
1418
        }
1419 39
        $record = 0x007D; // Record identifier
1420 39
        $length = 0x000C; // Number of bytes to follow
1421
1422 39
        $coldx *= 256; // Convert to units of 1/256 of a char
1423
1424 39
        $ixfe = $xfIndex;
1425 39
        $reserved = 0x0000; // Reserved
1426
1427 39
        $level = max(0, min($level, 7));
1428 39
        $grbit |= $level << 8;
1429
1430 39
        $header = pack('vv', $record, $length);
1431 39
        $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...
1432 39
        $this->append($header . $data);
1433 39
    }
1434
1435
    /**
1436
     * Write BIFF record SELECTION.
1437
     */
1438 39
    private function writeSelection()
1439
    {
1440
        // look up the selected cell range
1441 39
        $selectedCells = Cell::splitRange($this->phpSheet->getSelectedCells());
1442 39
        $selectedCells = $selectedCells[0];
1443 39
        if (count($selectedCells) == 2) {
1444 13
            list($first, $last) = $selectedCells;
1445
        } else {
1446 32
            $first = $selectedCells[0];
1447 32
            $last = $selectedCells[0];
1448
        }
1449
1450 39
        list($colFirst, $rwFirst) = Cell::coordinateFromString($first);
1451 39
        $colFirst = Cell::columnIndexFromString($colFirst) - 1; // base 0 column index
1452 39
        --$rwFirst; // base 0 row index
1453
1454 39
        list($colLast, $rwLast) = Cell::coordinateFromString($last);
1455 39
        $colLast = Cell::columnIndexFromString($colLast) - 1; // base 0 column index
1456 39
        --$rwLast; // base 0 row index
1457
1458
        // make sure we are not out of bounds
1459 39
        $colFirst = min($colFirst, 255);
1460 39
        $colLast = min($colLast, 255);
1461
1462 39
        $rwFirst = min($rwFirst, 65535);
1463 39
        $rwLast = min($rwLast, 65535);
1464
1465 39
        $record = 0x001D; // Record identifier
1466 39
        $length = 0x000F; // Number of bytes to follow
1467
1468 39
        $pnn = $this->activePane; // Pane position
1469 39
        $rwAct = $rwFirst; // Active row
1470 39
        $colAct = $colFirst; // Active column
1471 39
        $irefAct = 0; // Active cell ref
1472 39
        $cref = 1; // Number of refs
1473
1474 39
        if (!isset($rwLast)) {
1475
            $rwLast = $rwFirst; // Last  row in reference
1476
        }
1477 39
        if (!isset($colLast)) {
1478
            $colLast = $colFirst; // Last  col in reference
1479
        }
1480
1481
        // Swap last row/col for first row/col as necessary
1482 39
        if ($rwFirst > $rwLast) {
1483
            list($rwFirst, $rwLast) = [$rwLast, $rwFirst];
1484
        }
1485
1486 39
        if ($colFirst > $colLast) {
1487
            list($colFirst, $colLast) = [$colLast, $colFirst];
1488
        }
1489
1490 39
        $header = pack('vv', $record, $length);
1491 39
        $data = pack('CvvvvvvCC', $pnn, $rwAct, $colAct, $irefAct, $cref, $rwFirst, $rwLast, $colFirst, $colLast);
1492 39
        $this->append($header . $data);
1493 39
    }
1494
1495
    /**
1496
     * Store the MERGEDCELLS records for all ranges of merged cells.
1497
     */
1498 39
    private function writeMergedCells()
1499
    {
1500 39
        $mergeCells = $this->phpSheet->getMergeCells();
1501 39
        $countMergeCells = count($mergeCells);
1502
1503 39
        if ($countMergeCells == 0) {
1504 38
            return;
1505
        }
1506
1507
        // maximum allowed number of merged cells per record
1508 9
        $maxCountMergeCellsPerRecord = 1027;
1509
1510
        // record identifier
1511 9
        $record = 0x00E5;
1512
1513
        // counter for total number of merged cells treated so far by the writer
1514 9
        $i = 0;
1515
1516
        // counter for number of merged cells written in record currently being written
1517 9
        $j = 0;
1518
1519
        // initialize record data
1520 9
        $recordData = '';
1521
1522
        // loop through the merged cells
1523 9
        foreach ($mergeCells as $mergeCell) {
1524 9
            ++$i;
1525 9
            ++$j;
1526
1527
            // extract the row and column indexes
1528 9
            $range = 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...
1529 9
            list($first, $last) = $range[0];
1530 9
            list($firstColumn, $firstRow) = Cell::coordinateFromString($first);
1531 9
            list($lastColumn, $lastRow) = Cell::coordinateFromString($last);
1532
1533 9
            $recordData .= pack('vvvv', $firstRow - 1, $lastRow - 1, Cell::columnIndexFromString($firstColumn) - 1, Cell::columnIndexFromString($lastColumn) - 1);
1534
1535
            // flush record if we have reached limit for number of merged cells, or reached final merged cell
1536 9
            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...
1537 9
                $recordData = pack('v', $j) . $recordData;
1538 9
                $length = strlen($recordData);
1539 9
                $header = pack('vv', $record, $length);
1540 9
                $this->append($header . $recordData);
1541
1542
                // initialize for next record, if any
1543 9
                $recordData = '';
1544 9
                $j = 0;
1545
            }
1546
        }
1547 9
    }
1548
1549
    /**
1550
     * Write SHEETLAYOUT record.
1551
     */
1552 39
    private function writeSheetLayout()
1553
    {
1554 39
        if (!$this->phpSheet->isTabColorSet()) {
1555 39
            return;
1556
        }
1557
1558 5
        $recordData = pack(
1559 5
            'vvVVVvv',
1560 5
            0x0862,
1561 5
            0x0000, // unused
1562 5
            0x00000000, // unused
1563 5
            0x00000000, // unused
1564 5
            0x00000014, // size of record data
1565 5
            $this->colors[$this->phpSheet->getTabColor()->getRGB()], // color index
1566 5
            0x0000        // unused
1567
        );
1568
1569 5
        $length = strlen($recordData);
1570
1571 5
        $record = 0x0862; // Record identifier
1572 5
        $header = pack('vv', $record, $length);
1573 5
        $this->append($header . $recordData);
1574 5
    }
1575
1576
    /**
1577
     * Write SHEETPROTECTION.
1578
     */
1579 39
    private function writeSheetProtection()
1580
    {
1581
        // record identifier
1582 39
        $record = 0x0867;
1583
1584
        // prepare options
1585 39
        $options = (int) !$this->phpSheet->getProtection()->getObjects()
1586 39
                    | (int) !$this->phpSheet->getProtection()->getScenarios() << 1
1587 39
                    | (int) !$this->phpSheet->getProtection()->getFormatCells() << 2
1588 39
                    | (int) !$this->phpSheet->getProtection()->getFormatColumns() << 3
1589 39
                    | (int) !$this->phpSheet->getProtection()->getFormatRows() << 4
1590 39
                    | (int) !$this->phpSheet->getProtection()->getInsertColumns() << 5
1591 39
                    | (int) !$this->phpSheet->getProtection()->getInsertRows() << 6
1592 39
                    | (int) !$this->phpSheet->getProtection()->getInsertHyperlinks() << 7
1593 39
                    | (int) !$this->phpSheet->getProtection()->getDeleteColumns() << 8
1594 39
                    | (int) !$this->phpSheet->getProtection()->getDeleteRows() << 9
1595 39
                    | (int) !$this->phpSheet->getProtection()->getSelectLockedCells() << 10
1596 39
                    | (int) !$this->phpSheet->getProtection()->getSort() << 11
1597 39
                    | (int) !$this->phpSheet->getProtection()->getAutoFilter() << 12
1598 39
                    | (int) !$this->phpSheet->getProtection()->getPivotTables() << 13
1599 39
                    | (int) !$this->phpSheet->getProtection()->getSelectUnlockedCells() << 14;
1600
1601
        // record data
1602 39
        $recordData = pack(
1603 39
            'vVVCVVvv',
1604 39
            0x0867, // repeated record identifier
1605 39
            0x0000, // not used
1606 39
            0x0000, // not used
1607 39
            0x00, // not used
1608 39
            0x01000200, // unknown data
1609 39
            0xFFFFFFFF, // unknown data
1610 39
            $options, // options
1611 39
            0x0000 // not used
1612
        );
1613
1614 39
        $length = strlen($recordData);
1615 39
        $header = pack('vv', $record, $length);
1616
1617 39
        $this->append($header . $recordData);
1618 39
    }
1619
1620
    /**
1621
     * Write BIFF record RANGEPROTECTION.
1622
     *
1623
     * Openoffice.org's Documentaion of the Microsoft Excel File Format uses term RANGEPROTECTION for these records
1624
     * Microsoft Office Excel 97-2007 Binary File Format Specification uses term FEAT for these records
1625
     */
1626 39
    private function writeRangeProtection()
1627
    {
1628 39
        foreach ($this->phpSheet->getProtectedCells() as $range => $password) {
1629
            // number of ranges, e.g. 'A1:B3 C20:D25'
1630 5
            $cellRanges = explode(' ', $range);
1631 5
            $cref = count($cellRanges);
1632
1633 5
            $recordData = pack(
1634 5
                'vvVVvCVvVv',
1635 5
                0x0868,
1636 5
                0x00,
1637 5
                0x0000,
1638 5
                0x0000,
1639 5
                0x02,
1640 5
                0x0,
1641 5
                0x0000,
1642 5
                $cref,
1643 5
                0x0000,
1644 5
                0x00
1645
            );
1646
1647 5
            foreach ($cellRanges as $cellRange) {
1648 5
                $recordData .= $this->writeBIFF8CellRangeAddressFixed($cellRange);
1649
            }
1650
1651
            // the rgbFeat structure
1652 5
            $recordData .= pack(
1653 5
                'VV',
1654 5
                0x0000,
1655 5
                hexdec($password)
1656
            );
1657
1658 5
            $recordData .= StringHelper::UTF8toBIFF8UnicodeLong('p' . md5($recordData));
1659
1660 5
            $length = strlen($recordData);
1661
1662 5
            $record = 0x0868; // Record identifier
1663 5
            $header = pack('vv', $record, $length);
1664 5
            $this->append($header . $recordData);
1665
        }
1666 39
    }
1667
1668
    /**
1669
     * Write BIFF record EXTERNCOUNT to indicate the number of external sheet
1670
     * references in a worksheet.
1671
     *
1672
     * Excel only stores references to external sheets that are used in formulas.
1673
     * For simplicity we store references to all the sheets in the workbook
1674
     * regardless of whether they are used or not. This reduces the overall
1675
     * complexity and eliminates the need for a two way dialogue between the formula
1676
     * parser the worksheet objects.
1677
     *
1678
     * @param int $count The number of external sheet references in this worksheet
1679
     */
1680 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...
1681
    {
1682
        $record = 0x0016; // Record identifier
1683
        $length = 0x0002; // Number of bytes to follow
1684
1685
        $header = pack('vv', $record, $length);
1686
        $data = pack('v', $count);
1687
        $this->append($header . $data);
1688
    }
1689
1690
    /**
1691
     * Writes the Excel BIFF EXTERNSHEET record. These references are used by
1692
     * formulas. A formula references a sheet name via an index. Since we store a
1693
     * reference to all of the external worksheets the EXTERNSHEET index is the same
1694
     * as the worksheet index.
1695
     *
1696
     * @param string $sheetname The name of a external worksheet
1697
     */
1698
    private function writeExternsheet($sheetname)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
1699
    {
1700
        $record = 0x0017; // Record identifier
1701
1702
        // References to the current sheet are encoded differently to references to
1703
        // external sheets.
1704
        //
1705
        if ($this->phpSheet->getTitle() == $sheetname) {
1706
            $sheetname = '';
1707
            $length = 0x02; // The following 2 bytes
1708
            $cch = 1; // The following byte
1709
            $rgch = 0x02; // Self reference
1710
        } else {
1711
            $length = 0x02 + strlen($sheetname);
1712
            $cch = strlen($sheetname);
1713
            $rgch = 0x03; // Reference to a sheet in the current workbook
1714
        }
1715
1716
        $header = pack('vv', $record, $length);
1717
        $data = pack('CC', $cch, $rgch);
1718
        $this->append($header . $data . $sheetname);
1719
    }
1720
1721
    /**
1722
     * Writes the Excel BIFF PANE record.
1723
     * The panes can either be frozen or thawed (unfrozen).
1724
     * Frozen panes are specified in terms of an integer number of rows and columns.
1725
     * Thawed panes are specified in terms of Excel's units for rows and columns.
1726
     */
1727 3
    private function writePanes()
1728
    {
1729 3
        $panes = [];
1730 3
        if ($freezePane = $this->phpSheet->getFreezePane()) {
1731 3
            list($column, $row) = Cell::coordinateFromString($freezePane);
1732 3
            $panes[0] = $row - 1;
1733 3
            $panes[1] = Cell::columnIndexFromString($column) - 1;
1734
        } else {
1735
            // thaw panes
1736
            return;
1737
        }
1738
1739 3
        $y = isset($panes[0]) ? $panes[0] : null;
1740 3
        $x = isset($panes[1]) ? $panes[1] : null;
1741 3
        $rwTop = isset($panes[2]) ? $panes[2] : null;
1742 3
        $colLeft = isset($panes[3]) ? $panes[3] : null;
1743 3
        if (count($panes) > 4) { // if Active pane was received
1744
            $pnnAct = $panes[4];
1745
        } else {
1746 3
            $pnnAct = null;
1747
        }
1748 3
        $record = 0x0041; // Record identifier
1749 3
        $length = 0x000A; // Number of bytes to follow
1750
1751
        // Code specific to frozen or thawed panes.
1752 3
        if ($this->phpSheet->getFreezePane()) {
1753
            // 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...
1754 3
            if (!isset($rwTop)) {
1755 3
                $rwTop = $y;
1756
            }
1757 3
            if (!isset($colLeft)) {
1758 3
                $colLeft = $x;
1759
            }
1760
        } else {
1761
            // 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...
1762
            if (!isset($rwTop)) {
1763
                $rwTop = 0;
1764
            }
1765
            if (!isset($colLeft)) {
1766
                $colLeft = 0;
1767
            }
1768
1769
            // Convert Excel's row and column units to the internal units.
1770
            // The default row height is 12.75
1771
            // The default column width is 8.43
1772
            // The following slope and intersection values were interpolated.
1773
            //
1774
            $y = 20 * $y + 255;
1775
            $x = 113.879 * $x + 390;
1776
        }
1777
1778
        // Determine which pane should be active. There is also the undocumented
1779
        // option to override this should it be necessary: may be removed later.
1780
        //
1781 3
        if (!isset($pnnAct)) {
1782 3
            if ($x != 0 && $y != 0) {
1783
                $pnnAct = 0; // Bottom right
1784
            }
1785 3
            if ($x != 0 && $y == 0) {
1786
                $pnnAct = 1; // Top right
1787
            }
1788 3
            if ($x == 0 && $y != 0) {
1789 3
                $pnnAct = 2; // Bottom left
1790
            }
1791 3
            if ($x == 0 && $y == 0) {
1792
                $pnnAct = 3; // Top left
1793
            }
1794
        }
1795
1796 3
        $this->activePane = $pnnAct; // Used in writeSelection
1797
1798 3
        $header = pack('vv', $record, $length);
1799 3
        $data = pack('vvvvv', $x, $y, $rwTop, $colLeft, $pnnAct);
1800 3
        $this->append($header . $data);
1801 3
    }
1802
1803
    /**
1804
     * Store the page setup SETUP BIFF record.
1805
     */
1806 39
    private function writeSetup()
1807
    {
1808 39
        $record = 0x00A1; // Record identifier
1809 39
        $length = 0x0022; // Number of bytes to follow
1810
1811 39
        $iPaperSize = $this->phpSheet->getPageSetup()->getPaperSize(); // Paper size
1812
1813 39
        $iScale = $this->phpSheet->getPageSetup()->getScale() ?
1814 39
            $this->phpSheet->getPageSetup()->getScale() : 100; // Print scaling factor
1815
1816 39
        $iPageStart = 0x01; // Starting page number
1817 39
        $iFitWidth = (int) $this->phpSheet->getPageSetup()->getFitToWidth(); // Fit to number of pages wide
1818 39
        $iFitHeight = (int) $this->phpSheet->getPageSetup()->getFitToHeight(); // Fit to number of pages high
1819 39
        $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...
1820 39
        $iRes = 0x0258; // Print resolution
1821 39
        $iVRes = 0x0258; // Vertical print resolution
1822
1823 39
        $numHdr = $this->phpSheet->getPageMargins()->getHeader(); // Header Margin
1824
1825 39
        $numFtr = $this->phpSheet->getPageMargins()->getFooter(); // Footer Margin
1826 39
        $iCopies = 0x01; // Number of copies
1827
1828 39
        $fLeftToRight = 0x0; // Print over then down
1829
1830
        // Page orientation
1831 39
        $fLandscape = ($this->phpSheet->getPageSetup()->getOrientation() == PageSetup::ORIENTATION_LANDSCAPE) ?
1832 39
            0x0 : 0x1;
1833
1834 39
        $fNoPls = 0x0; // Setup not read from printer
1835 39
        $fNoColor = 0x0; // Print black and white
1836 39
        $fDraft = 0x0; // Print draft quality
1837 39
        $fNotes = 0x0; // Print notes
1838 39
        $fNoOrient = 0x0; // Orientation not set
1839 39
        $fUsePage = 0x0; // Use custom starting page
1840
1841 39
        $grbit = $fLeftToRight;
1842 39
        $grbit |= $fLandscape << 1;
1843 39
        $grbit |= $fNoPls << 2;
1844 39
        $grbit |= $fNoColor << 3;
1845 39
        $grbit |= $fDraft << 4;
1846 39
        $grbit |= $fNotes << 5;
1847 39
        $grbit |= $fNoOrient << 6;
1848 39
        $grbit |= $fUsePage << 7;
1849
1850 39
        $numHdr = pack('d', $numHdr);
1851 39
        $numFtr = pack('d', $numFtr);
1852 39
        if (self::getByteOrder()) { // if it's Big Endian
1853
            $numHdr = strrev($numHdr);
1854
            $numFtr = strrev($numFtr);
1855
        }
1856
1857 39
        $header = pack('vv', $record, $length);
1858 39
        $data1 = pack('vvvvvvvv', $iPaperSize, $iScale, $iPageStart, $iFitWidth, $iFitHeight, $grbit, $iRes, $iVRes);
1859 39
        $data2 = $numHdr . $numFtr;
1860 39
        $data3 = pack('v', $iCopies);
1861 39
        $this->append($header . $data1 . $data2 . $data3);
1862 39
    }
1863
1864
    /**
1865
     * Store the header caption BIFF record.
1866
     */
1867 39 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...
1868
    {
1869 39
        $record = 0x0014; // Record identifier
1870
1871
        /* 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...
1872
        // need to fix character count (multibyte!)
1873
        if (strlen($this->phpSheet->getHeaderFooter()->getOddHeader()) <= 255) {
1874
            $str      = $this->phpSheet->getHeaderFooter()->getOddHeader();       // header string
1875
        } else {
1876
            $str = '';
1877
        }
1878
        */
1879
1880 39
        $recordData = StringHelper::UTF8toBIFF8UnicodeLong($this->phpSheet->getHeaderFooter()->getOddHeader());
1881 39
        $length = strlen($recordData);
1882
1883 39
        $header = pack('vv', $record, $length);
1884
1885 39
        $this->append($header . $recordData);
1886 39
    }
1887
1888
    /**
1889
     * Store the footer caption BIFF record.
1890
     */
1891 39 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...
1892
    {
1893 39
        $record = 0x0015; // Record identifier
1894
1895
        /* 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...
1896
        // need to fix character count (multibyte!)
1897
        if (strlen($this->phpSheet->getHeaderFooter()->getOddFooter()) <= 255) {
1898
            $str = $this->phpSheet->getHeaderFooter()->getOddFooter();
1899
        } else {
1900
            $str = '';
1901
        }
1902
        */
1903
1904 39
        $recordData = StringHelper::UTF8toBIFF8UnicodeLong($this->phpSheet->getHeaderFooter()->getOddFooter());
1905 39
        $length = strlen($recordData);
1906
1907 39
        $header = pack('vv', $record, $length);
1908
1909 39
        $this->append($header . $recordData);
1910 39
    }
1911
1912
    /**
1913
     * Store the horizontal centering HCENTER BIFF record.
1914
     */
1915 39 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...
1916
    {
1917 39
        $record = 0x0083; // Record identifier
1918 39
        $length = 0x0002; // Bytes to follow
1919
1920 39
        $fHCenter = $this->phpSheet->getPageSetup()->getHorizontalCentered() ? 1 : 0; // Horizontal centering
1921
1922 39
        $header = pack('vv', $record, $length);
1923 39
        $data = pack('v', $fHCenter);
1924
1925 39
        $this->append($header . $data);
1926 39
    }
1927
1928
    /**
1929
     * Store the vertical centering VCENTER BIFF record.
1930
     */
1931 39 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...
1932
    {
1933 39
        $record = 0x0084; // Record identifier
1934 39
        $length = 0x0002; // Bytes to follow
1935
1936 39
        $fVCenter = $this->phpSheet->getPageSetup()->getVerticalCentered() ? 1 : 0; // Horizontal centering
1937
1938 39
        $header = pack('vv', $record, $length);
1939 39
        $data = pack('v', $fVCenter);
1940 39
        $this->append($header . $data);
1941 39
    }
1942
1943
    /**
1944
     * Store the LEFTMARGIN BIFF record.
1945
     */
1946 39 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...
1947
    {
1948 39
        $record = 0x0026; // Record identifier
1949 39
        $length = 0x0008; // Bytes to follow
1950
1951 39
        $margin = $this->phpSheet->getPageMargins()->getLeft(); // Margin in inches
1952
1953 39
        $header = pack('vv', $record, $length);
1954 39
        $data = pack('d', $margin);
1955 39
        if (self::getByteOrder()) { // if it's Big Endian
1956
            $data = strrev($data);
1957
        }
1958
1959 39
        $this->append($header . $data);
1960 39
    }
1961
1962
    /**
1963
     * Store the RIGHTMARGIN BIFF record.
1964
     */
1965 39 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...
1966
    {
1967 39
        $record = 0x0027; // Record identifier
1968 39
        $length = 0x0008; // Bytes to follow
1969
1970 39
        $margin = $this->phpSheet->getPageMargins()->getRight(); // Margin in inches
1971
1972 39
        $header = pack('vv', $record, $length);
1973 39
        $data = pack('d', $margin);
1974 39
        if (self::getByteOrder()) { // if it's Big Endian
1975
            $data = strrev($data);
1976
        }
1977
1978 39
        $this->append($header . $data);
1979 39
    }
1980
1981
    /**
1982
     * Store the TOPMARGIN BIFF record.
1983
     */
1984 39 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...
1985
    {
1986 39
        $record = 0x0028; // Record identifier
1987 39
        $length = 0x0008; // Bytes to follow
1988
1989 39
        $margin = $this->phpSheet->getPageMargins()->getTop(); // Margin in inches
1990
1991 39
        $header = pack('vv', $record, $length);
1992 39
        $data = pack('d', $margin);
1993 39
        if (self::getByteOrder()) { // if it's Big Endian
1994
            $data = strrev($data);
1995
        }
1996
1997 39
        $this->append($header . $data);
1998 39
    }
1999
2000
    /**
2001
     * Store the BOTTOMMARGIN BIFF record.
2002
     */
2003 39 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...
2004
    {
2005 39
        $record = 0x0029; // Record identifier
2006 39
        $length = 0x0008; // Bytes to follow
2007
2008 39
        $margin = $this->phpSheet->getPageMargins()->getBottom(); // Margin in inches
2009
2010 39
        $header = pack('vv', $record, $length);
2011 39
        $data = pack('d', $margin);
2012 39
        if (self::getByteOrder()) { // if it's Big Endian
2013
            $data = strrev($data);
2014
        }
2015
2016 39
        $this->append($header . $data);
2017 39
    }
2018
2019
    /**
2020
     * Write the PRINTHEADERS BIFF record.
2021
     */
2022 39 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...
2023
    {
2024 39
        $record = 0x002a; // Record identifier
2025 39
        $length = 0x0002; // Bytes to follow
2026
2027 39
        $fPrintRwCol = $this->printHeaders; // Boolean flag
2028
2029 39
        $header = pack('vv', $record, $length);
2030 39
        $data = pack('v', $fPrintRwCol);
2031 39
        $this->append($header . $data);
2032 39
    }
2033
2034
    /**
2035
     * Write the PRINTGRIDLINES BIFF record. Must be used in conjunction with the
2036
     * GRIDSET record.
2037
     */
2038 39 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...
2039
    {
2040 39
        $record = 0x002b; // Record identifier
2041 39
        $length = 0x0002; // Bytes to follow
2042
2043 39
        $fPrintGrid = $this->phpSheet->getPrintGridlines() ? 1 : 0; // Boolean flag
2044
2045 39
        $header = pack('vv', $record, $length);
2046 39
        $data = pack('v', $fPrintGrid);
2047 39
        $this->append($header . $data);
2048 39
    }
2049
2050
    /**
2051
     * Write the GRIDSET BIFF record. Must be used in conjunction with the
2052
     * PRINTGRIDLINES record.
2053
     */
2054 39
    private function writeGridset()
2055
    {
2056 39
        $record = 0x0082; // Record identifier
2057 39
        $length = 0x0002; // Bytes to follow
2058
2059 39
        $fGridSet = !$this->phpSheet->getPrintGridlines(); // Boolean flag
2060
2061 39
        $header = pack('vv', $record, $length);
2062 39
        $data = pack('v', $fGridSet);
2063 39
        $this->append($header . $data);
2064 39
    }
2065
2066
    /**
2067
     * Write the AUTOFILTERINFO BIFF record. This is used to configure the number of autofilter select used in the sheet.
2068
     */
2069 3
    private function writeAutoFilterInfo()
2070
    {
2071 3
        $record = 0x009D; // Record identifier
2072 3
        $length = 0x0002; // Bytes to follow
2073
2074 3
        $rangeBounds = Cell::rangeBoundaries($this->phpSheet->getAutoFilter()->getRange());
2075 3
        $iNumFilters = 1 + $rangeBounds[1][0] - $rangeBounds[0][0];
2076
2077 3
        $header = pack('vv', $record, $length);
2078 3
        $data = pack('v', $iNumFilters);
2079 3
        $this->append($header . $data);
2080 3
    }
2081
2082
    /**
2083
     * Write the GUTS BIFF record. This is used to configure the gutter margins
2084
     * where Excel outline symbols are displayed. The visibility of the gutters is
2085
     * controlled by a flag in WSBOOL.
2086
     *
2087
     * @see writeWsbool()
2088
     */
2089 39
    private function writeGuts()
2090
    {
2091 39
        $record = 0x0080; // Record identifier
2092 39
        $length = 0x0008; // Bytes to follow
2093
2094 39
        $dxRwGut = 0x0000; // Size of row gutter
2095 39
        $dxColGut = 0x0000; // Size of col gutter
2096
2097
        // determine maximum row outline level
2098 39
        $maxRowOutlineLevel = 0;
2099 39
        foreach ($this->phpSheet->getRowDimensions() as $rowDimension) {
2100 38
            $maxRowOutlineLevel = max($maxRowOutlineLevel, $rowDimension->getOutlineLevel());
2101
        }
2102
2103 39
        $col_level = 0;
2104
2105
        // Calculate the maximum column outline level. The equivalent calculation
2106
        // for the row outline level is carried out in writeRow().
2107 39
        $colcount = count($this->columnInfo);
2108 39
        for ($i = 0; $i < $colcount; ++$i) {
2109 39
            $col_level = max($this->columnInfo[$i][5], $col_level);
2110
        }
2111
2112
        // Set the limits for the outline levels (0 <= x <= 7).
2113 39
        $col_level = max(0, min($col_level, 7));
2114
2115
        // The displayed level is one greater than the max outline levels
2116 39
        if ($maxRowOutlineLevel) {
2117
            ++$maxRowOutlineLevel;
2118
        }
2119 39
        if ($col_level) {
2120 1
            ++$col_level;
2121
        }
2122
2123 39
        $header = pack('vv', $record, $length);
2124 39
        $data = pack('vvvv', $dxRwGut, $dxColGut, $maxRowOutlineLevel, $col_level);
2125
2126 39
        $this->append($header . $data);
2127 39
    }
2128
2129
    /**
2130
     * Write the WSBOOL BIFF record, mainly for fit-to-page. Used in conjunction
2131
     * with the SETUP record.
2132
     */
2133 39
    private function writeWsbool()
2134
    {
2135 39
        $record = 0x0081; // Record identifier
2136 39
        $length = 0x0002; // Bytes to follow
2137 39
        $grbit = 0x0000;
2138
2139
        // The only option that is of interest is the flag for fit to page. So we
2140
        // set all the options in one go.
2141
        //
2142
        // Set the option flags
2143 39
        $grbit |= 0x0001; // Auto page breaks visible
2144 39
        if ($this->outlineStyle) {
2145
            $grbit |= 0x0020; // Auto outline styles
2146
        }
2147 39
        if ($this->phpSheet->getShowSummaryBelow()) {
2148 39
            $grbit |= 0x0040; // Outline summary below
2149
        }
2150 39
        if ($this->phpSheet->getShowSummaryRight()) {
2151 39
            $grbit |= 0x0080; // Outline summary right
2152
        }
2153 39
        if ($this->phpSheet->getPageSetup()->getFitToPage()) {
2154
            $grbit |= 0x0100; // Page setup fit to page
2155
        }
2156 39
        if ($this->outlineOn) {
2157 39
            $grbit |= 0x0400; // Outline symbols displayed
2158
        }
2159
2160 39
        $header = pack('vv', $record, $length);
2161 39
        $data = pack('v', $grbit);
2162 39
        $this->append($header . $data);
2163 39
    }
2164
2165
    /**
2166
     * Write the HORIZONTALPAGEBREAKS and VERTICALPAGEBREAKS BIFF records.
2167
     */
2168 39
    private function writeBreaks()
2169
    {
2170
        // initialize
2171 39
        $vbreaks = [];
2172 39
        $hbreaks = [];
2173
2174 39
        foreach ($this->phpSheet->getBreaks() as $cell => $breakType) {
2175
            // Fetch coordinates
2176 1
            $coordinates = Cell::coordinateFromString($cell);
2177
2178
            // Decide what to do by the type of break
2179
            switch ($breakType) {
2180 1
                case \PhpOffice\PhpSpreadsheet\Worksheet::BREAK_COLUMN:
2181
                    // Add to list of vertical breaks
2182
                    $vbreaks[] = Cell::columnIndexFromString($coordinates[0]) - 1;
2183
                    break;
2184 1
                case \PhpOffice\PhpSpreadsheet\Worksheet::BREAK_ROW:
2185
                    // Add to list of horizontal breaks
2186 1
                    $hbreaks[] = $coordinates[1];
2187 1
                    break;
2188
                case \PhpOffice\PhpSpreadsheet\Worksheet::BREAK_NONE:
2189
                default:
2190
                    // Nothing to do
2191 1
                    break;
2192
            }
2193
        }
2194
2195
        //horizontal page breaks
2196 39
        if (!empty($hbreaks)) {
2197
            // Sort and filter array of page breaks
2198 1
            sort($hbreaks, SORT_NUMERIC);
2199 1
            if ($hbreaks[0] == 0) { // don't use first break if it's 0
2200
                array_shift($hbreaks);
2201
            }
2202
2203 1
            $record = 0x001b; // Record identifier
2204 1
            $cbrk = count($hbreaks); // Number of page breaks
2205 1
            $length = 2 + 6 * $cbrk; // Bytes to follow
2206
2207 1
            $header = pack('vv', $record, $length);
2208 1
            $data = pack('v', $cbrk);
2209
2210
            // Append each page break
2211 1
            foreach ($hbreaks as $hbreak) {
2212 1
                $data .= pack('vvv', $hbreak, 0x0000, 0x00ff);
2213
            }
2214
2215 1
            $this->append($header . $data);
2216
        }
2217
2218
        // vertical page breaks
2219 39
        if (!empty($vbreaks)) {
2220
            // 1000 vertical pagebreaks appears to be an internal Excel 5 limit.
2221
            // It is slightly higher in Excel 97/200, approx. 1026
2222
            $vbreaks = array_slice($vbreaks, 0, 1000);
2223
2224
            // Sort and filter array of page breaks
2225
            sort($vbreaks, SORT_NUMERIC);
2226
            if ($vbreaks[0] == 0) { // don't use first break if it's 0
2227
                array_shift($vbreaks);
2228
            }
2229
2230
            $record = 0x001a; // Record identifier
2231
            $cbrk = count($vbreaks); // Number of page breaks
2232
            $length = 2 + 6 * $cbrk; // Bytes to follow
2233
2234
            $header = pack('vv', $record, $length);
2235
            $data = pack('v', $cbrk);
2236
2237
            // Append each page break
2238
            foreach ($vbreaks as $vbreak) {
2239
                $data .= pack('vvv', $vbreak, 0x0000, 0xffff);
2240
            }
2241
2242
            $this->append($header . $data);
2243
        }
2244 39
    }
2245
2246
    /**
2247
     * Set the Biff PROTECT record to indicate that the worksheet is protected.
2248
     */
2249 39 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...
2250
    {
2251
        // Exit unless sheet protection has been specified
2252 39
        if (!$this->phpSheet->getProtection()->getSheet()) {
2253 37
            return;
2254
        }
2255
2256 7
        $record = 0x0012; // Record identifier
2257 7
        $length = 0x0002; // Bytes to follow
2258
2259 7
        $fLock = 1; // Worksheet is protected
2260
2261 7
        $header = pack('vv', $record, $length);
2262 7
        $data = pack('v', $fLock);
2263
2264 7
        $this->append($header . $data);
2265 7
    }
2266
2267
    /**
2268
     * Write SCENPROTECT.
2269
     */
2270 39 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...
2271
    {
2272
        // Exit if sheet protection is not active
2273 39
        if (!$this->phpSheet->getProtection()->getSheet()) {
2274 37
            return;
2275
        }
2276
2277
        // Exit if scenarios are not protected
2278 7
        if (!$this->phpSheet->getProtection()->getScenarios()) {
2279 7
            return;
2280
        }
2281
2282
        $record = 0x00DD; // Record identifier
2283
        $length = 0x0002; // Bytes to follow
2284
2285
        $header = pack('vv', $record, $length);
2286
        $data = pack('v', 1);
2287
2288
        $this->append($header . $data);
2289
    }
2290
2291
    /**
2292
     * Write OBJECTPROTECT.
2293
     */
2294 39 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...
2295
    {
2296
        // Exit if sheet protection is not active
2297 39
        if (!$this->phpSheet->getProtection()->getSheet()) {
2298 37
            return;
2299
        }
2300
2301
        // Exit if objects are not protected
2302 7
        if (!$this->phpSheet->getProtection()->getObjects()) {
2303 7
            return;
2304
        }
2305
2306
        $record = 0x0063; // Record identifier
2307
        $length = 0x0002; // Bytes to follow
2308
2309
        $header = pack('vv', $record, $length);
2310
        $data = pack('v', 1);
2311
2312
        $this->append($header . $data);
2313
    }
2314
2315
    /**
2316
     * Write the worksheet PASSWORD record.
2317
     */
2318 39
    private function writePassword()
2319
    {
2320
        // Exit unless sheet protection and password have been specified
2321 39
        if (!$this->phpSheet->getProtection()->getSheet() || !$this->phpSheet->getProtection()->getPassword()) {
2322 38
            return;
2323
        }
2324
2325 1
        $record = 0x0013; // Record identifier
2326 1
        $length = 0x0002; // Bytes to follow
2327
2328 1
        $wPassword = hexdec($this->phpSheet->getProtection()->getPassword()); // Encoded password
2329
2330 1
        $header = pack('vv', $record, $length);
2331 1
        $data = pack('v', $wPassword);
2332
2333 1
        $this->append($header . $data);
2334 1
    }
2335
2336
    /**
2337
     * Insert a 24bit bitmap image in a worksheet.
2338
     *
2339
     * @param int $row The row we are going to insert the bitmap into
2340
     * @param int $col The column we are going to insert the bitmap into
2341
     * @param mixed $bitmap The bitmap filename or GD-image resource
2342
     * @param int $x the horizontal position (offset) of the image inside the cell
2343
     * @param int $y the vertical position (offset) of the image inside the cell
2344
     * @param float $scale_x The horizontal scale
2345
     * @param float $scale_y The vertical scale
2346
     */
2347
    public function insertBitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1)
2348
    {
2349
        $bitmap_array = (is_resource($bitmap) ? $this->processBitmapGd($bitmap) : $this->processBitmap($bitmap));
2350
        list($width, $height, $size, $data) = $bitmap_array;
2351
2352
        // Scale the frame of the image.
2353
        $width *= $scale_x;
2354
        $height *= $scale_y;
2355
2356
        // Calculate the vertices of the image and write the OBJ record
2357
        $this->positionImage($col, $row, $x, $y, $width, $height);
2358
2359
        // Write the IMDATA record to store the bitmap data
2360
        $record = 0x007f;
2361
        $length = 8 + $size;
2362
        $cf = 0x09;
2363
        $env = 0x01;
2364
        $lcb = $size;
2365
2366
        $header = pack('vvvvV', $record, $length, $cf, $env, $lcb);
2367
        $this->append($header . $data);
2368
    }
2369
2370
    /**
2371
     * Calculate the vertices that define the position of the image as required by
2372
     * the OBJ record.
2373
     *
2374
     *         +------------+------------+
2375
     *         |     A      |      B     |
2376
     *   +-----+------------+------------+
2377
     *   |     |(x1,y1)     |            |
2378
     *   |  1  |(A1)._______|______      |
2379
     *   |     |    |              |     |
2380
     *   |     |    |              |     |
2381
     *   +-----+----|    BITMAP    |-----+
2382
     *   |     |    |              |     |
2383
     *   |  2  |    |______________.     |
2384
     *   |     |            |        (B2)|
2385
     *   |     |            |     (x2,y2)|
2386
     *   +---- +------------+------------+
2387
     *
2388
     * Example of a bitmap that covers some of the area from cell A1 to cell B2.
2389
     *
2390
     * Based on the width and height of the bitmap we need to calculate 8 vars:
2391
     *     $col_start, $row_start, $col_end, $row_end, $x1, $y1, $x2, $y2.
2392
     * The width and height of the cells are also variable and have to be taken into
2393
     * account.
2394
     * The values of $col_start and $row_start are passed in from the calling
2395
     * function. The values of $col_end and $row_end are calculated by subtracting
2396
     * the width and height of the bitmap from the width and height of the
2397
     * underlying cells.
2398
     * The vertices are expressed as a percentage of the underlying cell width as
2399
     * follows (rhs values are in pixels):
2400
     *
2401
     *       x1 = X / W *1024
2402
     *       y1 = Y / H *256
2403
     *       x2 = (X-1) / W *1024
2404
     *       y2 = (Y-1) / H *256
2405
     *
2406
     *       Where:  X is distance from the left side of the underlying cell
2407
     *               Y is distance from the top of the underlying cell
2408
     *               W is the width of the cell
2409
     *               H is the height of the cell
2410
     * The SDK incorrectly states that the height should be expressed as a
2411
     *        percentage of 1024.
2412
     *
2413
     * @param int $col_start Col containing upper left corner of object
2414
     * @param int $row_start Row containing top left corner of object
2415
     * @param int $x1 Distance to left side of object
2416
     * @param int $y1 Distance to top of object
2417
     * @param int $width Width of image frame
2418
     * @param int $height Height of image frame
2419
     */
2420
    public function positionImage($col_start, $row_start, $x1, $y1, $width, $height)
2421
    {
2422
        // Initialise end cell to the same as the start cell
2423
        $col_end = $col_start; // Col containing lower right corner of object
2424
        $row_end = $row_start; // Row containing bottom right corner of object
2425
2426
        // Zero the specified offset if greater than the cell dimensions
2427
        if ($x1 >= Xls::sizeCol($this->phpSheet, Cell::stringFromColumnIndex($col_start))) {
2428
            $x1 = 0;
2429
        }
2430
        if ($y1 >= Xls::sizeRow($this->phpSheet, $row_start + 1)) {
2431
            $y1 = 0;
2432
        }
2433
2434
        $width = $width + $x1 - 1;
2435
        $height = $height + $y1 - 1;
2436
2437
        // Subtract the underlying cell widths to find the end cell of the image
2438
        while ($width >= Xls::sizeCol($this->phpSheet, Cell::stringFromColumnIndex($col_end))) {
2439
            $width -= Xls::sizeCol($this->phpSheet, Cell::stringFromColumnIndex($col_end));
2440
            ++$col_end;
2441
        }
2442
2443
        // Subtract the underlying cell heights to find the end cell of the image
2444
        while ($height >= Xls::sizeRow($this->phpSheet, $row_end + 1)) {
2445
            $height -= Xls::sizeRow($this->phpSheet, $row_end + 1);
2446
            ++$row_end;
2447
        }
2448
2449
        // Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell
2450
        // with zero eight or width.
2451
        //
2452
        if (Xls::sizeCol($this->phpSheet, Cell::stringFromColumnIndex($col_start)) == 0) {
2453
            return;
2454
        }
2455
        if (Xls::sizeCol($this->phpSheet, Cell::stringFromColumnIndex($col_end)) == 0) {
2456
            return;
2457
        }
2458
        if (Xls::sizeRow($this->phpSheet, $row_start + 1) == 0) {
2459
            return;
2460
        }
2461
        if (Xls::sizeRow($this->phpSheet, $row_end + 1) == 0) {
2462
            return;
2463
        }
2464
2465
        // Convert the pixel values to the percentage value expected by Excel
2466
        $x1 = $x1 / Xls::sizeCol($this->phpSheet, Cell::stringFromColumnIndex($col_start)) * 1024;
2467
        $y1 = $y1 / Xls::sizeRow($this->phpSheet, $row_start + 1) * 256;
2468
        $x2 = $width / Xls::sizeCol($this->phpSheet, Cell::stringFromColumnIndex($col_end)) * 1024; // Distance to right side of object
2469
        $y2 = $height / Xls::sizeRow($this->phpSheet, $row_end + 1) * 256; // Distance to bottom of object
2470
2471
        $this->writeObjPicture($col_start, $x1, $row_start, $y1, $col_end, $x2, $row_end, $y2);
2472
    }
2473
2474
    /**
2475
     * Store the OBJ record that precedes an IMDATA record. This could be generalise
2476
     * to support other Excel objects.
2477
     *
2478
     * @param int $colL Column containing upper left corner of object
2479
     * @param int $dxL Distance from left side of cell
2480
     * @param int $rwT Row containing top left corner of object
2481
     * @param int $dyT Distance from top of cell
2482
     * @param int $colR Column containing lower right corner of object
2483
     * @param int $dxR Distance from right of cell
2484
     * @param int $rwB Row containing bottom right corner of object
2485
     * @param int $dyB Distance from bottom of cell
2486
     */
2487
    private function writeObjPicture($colL, $dxL, $rwT, $dyT, $colR, $dxR, $rwB, $dyB)
2488
    {
2489
        $record = 0x005d; // Record identifier
2490
        $length = 0x003c; // Bytes to follow
2491
2492
        $cObj = 0x0001; // Count of objects in file (set to 1)
2493
        $OT = 0x0008; // Object type. 8 = Picture
2494
        $id = 0x0001; // Object ID
2495
        $grbit = 0x0614; // Option flags
2496
2497
        $cbMacro = 0x0000; // Length of FMLA structure
2498
        $Reserved1 = 0x0000; // Reserved
2499
        $Reserved2 = 0x0000; // Reserved
2500
2501
        $icvBack = 0x09; // Background colour
2502
        $icvFore = 0x09; // Foreground colour
2503
        $fls = 0x00; // Fill pattern
2504
        $fAuto = 0x00; // Automatic fill
2505
        $icv = 0x08; // Line colour
2506
        $lns = 0xff; // Line style
2507
        $lnw = 0x01; // Line weight
2508
        $fAutoB = 0x00; // Automatic border
2509
        $frs = 0x0000; // Frame style
2510
        $cf = 0x0009; // Image format, 9 = bitmap
2511
        $Reserved3 = 0x0000; // Reserved
2512
        $cbPictFmla = 0x0000; // Length of FMLA structure
2513
        $Reserved4 = 0x0000; // Reserved
2514
        $grbit2 = 0x0001; // Option flags
2515
        $Reserved5 = 0x0000; // Reserved
2516
2517
        $header = pack('vv', $record, $length);
2518
        $data = pack('V', $cObj);
2519
        $data .= pack('v', $OT);
2520
        $data .= pack('v', $id);
2521
        $data .= pack('v', $grbit);
2522
        $data .= pack('v', $colL);
2523
        $data .= pack('v', $dxL);
2524
        $data .= pack('v', $rwT);
2525
        $data .= pack('v', $dyT);
2526
        $data .= pack('v', $colR);
2527
        $data .= pack('v', $dxR);
2528
        $data .= pack('v', $rwB);
2529
        $data .= pack('v', $dyB);
2530
        $data .= pack('v', $cbMacro);
2531
        $data .= pack('V', $Reserved1);
2532
        $data .= pack('v', $Reserved2);
2533
        $data .= pack('C', $icvBack);
2534
        $data .= pack('C', $icvFore);
2535
        $data .= pack('C', $fls);
2536
        $data .= pack('C', $fAuto);
2537
        $data .= pack('C', $icv);
2538
        $data .= pack('C', $lns);
2539
        $data .= pack('C', $lnw);
2540
        $data .= pack('C', $fAutoB);
2541
        $data .= pack('v', $frs);
2542
        $data .= pack('V', $cf);
2543
        $data .= pack('v', $Reserved3);
2544
        $data .= pack('v', $cbPictFmla);
2545
        $data .= pack('v', $Reserved4);
2546
        $data .= pack('v', $grbit2);
2547
        $data .= pack('V', $Reserved5);
2548
2549
        $this->append($header . $data);
2550
    }
2551
2552
    /**
2553
     * Convert a GD-image into the internal format.
2554
     *
2555
     * @param resource $image The image to process
2556
     *
2557
     * @return array Array with data and properties of the bitmap
2558
     */
2559
    public function processBitmapGd($image)
2560
    {
2561
        $width = imagesx($image);
2562
        $height = imagesy($image);
2563
2564
        $data = pack('Vvvvv', 0x000c, $width, $height, 0x01, 0x18);
2565
        for ($j = $height; --$j;) {
2566
            for ($i = 0; $i < $width; ++$i) {
2567
                $color = imagecolorsforindex($image, imagecolorat($image, $i, $j));
2568
                foreach (['red', 'green', 'blue'] as $key) {
2569
                    $color[$key] = $color[$key] + round((255 - $color[$key]) * $color['alpha'] / 127);
2570
                }
2571
                $data .= chr($color['blue']) . chr($color['green']) . chr($color['red']);
2572
            }
2573
            if (3 * $width % 4) {
2574
                $data .= str_repeat("\x00", 4 - 3 * $width % 4);
2575
            }
2576
        }
2577
2578
        return [$width, $height, strlen($data), $data];
2579
    }
2580
2581
    /**
2582
     * Convert a 24 bit bitmap into the modified internal format used by Windows.
2583
     * This is described in BITMAPCOREHEADER and BITMAPCOREINFO structures in the
2584
     * MSDN library.
2585
     *
2586
     * @param string $bitmap The bitmap to process
2587
     *
2588
     * @return array Array with data and properties of the bitmap
2589
     */
2590
    public function processBitmap($bitmap)
2591
    {
2592
        // Open file.
2593
        $bmp_fd = @fopen($bitmap, 'rb');
2594
        if (!$bmp_fd) {
2595
            throw new WriterException("Couldn't import $bitmap");
2596
        }
2597
2598
        // Slurp the file into a string.
2599
        $data = fread($bmp_fd, filesize($bitmap));
2600
2601
        // Check that the file is big enough to be a bitmap.
2602
        if (strlen($data) <= 0x36) {
2603
            throw new WriterException("$bitmap doesn't contain enough data.\n");
2604
        }
2605
2606
        // The first 2 bytes are used to identify the bitmap.
2607
        $identity = unpack('A2ident', $data);
2608
        if ($identity['ident'] != 'BM') {
2609
            throw new WriterException("$bitmap doesn't appear to be a valid bitmap image.\n");
2610
        }
2611
2612
        // Remove bitmap data: ID.
2613
        $data = substr($data, 2);
2614
2615
        // Read and remove the bitmap size. This is more reliable than reading
2616
        // the data size at offset 0x22.
2617
        //
2618
        $size_array = unpack('Vsa', substr($data, 0, 4));
2619
        $size = $size_array['sa'];
2620
        $data = substr($data, 4);
2621
        $size -= 0x36; // Subtract size of bitmap header.
2622
        $size += 0x0C; // Add size of BIFF header.
2623
2624
        // Remove bitmap data: reserved, offset, header length.
2625
        $data = substr($data, 12);
2626
2627
        // Read and remove the bitmap width and height. Verify the sizes.
2628
        $width_and_height = unpack('V2', substr($data, 0, 8));
2629
        $width = $width_and_height[1];
2630
        $height = $width_and_height[2];
2631
        $data = substr($data, 8);
2632
        if ($width > 0xFFFF) {
2633
            throw new WriterException("$bitmap: largest image width supported is 65k.\n");
2634
        }
2635
        if ($height > 0xFFFF) {
2636
            throw new WriterException("$bitmap: largest image height supported is 65k.\n");
2637
        }
2638
2639
        // Read and remove the bitmap planes and bpp data. Verify them.
2640
        $planes_and_bitcount = unpack('v2', substr($data, 0, 4));
2641
        $data = substr($data, 4);
2642
        if ($planes_and_bitcount[2] != 24) { // Bitcount
2643
            throw new WriterException("$bitmap isn't a 24bit true color bitmap.\n");
2644
        }
2645
        if ($planes_and_bitcount[1] != 1) {
2646
            throw new WriterException("$bitmap: only 1 plane supported in bitmap image.\n");
2647
        }
2648
2649
        // Read and remove the bitmap compression. Verify compression.
2650
        $compression = unpack('Vcomp', substr($data, 0, 4));
2651
        $data = substr($data, 4);
2652
2653
        if ($compression['comp'] != 0) {
2654
            throw new WriterException("$bitmap: compression not supported in bitmap image.\n");
2655
        }
2656
2657
        // Remove bitmap data: data size, hres, vres, colours, imp. colours.
2658
        $data = substr($data, 20);
2659
2660
        // Add the BITMAPCOREHEADER data
2661
        $header = pack('Vvvvv', 0x000c, $width, $height, 0x01, 0x18);
2662
        $data = $header . $data;
2663
2664
        return [$width, $height, $size, $data];
2665
    }
2666
2667
    /**
2668
     * Store the window zoom factor. This should be a reduced fraction but for
2669
     * simplicity we will store all fractions with a numerator of 100.
2670
     */
2671 39 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...
2672
    {
2673
        // If scale is 100 we don't need to write a record
2674 39
        if ($this->phpSheet->getSheetView()->getZoomScale() == 100) {
2675 39
            return;
2676
        }
2677
2678
        $record = 0x00A0; // Record identifier
2679
        $length = 0x0004; // Bytes to follow
2680
2681
        $header = pack('vv', $record, $length);
2682
        $data = pack('vv', $this->phpSheet->getSheetView()->getZoomScale(), 100);
2683
        $this->append($header . $data);
2684
    }
2685
2686
    /**
2687
     * Get Escher object.
2688
     *
2689
     * @return \PhpOffice\PhpSpreadsheet\Shared\Escher
2690
     */
2691
    public function getEscher()
2692
    {
2693
        return $this->escher;
2694
    }
2695
2696
    /**
2697
     * Set Escher object.
2698
     *
2699
     * @param \PhpOffice\PhpSpreadsheet\Shared\Escher $pValue
2700
     */
2701 10
    public function setEscher(\PhpOffice\PhpSpreadsheet\Shared\Escher $pValue = null)
2702
    {
2703 10
        $this->escher = $pValue;
2704 10
    }
2705
2706
    /**
2707
     * Write MSODRAWING record.
2708
     */
2709 39
    private function writeMsoDrawing()
2710
    {
2711
        // write the Escher stream if necessary
2712 39
        if (isset($this->escher)) {
2713 10
            $writer = new Escher($this->escher);
2714 10
            $data = $writer->close();
2715 10
            $spOffsets = $writer->getSpOffsets();
2716 10
            $spTypes = $writer->getSpTypes();
2717
            // write the neccesary MSODRAWING, OBJ records
2718
2719
            // split the Escher stream
2720 10
            $spOffsets[0] = 0;
2721 10
            $nm = count($spOffsets) - 1; // number of shapes excluding first shape
2722 10
            for ($i = 1; $i <= $nm; ++$i) {
2723
                // MSODRAWING record
2724 10
                $record = 0x00EC; // Record identifier
2725
2726
                // chunk of Escher stream for one shape
2727 10
                $dataChunk = substr($data, $spOffsets[$i - 1], $spOffsets[$i] - $spOffsets[$i - 1]);
2728
2729 10
                $length = strlen($dataChunk);
2730 10
                $header = pack('vv', $record, $length);
2731
2732 10
                $this->append($header . $dataChunk);
2733
2734
                // OBJ record
2735 10
                $record = 0x005D; // record identifier
2736 10
                $objData = '';
2737
2738
                // ftCmo
2739 10
                if ($spTypes[$i] == 0x00C9) {
2740
                    // Add ftCmo (common object data) subobject
2741
                    $objData .=
2742 3
                        pack(
2743 3
                            'vvvvvVVV',
2744 3
                            0x0015, // 0x0015 = ftCmo
2745 3
                            0x0012, // length of ftCmo data
2746 3
                            0x0014, // object type, 0x0014 = filter
2747 3
                            $i, // object id number, Excel seems to use 1-based index, local for the sheet
2748 3
                            0x2101, // option flags, 0x2001 is what OpenOffice.org uses
2749 3
                            0, // reserved
2750 3
                            0, // reserved
2751 3
                            0  // reserved
2752
                        );
2753
2754
                    // Add ftSbs Scroll bar subobject
2755 3
                    $objData .= pack('vv', 0x00C, 0x0014);
2756 3
                    $objData .= pack('H*', '0000000000000000640001000A00000010000100');
2757
                    // Add ftLbsData (List box data) subobject
2758 3
                    $objData .= pack('vv', 0x0013, 0x1FEE);
2759 3
                    $objData .= pack('H*', '00000000010001030000020008005700');
2760
                } else {
2761
                    // Add ftCmo (common object data) subobject
2762
                    $objData .=
2763 7
                        pack(
2764 7
                            'vvvvvVVV',
2765 7
                            0x0015, // 0x0015 = ftCmo
2766 7
                            0x0012, // length of ftCmo data
2767 7
                            0x0008, // object type, 0x0008 = picture
2768 7
                            $i, // object id number, Excel seems to use 1-based index, local for the sheet
2769 7
                            0x6011, // option flags, 0x6011 is what OpenOffice.org uses
2770 7
                            0, // reserved
2771 7
                            0, // reserved
2772 7
                            0  // reserved
2773
                        );
2774
                }
2775
2776
                // ftEnd
2777
                $objData .=
2778 10
                    pack(
2779 10
                        'vv',
2780 10
                        0x0000, // 0x0000 = ftEnd
2781 10
                        0x0000  // length of ftEnd data
2782
                    );
2783
2784 10
                $length = strlen($objData);
2785 10
                $header = pack('vv', $record, $length);
2786 10
                $this->append($header . $objData);
2787
            }
2788
        }
2789 39
    }
2790
2791
    /**
2792
     * Store the DATAVALIDATIONS and DATAVALIDATION records.
2793
     *
2794
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
2795
     */
2796 39
    private function writeDataValidity()
2797
    {
2798
        // Datavalidation collection
2799 39
        $dataValidationCollection = $this->phpSheet->getDataValidationCollection();
2800
2801
        // Write data validations?
2802 39
        if (!empty($dataValidationCollection)) {
2803
            // DATAVALIDATIONS record
2804 2
            $record = 0x01B2; // Record identifier
2805 2
            $length = 0x0012; // Bytes to follow
2806
2807 2
            $grbit = 0x0000; // Prompt box at cell, no cached validity data at DV records
2808 2
            $horPos = 0x00000000; // Horizontal position of prompt box, if fixed position
2809 2
            $verPos = 0x00000000; // Vertical position of prompt box, if fixed position
2810 2
            $objId = 0xFFFFFFFF; // Object identifier of drop down arrow object, or -1 if not visible
2811
2812 2
            $header = pack('vv', $record, $length);
2813 2
            $data = pack('vVVVV', $grbit, $horPos, $verPos, $objId, count($dataValidationCollection));
2814 2
            $this->append($header . $data);
2815
2816
            // DATAVALIDATION records
2817 2
            $record = 0x01BE; // Record identifier
2818
2819 2
            foreach ($dataValidationCollection as $cellCoordinate => $dataValidation) {
2820
                // initialize record data
2821 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...
2822
2823
                // options
2824 2
                $options = 0x00000000;
2825
2826
                // data type
2827 2
                $type = 0x00;
2828 2 View Code Duplication
                switch ($dataValidation->getType()) {
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...
2829 2
                    case DataValidation::TYPE_NONE:
2830
                        $type = 0x00;
2831
                        break;
2832 2
                    case DataValidation::TYPE_WHOLE:
2833
                        $type = 0x01;
2834
                        break;
2835 2
                    case DataValidation::TYPE_DECIMAL:
2836
                        $type = 0x02;
2837
                        break;
2838 2
                    case DataValidation::TYPE_LIST:
2839
                        $type = 0x03;
2840
                        break;
2841 2
                    case DataValidation::TYPE_DATE:
2842
                        $type = 0x04;
2843
                        break;
2844 2
                    case DataValidation::TYPE_TIME:
2845
                        $type = 0x05;
2846
                        break;
2847 2
                    case DataValidation::TYPE_TEXTLENGTH:
2848
                        $type = 0x06;
2849
                        break;
2850 2
                    case DataValidation::TYPE_CUSTOM:
2851
                        $type = 0x07;
2852
                        break;
2853
                }
2854
2855 2
                $options |= $type << 0;
2856
2857
                // error style
2858 2
                $errorStyle = 0x00;
2859 2 View Code Duplication
                switch ($dataValidation->getErrorStyle()) {
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...
2860 2
                    case DataValidation::STYLE_STOP:
2861
                        $errorStyle = 0x00;
2862
                        break;
2863 2
                    case DataValidation::STYLE_WARNING:
2864
                        $errorStyle = 0x01;
2865
                        break;
2866 2
                    case DataValidation::STYLE_INFORMATION:
2867
                        $errorStyle = 0x02;
2868
                        break;
2869
                }
2870
2871 2
                $options |= $errorStyle << 4;
2872
2873
                // explicit formula?
2874 2
                if ($type == 0x03 && preg_match('/^\".*\"$/', $dataValidation->getFormula1())) {
2875
                    $options |= 0x01 << 7;
2876
                }
2877
2878
                // empty cells allowed
2879 2
                $options |= $dataValidation->getAllowBlank() << 8;
2880
2881
                // show drop down
2882 2
                $options |= (!$dataValidation->getShowDropDown()) << 9;
2883
2884
                // show input message
2885 2
                $options |= $dataValidation->getShowInputMessage() << 18;
2886
2887
                // show error message
2888 2
                $options |= $dataValidation->getShowErrorMessage() << 19;
2889
2890
                // condition operator
2891 2
                $operator = 0x00;
2892 2 View Code Duplication
                switch ($dataValidation->getOperator()) {
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...
2893 2
                    case DataValidation::OPERATOR_BETWEEN:
2894 2
                        $operator = 0x00;
2895 2
                        break;
2896
                    case DataValidation::OPERATOR_NOTBETWEEN:
2897
                        $operator = 0x01;
2898
                        break;
2899
                    case DataValidation::OPERATOR_EQUAL:
2900
                        $operator = 0x02;
2901
                        break;
2902
                    case DataValidation::OPERATOR_NOTEQUAL:
2903
                        $operator = 0x03;
2904
                        break;
2905
                    case DataValidation::OPERATOR_GREATERTHAN:
2906
                        $operator = 0x04;
2907
                        break;
2908
                    case DataValidation::OPERATOR_LESSTHAN:
2909
                        $operator = 0x05;
2910
                        break;
2911
                    case DataValidation::OPERATOR_GREATERTHANOREQUAL:
2912
                        $operator = 0x06;
2913
                        break;
2914
                    case DataValidation::OPERATOR_LESSTHANOREQUAL:
2915
                        $operator = 0x07;
2916
                        break;
2917
                }
2918
2919 2
                $options |= $operator << 20;
2920
2921 2
                $data = pack('V', $options);
2922
2923
                // prompt title
2924 2
                $promptTitle = $dataValidation->getPromptTitle() !== '' ?
2925 2
                    $dataValidation->getPromptTitle() : chr(0);
2926 2
                $data .= StringHelper::UTF8toBIFF8UnicodeLong($promptTitle);
2927
2928
                // error title
2929 2
                $errorTitle = $dataValidation->getErrorTitle() !== '' ?
2930 2
                    $dataValidation->getErrorTitle() : chr(0);
2931 2
                $data .= StringHelper::UTF8toBIFF8UnicodeLong($errorTitle);
2932
2933
                // prompt text
2934 2
                $prompt = $dataValidation->getPrompt() !== '' ?
2935 2
                    $dataValidation->getPrompt() : chr(0);
2936 2
                $data .= StringHelper::UTF8toBIFF8UnicodeLong($prompt);
2937
2938
                // error text
2939 2
                $error = $dataValidation->getError() !== '' ?
2940 2
                    $dataValidation->getError() : chr(0);
2941 2
                $data .= StringHelper::UTF8toBIFF8UnicodeLong($error);
2942
2943
                // formula 1
2944
                try {
2945 2
                    $formula1 = $dataValidation->getFormula1();
2946 2
                    if ($type == 0x03) { // list type
2947
                        $formula1 = str_replace(',', chr(0), $formula1);
2948
                    }
2949 2
                    $this->parser->parse($formula1);
2950 1
                    $formula1 = $this->parser->toReversePolish();
2951 1
                    $sz1 = strlen($formula1);
2952 2
                } catch (PhpSpreadsheetException $e) {
2953 2
                    $sz1 = 0;
2954 2
                    $formula1 = '';
2955
                }
2956 2
                $data .= pack('vv', $sz1, 0x0000);
2957 2
                $data .= $formula1;
2958
2959
                // formula 2
2960
                try {
2961 2
                    $formula2 = $dataValidation->getFormula2();
2962 2
                    if ($formula2 === '') {
2963 2
                        throw new WriterException('No formula2');
2964
                    }
2965 1
                    $this->parser->parse($formula2);
2966
                    $formula2 = $this->parser->toReversePolish();
2967
                    $sz2 = strlen($formula2);
2968 2
                } catch (PhpSpreadsheetException $e) {
2969 2
                    $sz2 = 0;
2970 2
                    $formula2 = '';
2971
                }
2972 2
                $data .= pack('vv', $sz2, 0x0000);
2973 2
                $data .= $formula2;
2974
2975
                // cell range address list
2976 2
                $data .= pack('v', 0x0001);
2977 2
                $data .= $this->writeBIFF8CellRangeAddressFixed($cellCoordinate);
2978
2979 2
                $length = strlen($data);
2980 2
                $header = pack('vv', $record, $length);
2981
2982 2
                $this->append($header . $data);
2983
            }
2984
        }
2985 39
    }
2986
2987
    /**
2988
     * Map Error code.
2989
     *
2990
     * @param string $errorCode
2991
     *
2992
     * @return int
2993
     */
2994 4
    private static function mapErrorCode($errorCode)
2995
    {
2996
        switch ($errorCode) {
2997 4
            case '#NULL!':
2998
                return 0x00;
2999 4
            case '#DIV/0!':
3000 3
                return 0x07;
3001 2
            case '#VALUE!':
3002 1
                return 0x0F;
3003 1
            case '#REF!':
3004
                return 0x17;
3005 1
            case '#NAME?':
3006
                return 0x1D;
3007 1
            case '#NUM!':
3008
                return 0x24;
3009 1
            case '#N/A':
3010 1
                return 0x2A;
3011
        }
3012
3013
        return 0;
3014
    }
3015
3016
    /**
3017
     * Write PLV Record.
3018
     */
3019 39
    private function writePageLayoutView()
3020
    {
3021 39
        $record = 0x088B; // Record identifier
3022 39
        $length = 0x0010; // Bytes to follow
3023
3024 39
        $rt = 0x088B; // 2
3025 39
        $grbitFrt = 0x0000; // 2
3026 39
        $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...
3027 39
        $wScalvePLV = $this->phpSheet->getSheetView()->getZoomScale(); // 2
3028
3029
        // The options flags that comprise $grbit
3030 39
        if ($this->phpSheet->getSheetView()->getView() == SheetView::SHEETVIEW_PAGE_LAYOUT) {
3031 1
            $fPageLayoutView = 1;
3032
        } else {
3033 38
            $fPageLayoutView = 0;
3034
        }
3035 39
        $fRulerVisible = 0;
3036 39
        $fWhitespaceHidden = 0;
3037
3038 39
        $grbit = $fPageLayoutView; // 2
3039 39
        $grbit |= $fRulerVisible << 1;
3040 39
        $grbit |= $fWhitespaceHidden << 3;
3041
3042 39
        $header = pack('vv', $record, $length);
3043 39
        $data = pack('vvVVvv', $rt, $grbitFrt, 0x00000000, 0x00000000, $wScalvePLV, $grbit);
3044 39
        $this->append($header . $data);
3045 39
    }
3046
3047
    /**
3048
     * Write CFRule Record.
3049
     *
3050
     * @param Conditional $conditional
3051
     */
3052 2
    private function writeCFRule(Conditional $conditional)
3053
    {
3054 2
        $record = 0x01B1; // Record identifier
3055
3056
        // $type : Type of the CF
3057
        // $operatorType : Comparison operator
3058 2
        if ($conditional->getConditionType() == Conditional::CONDITION_EXPRESSION) {
3059
            $type = 0x02;
3060
            $operatorType = 0x00;
3061 2
        } elseif ($conditional->getConditionType() == Conditional::CONDITION_CELLIS) {
3062 2
            $type = 0x01;
3063
3064 2
            switch ($conditional->getOperatorType()) {
3065 2
                case Conditional::OPERATOR_NONE:
3066
                    $operatorType = 0x00;
3067
                    break;
3068 2
                case Conditional::OPERATOR_EQUAL:
3069
                    $operatorType = 0x03;
3070
                    break;
3071 2
                case Conditional::OPERATOR_GREATERTHAN:
3072
                    $operatorType = 0x05;
3073
                    break;
3074 2
                case Conditional::OPERATOR_GREATERTHANOREQUAL:
3075 2
                    $operatorType = 0x07;
3076 2
                    break;
3077 2
                case Conditional::OPERATOR_LESSTHAN:
3078 2
                    $operatorType = 0x06;
3079 2
                    break;
3080 1
                case Conditional::OPERATOR_LESSTHANOREQUAL:
3081
                    $operatorType = 0x08;
3082
                    break;
3083 1
                case Conditional::OPERATOR_NOTEQUAL:
3084
                    $operatorType = 0x04;
3085
                    break;
3086 1
                case Conditional::OPERATOR_BETWEEN:
3087 1
                    $operatorType = 0x01;
3088 1
                    break;
3089
                    // not OPERATOR_NOTBETWEEN 0x02
3090
            }
3091
        }
3092
3093
        // $szValue1 : size of the formula data for first value or formula
3094
        // $szValue2 : size of the formula data for second value or formula
3095 2
        $arrConditions = $conditional->getConditions();
3096 2
        $numConditions = count($arrConditions);
3097 2
        if ($numConditions == 1) {
3098 2
            $szValue1 = ($arrConditions[0] <= 65535 ? 3 : 0x0000);
3099 2
            $szValue2 = 0x0000;
3100 2
            $operand1 = pack('Cv', 0x1E, $arrConditions[0]);
3101 2
            $operand2 = null;
3102 1
        } elseif ($numConditions == 2 && ($conditional->getOperatorType() == Conditional::OPERATOR_BETWEEN)) {
3103 1
            $szValue1 = ($arrConditions[0] <= 65535 ? 3 : 0x0000);
3104 1
            $szValue2 = ($arrConditions[1] <= 65535 ? 3 : 0x0000);
3105 1
            $operand1 = pack('Cv', 0x1E, $arrConditions[0]);
3106 1
            $operand2 = pack('Cv', 0x1E, $arrConditions[1]);
3107
        } else {
3108
            $szValue1 = 0x0000;
3109
            $szValue2 = 0x0000;
3110
            $operand1 = null;
3111
            $operand2 = null;
3112
        }
3113
3114
        // $flags : Option flags
3115
        // Alignment
3116 2
        $bAlignHz = ($conditional->getStyle()->getAlignment()->getHorizontal() == null ? 1 : 0);
3117 2
        $bAlignVt = ($conditional->getStyle()->getAlignment()->getVertical() == null ? 1 : 0);
3118 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...
3119 2
        $bTxRotation = ($conditional->getStyle()->getAlignment()->getTextRotation() == null ? 1 : 0);
3120 2
        $bIndent = ($conditional->getStyle()->getAlignment()->getIndent() == 0 ? 1 : 0);
3121 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...
3122 2
        if ($bAlignHz == 0 || $bAlignVt == 0 || $bAlignWrapTx == 0 || $bTxRotation == 0 || $bIndent == 0 || $bShrinkToFit == 0) {
3123
            $bFormatAlign = 1;
3124
        } else {
3125 2
            $bFormatAlign = 0;
3126
        }
3127
        // Protection
3128 2
        $bProtLocked = ($conditional->getStyle()->getProtection()->getLocked() == null ? 1 : 0);
3129 2
        $bProtHidden = ($conditional->getStyle()->getProtection()->getHidden() == null ? 1 : 0);
3130 2
        if ($bProtLocked == 0 || $bProtHidden == 0) {
3131
            $bFormatProt = 1;
3132
        } else {
3133 2
            $bFormatProt = 0;
3134
        }
3135
        // Border
3136 2
        $bBorderLeft = ($conditional->getStyle()->getBorders()->getLeft()->getColor()->getARGB() == Color::COLOR_BLACK
3137 2
                        && $conditional->getStyle()->getBorders()->getLeft()->getBorderStyle() == Border::BORDER_NONE ? 1 : 0);
3138 2
        $bBorderRight = ($conditional->getStyle()->getBorders()->getRight()->getColor()->getARGB() == Color::COLOR_BLACK
3139 2
                        && $conditional->getStyle()->getBorders()->getRight()->getBorderStyle() == Border::BORDER_NONE ? 1 : 0);
3140 2
        $bBorderTop = ($conditional->getStyle()->getBorders()->getTop()->getColor()->getARGB() == Color::COLOR_BLACK
3141 2
                        && $conditional->getStyle()->getBorders()->getTop()->getBorderStyle() == Border::BORDER_NONE ? 1 : 0);
3142 2
        $bBorderBottom = ($conditional->getStyle()->getBorders()->getBottom()->getColor()->getARGB() == Color::COLOR_BLACK
3143 2
                        && $conditional->getStyle()->getBorders()->getBottom()->getBorderStyle() == Border::BORDER_NONE ? 1 : 0);
3144 2
        if ($bBorderLeft == 0 || $bBorderRight == 0 || $bBorderTop == 0 || $bBorderBottom == 0) {
3145
            $bFormatBorder = 1;
3146
        } else {
3147 2
            $bFormatBorder = 0;
3148
        }
3149
        // Pattern
3150 2
        $bFillStyle = ($conditional->getStyle()->getFill()->getFillType() == null ? 0 : 1);
3151 2
        $bFillColor = ($conditional->getStyle()->getFill()->getStartColor()->getARGB() == null ? 0 : 1);
3152 2
        $bFillColorBg = ($conditional->getStyle()->getFill()->getEndColor()->getARGB() == null ? 0 : 1);
3153 2
        if ($bFillStyle == 0 || $bFillColor == 0 || $bFillColorBg == 0) {
3154 2
            $bFormatFill = 1;
3155
        } else {
3156
            $bFormatFill = 0;
3157
        }
3158
        // Font
3159 2
        if ($conditional->getStyle()->getFont()->getName() != null
3160 2
            || $conditional->getStyle()->getFont()->getSize() != null
3161 2
            || $conditional->getStyle()->getFont()->getBold() != null
3162 2
            || $conditional->getStyle()->getFont()->getItalic() != null
3163 1
            || $conditional->getStyle()->getFont()->getSuperscript() != null
3164 1
            || $conditional->getStyle()->getFont()->getSubscript() != null
3165 1
            || $conditional->getStyle()->getFont()->getUnderline() != null
3166 1
            || $conditional->getStyle()->getFont()->getStrikethrough() != null
3167 2
            || $conditional->getStyle()->getFont()->getColor()->getARGB() != null) {
3168 2
            $bFormatFont = 1;
3169
        } else {
3170
            $bFormatFont = 0;
3171
        }
3172
        // Alignment
3173 2
        $flags = 0;
3174 2
        $flags |= (1 == $bAlignHz ? 0x00000001 : 0);
3175 2
        $flags |= (1 == $bAlignVt ? 0x00000002 : 0);
3176 2
        $flags |= (1 == $bAlignWrapTx ? 0x00000004 : 0);
3177 2
        $flags |= (1 == $bTxRotation ? 0x00000008 : 0);
3178
        // Justify last line flag
3179 2
        $flags |= (1 == 1 ? 0x00000010 : 0);
3180 2
        $flags |= (1 == $bIndent ? 0x00000020 : 0);
3181 2
        $flags |= (1 == $bShrinkToFit ? 0x00000040 : 0);
3182
        // Default
3183 2
        $flags |= (1 == 1 ? 0x00000080 : 0);
3184
        // Protection
3185 2
        $flags |= (1 == $bProtLocked ? 0x00000100 : 0);
3186 2
        $flags |= (1 == $bProtHidden ? 0x00000200 : 0);
3187
        // Border
3188 2
        $flags |= (1 == $bBorderLeft ? 0x00000400 : 0);
3189 2
        $flags |= (1 == $bBorderRight ? 0x00000800 : 0);
3190 2
        $flags |= (1 == $bBorderTop ? 0x00001000 : 0);
3191 2
        $flags |= (1 == $bBorderBottom ? 0x00002000 : 0);
3192 2
        $flags |= (1 == 1 ? 0x00004000 : 0); // Top left to Bottom right border
3193 2
        $flags |= (1 == 1 ? 0x00008000 : 0); // Bottom left to Top right border
3194
        // Pattern
3195 2
        $flags |= (1 == $bFillStyle ? 0x00010000 : 0);
3196 2
        $flags |= (1 == $bFillColor ? 0x00020000 : 0);
3197 2
        $flags |= (1 == $bFillColorBg ? 0x00040000 : 0);
3198 2
        $flags |= (1 == 1 ? 0x00380000 : 0);
3199
        // Font
3200 2
        $flags |= (1 == $bFormatFont ? 0x04000000 : 0);
3201
        // Alignment:
3202 2
        $flags |= (1 == $bFormatAlign ? 0x08000000 : 0);
3203
        // Border
3204 2
        $flags |= (1 == $bFormatBorder ? 0x10000000 : 0);
3205
        // Pattern
3206 2
        $flags |= (1 == $bFormatFill ? 0x20000000 : 0);
3207
        // Protection
3208 2
        $flags |= (1 == $bFormatProt ? 0x40000000 : 0);
3209
        // Text direction
3210 2
        $flags |= (1 == 0 ? 0x80000000 : 0);
3211
3212
        // Data Blocks
3213 2
        if ($bFormatFont == 1) {
3214
            // Font Name
3215 2
            if ($conditional->getStyle()->getFont()->getName() == null) {
3216 2
                $dataBlockFont = pack('VVVVVVVV', 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
3217 2
                $dataBlockFont .= pack('VVVVVVVV', 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
3218
            } else {
3219
                $dataBlockFont = StringHelper::UTF8toBIFF8UnicodeLong($conditional->getStyle()->getFont()->getName());
3220
            }
3221
            // Font Size
3222 2
            if ($conditional->getStyle()->getFont()->getSize() == null) {
3223 2
                $dataBlockFont .= pack('V', 20 * 11);
3224
            } else {
3225
                $dataBlockFont .= pack('V', 20 * $conditional->getStyle()->getFont()->getSize());
3226
            }
3227
            // Font Options
3228 2
            $dataBlockFont .= pack('V', 0);
3229
            // Font weight
3230 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...
3231 1
                $dataBlockFont .= pack('v', 0x02BC);
3232
            } else {
3233 2
                $dataBlockFont .= pack('v', 0x0190);
3234
            }
3235
            // Escapement type
3236 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...
3237
                $dataBlockFont .= pack('v', 0x02);
3238
                $fontEscapement = 0;
3239 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...
3240
                $dataBlockFont .= pack('v', 0x01);
3241
                $fontEscapement = 0;
3242
            } else {
3243 2
                $dataBlockFont .= pack('v', 0x00);
3244 2
                $fontEscapement = 1;
3245
            }
3246
            // Underline type
3247 2
            switch ($conditional->getStyle()->getFont()->getUnderline()) {
3248 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_NONE:
3249
                    $dataBlockFont .= pack('C', 0x00);
3250
                    $fontUnderline = 0;
3251
                    break;
3252 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_DOUBLE:
3253
                    $dataBlockFont .= pack('C', 0x02);
3254
                    $fontUnderline = 0;
3255
                    break;
3256 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_DOUBLEACCOUNTING:
3257
                    $dataBlockFont .= pack('C', 0x22);
3258
                    $fontUnderline = 0;
3259
                    break;
3260 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_SINGLE:
3261
                    $dataBlockFont .= pack('C', 0x01);
3262
                    $fontUnderline = 0;
3263
                    break;
3264 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_SINGLEACCOUNTING:
3265
                    $dataBlockFont .= pack('C', 0x21);
3266
                    $fontUnderline = 0;
3267
                    break;
3268
                default:
3269 2
                    $dataBlockFont .= pack('C', 0x00);
3270 2
                    $fontUnderline = 1;
3271 2
                    break;
3272
            }
3273
            // 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...
3274 2
            $dataBlockFont .= pack('vC', 0x0000, 0x00);
3275
            // Font color index
3276 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...
3277 2
                case '000000':
3278
                    $colorIdx = 0x08;
3279
                    break;
3280 2
                case 'FFFFFF':
3281
                    $colorIdx = 0x09;
3282
                    break;
3283 2
                case 'FF0000':
3284 2
                    $colorIdx = 0x0A;
3285 2
                    break;
3286 2
                case '00FF00':
3287 2
                    $colorIdx = 0x0B;
3288 2
                    break;
3289 1
                case '0000FF':
3290
                    $colorIdx = 0x0C;
3291
                    break;
3292 1
                case 'FFFF00':
3293 1
                    $colorIdx = 0x0D;
3294 1
                    break;
3295
                case 'FF00FF':
3296
                    $colorIdx = 0x0E;
3297
                    break;
3298
                case '00FFFF':
3299
                    $colorIdx = 0x0F;
3300
                    break;
3301
                case '800000':
3302
                    $colorIdx = 0x10;
3303
                    break;
3304
                case '008000':
3305
                    $colorIdx = 0x11;
3306
                    break;
3307
                case '000080':
3308
                    $colorIdx = 0x12;
3309
                    break;
3310
                case '808000':
3311
                    $colorIdx = 0x13;
3312
                    break;
3313
                case '800080':
3314
                    $colorIdx = 0x14;
3315
                    break;
3316
                case '008080':
3317
                    $colorIdx = 0x15;
3318
                    break;
3319
                case 'C0C0C0':
3320
                    $colorIdx = 0x16;
3321
                    break;
3322
                case '808080':
3323
                    $colorIdx = 0x17;
3324
                    break;
3325
                case '9999FF':
3326
                    $colorIdx = 0x18;
3327
                    break;
3328
                case '993366':
3329
                    $colorIdx = 0x19;
3330
                    break;
3331
                case 'FFFFCC':
3332
                    $colorIdx = 0x1A;
3333
                    break;
3334
                case 'CCFFFF':
3335
                    $colorIdx = 0x1B;
3336
                    break;
3337
                case '660066':
3338
                    $colorIdx = 0x1C;
3339
                    break;
3340
                case 'FF8080':
3341
                    $colorIdx = 0x1D;
3342
                    break;
3343
                case '0066CC':
3344
                    $colorIdx = 0x1E;
3345
                    break;
3346
                case 'CCCCFF':
3347
                    $colorIdx = 0x1F;
3348
                    break;
3349
                case '000080':
3350
                    $colorIdx = 0x20;
3351
                    break;
3352
                case 'FF00FF':
3353
                    $colorIdx = 0x21;
3354
                    break;
3355
                case 'FFFF00':
3356
                    $colorIdx = 0x22;
3357
                    break;
3358
                case '00FFFF':
3359
                    $colorIdx = 0x23;
3360
                    break;
3361
                case '800080':
3362
                    $colorIdx = 0x24;
3363
                    break;
3364
                case '800000':
3365
                    $colorIdx = 0x25;
3366
                    break;
3367
                case '008080':
3368
                    $colorIdx = 0x26;
3369
                    break;
3370
                case '0000FF':
3371
                    $colorIdx = 0x27;
3372
                    break;
3373
                case '00CCFF':
3374
                    $colorIdx = 0x28;
3375
                    break;
3376
                case 'CCFFFF':
3377
                    $colorIdx = 0x29;
3378
                    break;
3379
                case 'CCFFCC':
3380
                    $colorIdx = 0x2A;
3381
                    break;
3382
                case 'FFFF99':
3383
                    $colorIdx = 0x2B;
3384
                    break;
3385
                case '99CCFF':
3386
                    $colorIdx = 0x2C;
3387
                    break;
3388
                case 'FF99CC':
3389
                    $colorIdx = 0x2D;
3390
                    break;
3391
                case 'CC99FF':
3392
                    $colorIdx = 0x2E;
3393
                    break;
3394
                case 'FFCC99':
3395
                    $colorIdx = 0x2F;
3396
                    break;
3397
                case '3366FF':
3398
                    $colorIdx = 0x30;
3399
                    break;
3400
                case '33CCCC':
3401
                    $colorIdx = 0x31;
3402
                    break;
3403
                case '99CC00':
3404
                    $colorIdx = 0x32;
3405
                    break;
3406
                case 'FFCC00':
3407
                    $colorIdx = 0x33;
3408
                    break;
3409
                case 'FF9900':
3410
                    $colorIdx = 0x34;
3411
                    break;
3412
                case 'FF6600':
3413
                    $colorIdx = 0x35;
3414
                    break;
3415
                case '666699':
3416
                    $colorIdx = 0x36;
3417
                    break;
3418
                case '969696':
3419
                    $colorIdx = 0x37;
3420
                    break;
3421
                case '003366':
3422
                    $colorIdx = 0x38;
3423
                    break;
3424
                case '339966':
3425
                    $colorIdx = 0x39;
3426
                    break;
3427
                case '003300':
3428
                    $colorIdx = 0x3A;
3429
                    break;
3430
                case '333300':
3431
                    $colorIdx = 0x3B;
3432
                    break;
3433
                case '993300':
3434
                    $colorIdx = 0x3C;
3435
                    break;
3436
                case '993366':
3437
                    $colorIdx = 0x3D;
3438
                    break;
3439
                case '333399':
3440
                    $colorIdx = 0x3E;
3441
                    break;
3442
                case '333333':
3443
                    $colorIdx = 0x3F;
3444
                    break;
3445
                default:
3446
                    $colorIdx = 0x00;
3447
                    break;
3448
            }
3449 2
            $dataBlockFont .= pack('V', $colorIdx);
3450
            // 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...
3451 2
            $dataBlockFont .= pack('V', 0x00000000);
3452
            // Options flags for modified font attributes
3453 2
            $optionsFlags = 0;
3454 2
            $optionsFlagsBold = ($conditional->getStyle()->getFont()->getBold() == null ? 1 : 0);
3455 2
            $optionsFlags |= (1 == $optionsFlagsBold ? 0x00000002 : 0);
3456 2
            $optionsFlags |= (1 == 1 ? 0x00000008 : 0);
3457 2
            $optionsFlags |= (1 == 1 ? 0x00000010 : 0);
3458 2
            $optionsFlags |= (1 == 0 ? 0x00000020 : 0);
3459 2
            $optionsFlags |= (1 == 1 ? 0x00000080 : 0);
3460 2
            $dataBlockFont .= pack('V', $optionsFlags);
3461
            // Escapement type
3462 2
            $dataBlockFont .= pack('V', $fontEscapement);
3463
            // Underline type
3464 2
            $dataBlockFont .= pack('V', $fontUnderline);
3465
            // Always
3466 2
            $dataBlockFont .= pack('V', 0x00000000);
3467
            // Always
3468 2
            $dataBlockFont .= pack('V', 0x00000000);
3469
            // 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...
3470 2
            $dataBlockFont .= pack('VV', 0x00000000, 0x00000000);
3471
            // Always
3472 2
            $dataBlockFont .= pack('v', 0x0001);
3473
        }
3474 2
        if ($bFormatAlign == 1) {
3475
            $blockAlign = 0;
3476
            // Alignment and text break
3477
            switch ($conditional->getStyle()->getAlignment()->getHorizontal()) {
3478
                case Alignment::HORIZONTAL_GENERAL:
3479
                    $blockAlign = 0;
3480
                    break;
3481
                case Alignment::HORIZONTAL_LEFT:
3482
                    $blockAlign = 1;
3483
                    break;
3484
                case Alignment::HORIZONTAL_RIGHT:
3485
                    $blockAlign = 3;
3486
                    break;
3487
                case Alignment::HORIZONTAL_CENTER:
3488
                    $blockAlign = 2;
3489
                    break;
3490
                case Alignment::HORIZONTAL_CENTER_CONTINUOUS:
3491
                    $blockAlign = 6;
3492
                    break;
3493
                case Alignment::HORIZONTAL_JUSTIFY:
3494
                    $blockAlign = 5;
3495
                    break;
3496
            }
3497
            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...
3498
                $blockAlign |= 1 << 3;
3499
            } else {
3500
                $blockAlign |= 0 << 3;
3501
            }
3502
            switch ($conditional->getStyle()->getAlignment()->getVertical()) {
3503
                case Alignment::VERTICAL_BOTTOM:
3504
                    $blockAlign = 2 << 4;
3505
                    break;
3506
                case Alignment::VERTICAL_TOP:
3507
                    $blockAlign = 0 << 4;
3508
                    break;
3509
                case Alignment::VERTICAL_CENTER:
3510
                    $blockAlign = 1 << 4;
3511
                    break;
3512
                case Alignment::VERTICAL_JUSTIFY:
3513
                    $blockAlign = 3 << 4;
3514
                    break;
3515
            }
3516
            $blockAlign |= 0 << 7;
3517
3518
            // Text rotation angle
3519
            $blockRotation = $conditional->getStyle()->getAlignment()->getTextRotation();
3520
3521
            // Indentation
3522
            $blockIndent = $conditional->getStyle()->getAlignment()->getIndent();
3523
            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...
3524
                $blockIndent |= 1 << 4;
3525
            } else {
3526
                $blockIndent |= 0 << 4;
3527
            }
3528
            $blockIndent |= 0 << 6;
3529
3530
            // Relative indentation
3531
            $blockIndentRelative = 255;
3532
3533
            $dataBlockAlign = pack('CCvvv', $blockAlign, $blockRotation, $blockIndent, $blockIndentRelative, 0x0000);
3534
        }
3535 2
        if ($bFormatBorder == 1) {
3536
            $blockLineStyle = 0;
3537
            switch ($conditional->getStyle()->getBorders()->getLeft()->getBorderStyle()) {
3538
                case Border::BORDER_NONE:
3539
                    $blockLineStyle |= 0x00;
3540
                    break;
3541
                case Border::BORDER_THIN:
3542
                    $blockLineStyle |= 0x01;
3543
                    break;
3544
                case Border::BORDER_MEDIUM:
3545
                    $blockLineStyle |= 0x02;
3546
                    break;
3547
                case Border::BORDER_DASHED:
3548
                    $blockLineStyle |= 0x03;
3549
                    break;
3550
                case Border::BORDER_DOTTED:
3551
                    $blockLineStyle |= 0x04;
3552
                    break;
3553
                case Border::BORDER_THICK:
3554
                    $blockLineStyle |= 0x05;
3555
                    break;
3556
                case Border::BORDER_DOUBLE:
3557
                    $blockLineStyle |= 0x06;
3558
                    break;
3559
                case Border::BORDER_HAIR:
3560
                    $blockLineStyle |= 0x07;
3561
                    break;
3562
                case Border::BORDER_MEDIUMDASHED:
3563
                    $blockLineStyle |= 0x08;
3564
                    break;
3565
                case Border::BORDER_DASHDOT:
3566
                    $blockLineStyle |= 0x09;
3567
                    break;
3568
                case Border::BORDER_MEDIUMDASHDOT:
3569
                    $blockLineStyle |= 0x0A;
3570
                    break;
3571
                case Border::BORDER_DASHDOTDOT:
3572
                    $blockLineStyle |= 0x0B;
3573
                    break;
3574
                case Border::BORDER_MEDIUMDASHDOTDOT:
3575
                    $blockLineStyle |= 0x0C;
3576
                    break;
3577
                case Border::BORDER_SLANTDASHDOT:
3578
                    $blockLineStyle |= 0x0D;
3579
                    break;
3580
            }
3581 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...
3582
                case Border::BORDER_NONE:
3583
                    $blockLineStyle |= 0x00 << 4;
3584
                    break;
3585
                case Border::BORDER_THIN:
3586
                    $blockLineStyle |= 0x01 << 4;
3587
                    break;
3588
                case Border::BORDER_MEDIUM:
3589
                    $blockLineStyle |= 0x02 << 4;
3590
                    break;
3591
                case Border::BORDER_DASHED:
3592
                    $blockLineStyle |= 0x03 << 4;
3593
                    break;
3594
                case Border::BORDER_DOTTED:
3595
                    $blockLineStyle |= 0x04 << 4;
3596
                    break;
3597
                case Border::BORDER_THICK:
3598
                    $blockLineStyle |= 0x05 << 4;
3599
                    break;
3600
                case Border::BORDER_DOUBLE:
3601
                    $blockLineStyle |= 0x06 << 4;
3602
                    break;
3603
                case Border::BORDER_HAIR:
3604
                    $blockLineStyle |= 0x07 << 4;
3605
                    break;
3606
                case Border::BORDER_MEDIUMDASHED:
3607
                    $blockLineStyle |= 0x08 << 4;
3608
                    break;
3609
                case Border::BORDER_DASHDOT:
3610
                    $blockLineStyle |= 0x09 << 4;
3611
                    break;
3612
                case Border::BORDER_MEDIUMDASHDOT:
3613
                    $blockLineStyle |= 0x0A << 4;
3614
                    break;
3615
                case Border::BORDER_DASHDOTDOT:
3616
                    $blockLineStyle |= 0x0B << 4;
3617
                    break;
3618
                case Border::BORDER_MEDIUMDASHDOTDOT:
3619
                    $blockLineStyle |= 0x0C << 4;
3620
                    break;
3621
                case Border::BORDER_SLANTDASHDOT:
3622
                    $blockLineStyle |= 0x0D << 4;
3623
                    break;
3624
            }
3625 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...
3626
                case Border::BORDER_NONE:
3627
                    $blockLineStyle |= 0x00 << 8;
3628
                    break;
3629
                case Border::BORDER_THIN:
3630
                    $blockLineStyle |= 0x01 << 8;
3631
                    break;
3632
                case Border::BORDER_MEDIUM:
3633
                    $blockLineStyle |= 0x02 << 8;
3634
                    break;
3635
                case Border::BORDER_DASHED:
3636
                    $blockLineStyle |= 0x03 << 8;
3637
                    break;
3638
                case Border::BORDER_DOTTED:
3639
                    $blockLineStyle |= 0x04 << 8;
3640
                    break;
3641
                case Border::BORDER_THICK:
3642
                    $blockLineStyle |= 0x05 << 8;
3643
                    break;
3644
                case Border::BORDER_DOUBLE:
3645
                    $blockLineStyle |= 0x06 << 8;
3646
                    break;
3647
                case Border::BORDER_HAIR:
3648
                    $blockLineStyle |= 0x07 << 8;
3649
                    break;
3650
                case Border::BORDER_MEDIUMDASHED:
3651
                    $blockLineStyle |= 0x08 << 8;
3652
                    break;
3653
                case Border::BORDER_DASHDOT:
3654
                    $blockLineStyle |= 0x09 << 8;
3655
                    break;
3656
                case Border::BORDER_MEDIUMDASHDOT:
3657
                    $blockLineStyle |= 0x0A << 8;
3658
                    break;
3659
                case Border::BORDER_DASHDOTDOT:
3660
                    $blockLineStyle |= 0x0B << 8;
3661
                    break;
3662
                case Border::BORDER_MEDIUMDASHDOTDOT:
3663
                    $blockLineStyle |= 0x0C << 8;
3664
                    break;
3665
                case Border::BORDER_SLANTDASHDOT:
3666
                    $blockLineStyle |= 0x0D << 8;
3667
                    break;
3668
            }
3669 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...
3670
                case Border::BORDER_NONE:
3671
                    $blockLineStyle |= 0x00 << 12;
3672
                    break;
3673
                case Border::BORDER_THIN:
3674
                    $blockLineStyle |= 0x01 << 12;
3675
                    break;
3676
                case Border::BORDER_MEDIUM:
3677
                    $blockLineStyle |= 0x02 << 12;
3678
                    break;
3679
                case Border::BORDER_DASHED:
3680
                    $blockLineStyle |= 0x03 << 12;
3681
                    break;
3682
                case Border::BORDER_DOTTED:
3683
                    $blockLineStyle |= 0x04 << 12;
3684
                    break;
3685
                case Border::BORDER_THICK:
3686
                    $blockLineStyle |= 0x05 << 12;
3687
                    break;
3688
                case Border::BORDER_DOUBLE:
3689
                    $blockLineStyle |= 0x06 << 12;
3690
                    break;
3691
                case Border::BORDER_HAIR:
3692
                    $blockLineStyle |= 0x07 << 12;
3693
                    break;
3694
                case Border::BORDER_MEDIUMDASHED:
3695
                    $blockLineStyle |= 0x08 << 12;
3696
                    break;
3697
                case Border::BORDER_DASHDOT:
3698
                    $blockLineStyle |= 0x09 << 12;
3699
                    break;
3700
                case Border::BORDER_MEDIUMDASHDOT:
3701
                    $blockLineStyle |= 0x0A << 12;
3702
                    break;
3703
                case Border::BORDER_DASHDOTDOT:
3704
                    $blockLineStyle |= 0x0B << 12;
3705
                    break;
3706
                case Border::BORDER_MEDIUMDASHDOTDOT:
3707
                    $blockLineStyle |= 0x0C << 12;
3708
                    break;
3709
                case Border::BORDER_SLANTDASHDOT:
3710
                    $blockLineStyle |= 0x0D << 12;
3711
                    break;
3712
            }
3713
            //@todo writeCFRule() => $blockLineStyle => Index Color for left line
3714
            //@todo writeCFRule() => $blockLineStyle => Index Color for right line
3715
            //@todo writeCFRule() => $blockLineStyle => Top-left to bottom-right on/off
3716
            //@todo writeCFRule() => $blockLineStyle => Bottom-left to top-right on/off
3717
            $blockColor = 0;
3718
            //@todo writeCFRule() => $blockColor => Index Color for top line
3719
            //@todo writeCFRule() => $blockColor => Index Color for bottom line
3720
            //@todo writeCFRule() => $blockColor => Index Color for diagonal line
3721 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...
3722
                case Border::BORDER_NONE:
3723
                    $blockColor |= 0x00 << 21;
3724
                    break;
3725
                case Border::BORDER_THIN:
3726
                    $blockColor |= 0x01 << 21;
3727
                    break;
3728
                case Border::BORDER_MEDIUM:
3729
                    $blockColor |= 0x02 << 21;
3730
                    break;
3731
                case Border::BORDER_DASHED:
3732
                    $blockColor |= 0x03 << 21;
3733
                    break;
3734
                case Border::BORDER_DOTTED:
3735
                    $blockColor |= 0x04 << 21;
3736
                    break;
3737
                case Border::BORDER_THICK:
3738
                    $blockColor |= 0x05 << 21;
3739
                    break;
3740
                case Border::BORDER_DOUBLE:
3741
                    $blockColor |= 0x06 << 21;
3742
                    break;
3743
                case Border::BORDER_HAIR:
3744
                    $blockColor |= 0x07 << 21;
3745
                    break;
3746
                case Border::BORDER_MEDIUMDASHED:
3747
                    $blockColor |= 0x08 << 21;
3748
                    break;
3749
                case Border::BORDER_DASHDOT:
3750
                    $blockColor |= 0x09 << 21;
3751
                    break;
3752
                case Border::BORDER_MEDIUMDASHDOT:
3753
                    $blockColor |= 0x0A << 21;
3754
                    break;
3755
                case Border::BORDER_DASHDOTDOT:
3756
                    $blockColor |= 0x0B << 21;
3757
                    break;
3758
                case Border::BORDER_MEDIUMDASHDOTDOT:
3759
                    $blockColor |= 0x0C << 21;
3760
                    break;
3761
                case Border::BORDER_SLANTDASHDOT:
3762
                    $blockColor |= 0x0D << 21;
3763
                    break;
3764
            }
3765
            $dataBlockBorder = pack('vv', $blockLineStyle, $blockColor);
3766
        }
3767 2
        if ($bFormatFill == 1) {
3768
            // Fill Patern Style
3769 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...
3770 2
            switch ($conditional->getStyle()->getFill()->getFillType()) {
3771 2
                case Fill::FILL_NONE:
3772
                    $blockFillPatternStyle = 0x00;
3773
                    break;
3774 2
                case Fill::FILL_SOLID:
3775
                    $blockFillPatternStyle = 0x01;
3776
                    break;
3777 2
                case Fill::FILL_PATTERN_MEDIUMGRAY:
3778
                    $blockFillPatternStyle = 0x02;
3779
                    break;
3780 2
                case Fill::FILL_PATTERN_DARKGRAY:
3781
                    $blockFillPatternStyle = 0x03;
3782
                    break;
3783 2
                case Fill::FILL_PATTERN_LIGHTGRAY:
3784
                    $blockFillPatternStyle = 0x04;
3785
                    break;
3786 2
                case Fill::FILL_PATTERN_DARKHORIZONTAL:
3787
                    $blockFillPatternStyle = 0x05;
3788
                    break;
3789 2
                case Fill::FILL_PATTERN_DARKVERTICAL:
3790
                    $blockFillPatternStyle = 0x06;
3791
                    break;
3792 2
                case Fill::FILL_PATTERN_DARKDOWN:
3793
                    $blockFillPatternStyle = 0x07;
3794
                    break;
3795 2
                case Fill::FILL_PATTERN_DARKUP:
3796
                    $blockFillPatternStyle = 0x08;
3797
                    break;
3798 2
                case Fill::FILL_PATTERN_DARKGRID:
3799
                    $blockFillPatternStyle = 0x09;
3800
                    break;
3801 2
                case Fill::FILL_PATTERN_DARKTRELLIS:
3802
                    $blockFillPatternStyle = 0x0A;
3803
                    break;
3804 2
                case Fill::FILL_PATTERN_LIGHTHORIZONTAL:
3805
                    $blockFillPatternStyle = 0x0B;
3806
                    break;
3807 2
                case Fill::FILL_PATTERN_LIGHTVERTICAL:
3808
                    $blockFillPatternStyle = 0x0C;
3809
                    break;
3810 2
                case Fill::FILL_PATTERN_LIGHTDOWN:
3811
                    $blockFillPatternStyle = 0x0D;
3812
                    break;
3813 2
                case Fill::FILL_PATTERN_LIGHTUP:
3814
                    $blockFillPatternStyle = 0x0E;
3815
                    break;
3816 2
                case Fill::FILL_PATTERN_LIGHTGRID:
3817
                    $blockFillPatternStyle = 0x0F;
3818
                    break;
3819 2
                case Fill::FILL_PATTERN_LIGHTTRELLIS:
3820
                    $blockFillPatternStyle = 0x10;
3821
                    break;
3822 2
                case Fill::FILL_PATTERN_GRAY125:
3823
                    $blockFillPatternStyle = 0x11;
3824
                    break;
3825 2
                case Fill::FILL_PATTERN_GRAY0625:
3826
                    $blockFillPatternStyle = 0x12;
3827
                    break;
3828 2
                case Fill::FILL_GRADIENT_LINEAR:
3829
                    $blockFillPatternStyle = 0x00;
3830
                    break; // does not exist in BIFF8
3831 2
                case Fill::FILL_GRADIENT_PATH:
3832
                    $blockFillPatternStyle = 0x00;
3833
                    break; // does not exist in BIFF8
3834
                default:
3835 2
                    $blockFillPatternStyle = 0x00;
3836 2
                    break;
3837
            }
3838
            // Color
3839 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...
3840 2
                case '000000':
3841
                    $colorIdxBg = 0x08;
3842
                    break;
3843 2
                case 'FFFFFF':
3844
                    $colorIdxBg = 0x09;
3845
                    break;
3846 2
                case 'FF0000':
3847
                    $colorIdxBg = 0x0A;
3848
                    break;
3849 2
                case '00FF00':
3850
                    $colorIdxBg = 0x0B;
3851
                    break;
3852 2
                case '0000FF':
3853
                    $colorIdxBg = 0x0C;
3854
                    break;
3855 2
                case 'FFFF00':
3856
                    $colorIdxBg = 0x0D;
3857
                    break;
3858 2
                case 'FF00FF':
3859
                    $colorIdxBg = 0x0E;
3860
                    break;
3861 2
                case '00FFFF':
3862
                    $colorIdxBg = 0x0F;
3863
                    break;
3864 2
                case '800000':
3865
                    $colorIdxBg = 0x10;
3866
                    break;
3867 2
                case '008000':
3868
                    $colorIdxBg = 0x11;
3869
                    break;
3870 2
                case '000080':
3871
                    $colorIdxBg = 0x12;
3872
                    break;
3873 2
                case '808000':
3874
                    $colorIdxBg = 0x13;
3875
                    break;
3876 2
                case '800080':
3877
                    $colorIdxBg = 0x14;
3878
                    break;
3879 2
                case '008080':
3880
                    $colorIdxBg = 0x15;
3881
                    break;
3882 2
                case 'C0C0C0':
3883
                    $colorIdxBg = 0x16;
3884
                    break;
3885 2
                case '808080':
3886
                    $colorIdxBg = 0x17;
3887
                    break;
3888 2
                case '9999FF':
3889
                    $colorIdxBg = 0x18;
3890
                    break;
3891 2
                case '993366':
3892
                    $colorIdxBg = 0x19;
3893
                    break;
3894 2
                case 'FFFFCC':
3895
                    $colorIdxBg = 0x1A;
3896
                    break;
3897 2
                case 'CCFFFF':
3898
                    $colorIdxBg = 0x1B;
3899
                    break;
3900 2
                case '660066':
3901
                    $colorIdxBg = 0x1C;
3902
                    break;
3903 2
                case 'FF8080':
3904
                    $colorIdxBg = 0x1D;
3905
                    break;
3906 2
                case '0066CC':
3907
                    $colorIdxBg = 0x1E;
3908
                    break;
3909 2
                case 'CCCCFF':
3910
                    $colorIdxBg = 0x1F;
3911
                    break;
3912 2
                case '000080':
3913
                    $colorIdxBg = 0x20;
3914
                    break;
3915 2
                case 'FF00FF':
3916
                    $colorIdxBg = 0x21;
3917
                    break;
3918 2
                case 'FFFF00':
3919
                    $colorIdxBg = 0x22;
3920
                    break;
3921 2
                case '00FFFF':
3922
                    $colorIdxBg = 0x23;
3923
                    break;
3924 2
                case '800080':
3925
                    $colorIdxBg = 0x24;
3926
                    break;
3927 2
                case '800000':
3928
                    $colorIdxBg = 0x25;
3929
                    break;
3930 2
                case '008080':
3931
                    $colorIdxBg = 0x26;
3932
                    break;
3933 2
                case '0000FF':
3934
                    $colorIdxBg = 0x27;
3935
                    break;
3936 2
                case '00CCFF':
3937
                    $colorIdxBg = 0x28;
3938
                    break;
3939 2
                case 'CCFFFF':
3940
                    $colorIdxBg = 0x29;
3941
                    break;
3942 2
                case 'CCFFCC':
3943
                    $colorIdxBg = 0x2A;
3944
                    break;
3945 2
                case 'FFFF99':
3946
                    $colorIdxBg = 0x2B;
3947
                    break;
3948 2
                case '99CCFF':
3949
                    $colorIdxBg = 0x2C;
3950
                    break;
3951 2
                case 'FF99CC':
3952
                    $colorIdxBg = 0x2D;
3953
                    break;
3954 2
                case 'CC99FF':
3955
                    $colorIdxBg = 0x2E;
3956
                    break;
3957 2
                case 'FFCC99':
3958
                    $colorIdxBg = 0x2F;
3959
                    break;
3960 2
                case '3366FF':
3961
                    $colorIdxBg = 0x30;
3962
                    break;
3963 2
                case '33CCCC':
3964
                    $colorIdxBg = 0x31;
3965
                    break;
3966 2
                case '99CC00':
3967
                    $colorIdxBg = 0x32;
3968
                    break;
3969 2
                case 'FFCC00':
3970
                    $colorIdxBg = 0x33;
3971
                    break;
3972 2
                case 'FF9900':
3973
                    $colorIdxBg = 0x34;
3974
                    break;
3975 2
                case 'FF6600':
3976
                    $colorIdxBg = 0x35;
3977
                    break;
3978 2
                case '666699':
3979
                    $colorIdxBg = 0x36;
3980
                    break;
3981 2
                case '969696':
3982
                    $colorIdxBg = 0x37;
3983
                    break;
3984 2
                case '003366':
3985
                    $colorIdxBg = 0x38;
3986
                    break;
3987 2
                case '339966':
3988
                    $colorIdxBg = 0x39;
3989
                    break;
3990 2
                case '003300':
3991
                    $colorIdxBg = 0x3A;
3992
                    break;
3993 2
                case '333300':
3994
                    $colorIdxBg = 0x3B;
3995
                    break;
3996 2
                case '993300':
3997
                    $colorIdxBg = 0x3C;
3998
                    break;
3999 2
                case '993366':
4000
                    $colorIdxBg = 0x3D;
4001
                    break;
4002 2
                case '333399':
4003
                    $colorIdxBg = 0x3E;
4004
                    break;
4005 2
                case '333333':
4006
                    $colorIdxBg = 0x3F;
4007
                    break;
4008
                default:
4009 2
                          $colorIdxBg = 0x41;
4010 2
                    break;
4011
            }
4012
            // Fg Color
4013 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...
4014 2
                case '000000':
4015
                    $colorIdxFg = 0x08;
4016
                    break;
4017 2
                case 'FFFFFF':
4018
                    $colorIdxFg = 0x09;
4019
                    break;
4020 2
                case 'FF0000':
4021
                    $colorIdxFg = 0x0A;
4022
                    break;
4023 2
                case '00FF00':
4024
                    $colorIdxFg = 0x0B;
4025
                    break;
4026 2
                case '0000FF':
4027
                    $colorIdxFg = 0x0C;
4028
                    break;
4029 2
                case 'FFFF00':
4030
                    $colorIdxFg = 0x0D;
4031
                    break;
4032 2
                case 'FF00FF':
4033
                    $colorIdxFg = 0x0E;
4034
                    break;
4035 2
                case '00FFFF':
4036
                    $colorIdxFg = 0x0F;
4037
                    break;
4038 2
                case '800000':
4039
                    $colorIdxFg = 0x10;
4040
                    break;
4041 2
                case '008000':
4042
                    $colorIdxFg = 0x11;
4043
                    break;
4044 2
                case '000080':
4045
                    $colorIdxFg = 0x12;
4046
                    break;
4047 2
                case '808000':
4048
                    $colorIdxFg = 0x13;
4049
                    break;
4050 2
                case '800080':
4051
                    $colorIdxFg = 0x14;
4052
                    break;
4053 2
                case '008080':
4054
                    $colorIdxFg = 0x15;
4055
                    break;
4056 2
                case 'C0C0C0':
4057
                    $colorIdxFg = 0x16;
4058
                    break;
4059 2
                case '808080':
4060
                    $colorIdxFg = 0x17;
4061
                    break;
4062 2
                case '9999FF':
4063
                    $colorIdxFg = 0x18;
4064
                    break;
4065 2
                case '993366':
4066
                    $colorIdxFg = 0x19;
4067
                    break;
4068 2
                case 'FFFFCC':
4069
                    $colorIdxFg = 0x1A;
4070
                    break;
4071 2
                case 'CCFFFF':
4072
                    $colorIdxFg = 0x1B;
4073
                    break;
4074 2
                case '660066':
4075
                    $colorIdxFg = 0x1C;
4076
                    break;
4077 2
                case 'FF8080':
4078
                    $colorIdxFg = 0x1D;
4079
                    break;
4080 2
                case '0066CC':
4081
                    $colorIdxFg = 0x1E;
4082
                    break;
4083 2
                case 'CCCCFF':
4084
                    $colorIdxFg = 0x1F;
4085
                    break;
4086 2
                case '000080':
4087
                    $colorIdxFg = 0x20;
4088
                    break;
4089 2
                case 'FF00FF':
4090
                    $colorIdxFg = 0x21;
4091
                    break;
4092 2
                case 'FFFF00':
4093
                    $colorIdxFg = 0x22;
4094
                    break;
4095 2
                case '00FFFF':
4096
                    $colorIdxFg = 0x23;
4097
                    break;
4098 2
                case '800080':
4099
                    $colorIdxFg = 0x24;
4100
                    break;
4101 2
                case '800000':
4102
                    $colorIdxFg = 0x25;
4103
                    break;
4104 2
                case '008080':
4105
                    $colorIdxFg = 0x26;
4106
                    break;
4107 2
                case '0000FF':
4108
                    $colorIdxFg = 0x27;
4109
                    break;
4110 2
                case '00CCFF':
4111
                    $colorIdxFg = 0x28;
4112
                    break;
4113 2
                case 'CCFFFF':
4114
                    $colorIdxFg = 0x29;
4115
                    break;
4116 2
                case 'CCFFCC':
4117
                    $colorIdxFg = 0x2A;
4118
                    break;
4119 2
                case 'FFFF99':
4120
                    $colorIdxFg = 0x2B;
4121
                    break;
4122 2
                case '99CCFF':
4123
                    $colorIdxFg = 0x2C;
4124
                    break;
4125 2
                case 'FF99CC':
4126
                    $colorIdxFg = 0x2D;
4127
                    break;
4128 2
                case 'CC99FF':
4129
                    $colorIdxFg = 0x2E;
4130
                    break;
4131 2
                case 'FFCC99':
4132
                    $colorIdxFg = 0x2F;
4133
                    break;
4134 2
                case '3366FF':
4135
                    $colorIdxFg = 0x30;
4136
                    break;
4137 2
                case '33CCCC':
4138
                    $colorIdxFg = 0x31;
4139
                    break;
4140 2
                case '99CC00':
4141
                    $colorIdxFg = 0x32;
4142
                    break;
4143 2
                case 'FFCC00':
4144
                    $colorIdxFg = 0x33;
4145
                    break;
4146 2
                case 'FF9900':
4147
                    $colorIdxFg = 0x34;
4148
                    break;
4149 2
                case 'FF6600':
4150
                    $colorIdxFg = 0x35;
4151
                    break;
4152 2
                case '666699':
4153
                    $colorIdxFg = 0x36;
4154
                    break;
4155 2
                case '969696':
4156
                    $colorIdxFg = 0x37;
4157
                    break;
4158 2
                case '003366':
4159
                    $colorIdxFg = 0x38;
4160
                    break;
4161 2
                case '339966':
4162
                    $colorIdxFg = 0x39;
4163
                    break;
4164 2
                case '003300':
4165
                    $colorIdxFg = 0x3A;
4166
                    break;
4167 2
                case '333300':
4168
                    $colorIdxFg = 0x3B;
4169
                    break;
4170 2
                case '993300':
4171
                    $colorIdxFg = 0x3C;
4172
                    break;
4173 2
                case '993366':
4174
                    $colorIdxFg = 0x3D;
4175
                    break;
4176 2
                case '333399':
4177
                    $colorIdxFg = 0x3E;
4178
                    break;
4179 2
                case '333333':
4180
                    $colorIdxFg = 0x3F;
4181
                    break;
4182
                default:
4183 2
                          $colorIdxFg = 0x40;
4184 2
                    break;
4185
            }
4186 2
            $dataBlockFill = pack('v', $blockFillPatternStyle);
4187 2
            $dataBlockFill .= pack('v', $colorIdxFg | ($colorIdxBg << 7));
4188
        }
4189 2
        if ($bFormatProt == 1) {
4190
            $dataBlockProtection = 0;
4191
            if ($conditional->getStyle()->getProtection()->getLocked() == Protection::PROTECTION_PROTECTED) {
4192
                $dataBlockProtection = 1;
4193
            }
4194
            if ($conditional->getStyle()->getProtection()->getHidden() == Protection::PROTECTION_PROTECTED) {
4195
                $dataBlockProtection = 1 << 1;
4196
            }
4197
        }
4198
4199 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...
4200 2
        if ($bFormatFont == 1) { // Block Formatting : OK
4201 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...
4202
        }
4203 2
        if ($bFormatAlign == 1) {
4204
            $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...
4205
        }
4206 2
        if ($bFormatBorder == 1) {
4207
            $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...
4208
        }
4209 2
        if ($bFormatFill == 1) { // Block Formatting : OK
4210 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...
4211
        }
4212 2
        if ($bFormatProt == 1) {
4213
            $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...
4214
        }
4215 2
        if (!is_null($operand1)) {
4216 2
            $data .= $operand1;
4217
        }
4218 2
        if (!is_null($operand2)) {
4219 1
            $data .= $operand2;
4220
        }
4221 2
        $header = pack('vv', $record, strlen($data));
4222 2
        $this->append($header . $data);
4223 2
    }
4224
4225
    /**
4226
     * Write CFHeader record.
4227
     */
4228 2
    private function writeCFHeader()
4229
    {
4230 2
        $record = 0x01B0; // Record identifier
4231 2
        $length = 0x0016; // Bytes to follow
4232
4233 2
        $numColumnMin = null;
4234 2
        $numColumnMax = null;
4235 2
        $numRowMin = null;
4236 2
        $numRowMax = null;
4237 2
        $arrConditional = [];
4238 2
        foreach ($this->phpSheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) {
4239 2
            foreach ($conditionalStyles as $conditional) {
4240 2
                if ($conditional->getConditionType() == Conditional::CONDITION_EXPRESSION
4241 2
                        || $conditional->getConditionType() == Conditional::CONDITION_CELLIS) {
4242 2
                    if (!in_array($conditional->getHashCode(), $arrConditional)) {
4243 2
                        $arrConditional[] = $conditional->getHashCode();
4244
                    }
4245
                    // Cells
4246 2
                    $arrCoord = Cell::coordinateFromString($cellCoordinate);
4247 2
                    if (!is_numeric($arrCoord[0])) {
4248 2
                        $arrCoord[0] = Cell::columnIndexFromString($arrCoord[0]);
4249
                    }
4250 2
                    if (is_null($numColumnMin) || ($numColumnMin > $arrCoord[0])) {
4251 2
                        $numColumnMin = $arrCoord[0];
4252
                    }
4253 2
                    if (is_null($numColumnMax) || ($numColumnMax < $arrCoord[0])) {
4254 2
                        $numColumnMax = $arrCoord[0];
4255
                    }
4256 2
                    if (is_null($numRowMin) || ($numRowMin > $arrCoord[1])) {
4257 2
                        $numRowMin = $arrCoord[1];
4258
                    }
4259 2
                    if (is_null($numRowMax) || ($numRowMax < $arrCoord[1])) {
4260 2
                        $numRowMax = $arrCoord[1];
4261
                    }
4262
                }
4263
            }
4264
        }
4265 2
        $needRedraw = 1;
4266 2
        $cellRange = pack('vvvv', $numRowMin - 1, $numRowMax - 1, $numColumnMin - 1, $numColumnMax - 1);
4267
4268 2
        $header = pack('vv', $record, $length);
4269 2
        $data = pack('vv', count($arrConditional), $needRedraw);
4270 2
        $data .= $cellRange;
4271 2
        $data .= pack('v', 0x0001);
4272 2
        $data .= $cellRange;
4273 2
        $this->append($header . $data);
4274 2
    }
4275
}
4276