Completed
Push — develop ( 6e4e0a...6aae76 )
by Adrien
21:10
created

Worksheet::writeDefcol()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 0
dl 0
loc 11
ccs 8
cts 8
cp 1
crap 1
rs 9.4285
c 0
b 0
f 0
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 38
    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 38
        parent::__construct();
251
252 38
        $this->preCalculateFormulas = $preCalculateFormulas;
253 38
        $this->stringTotal = &$str_total;
254 38
        $this->stringUnique = &$str_unique;
255 38
        $this->stringTable = &$str_table;
256 38
        $this->colors = &$colors;
257 38
        $this->parser = $parser;
258
259 38
        $this->phpSheet = $phpSheet;
0 ignored issues
show
Documentation Bug introduced by
It seems like $phpSheet of type string is incompatible with the declared type object<PhpOffice\PhpSpreadsheet\Worksheet> of property $phpSheet.

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

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

Loading history...
260
261 38
        $this->xlsStringMaxLength = 255;
262 38
        $this->columnInfo = [];
263 38
        $this->selection = [0, 0, 0, 0];
264 38
        $this->activePane = 3;
265
266 38
        $this->printHeaders = 0;
267
268 38
        $this->outlineStyle = 0;
0 ignored issues
show
Documentation Bug introduced by
The property $outlineStyle was declared of type boolean, but 0 is of type integer. Maybe add a type cast?

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

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

$answer = 42;

$correct = false;

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

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

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

$answer = 42;

$correct = false;

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

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

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

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
271 38
        $this->outlineOn = 1;
272
273 38
        $this->fontHashIndex = [];
274
275
        // calculate values for DIMENSIONS record
276 38
        $minR = 1;
0 ignored issues
show
Unused Code introduced by
$minR is not used, you could remove the assignment.

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

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

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

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

Loading history...
277 38
        $minC = 'A';
278
279 38
        $maxR = $this->phpSheet->getHighestRow();
0 ignored issues
show
Bug introduced by
The method getHighestRow cannot be called on $this->phpSheet (of type string).

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

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

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

Loading history...
281
282
        // Determine lowest and highest column and row
283 38
        $this->lastRowIndex = ($maxR > 65535) ? 65535 : $maxR;
284
285 38
        $this->firstColumnIndex = Cell::columnIndexFromString($minC);
286 38
        $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 38
        if ($this->lastColumnIndex > 255) {
290
            $this->lastColumnIndex = 255;
291
        }
292
293 38
        $this->countCellStyleXfs = count($phpSheet->getParent()->getCellStyleXfCollection());
0 ignored issues
show
Bug introduced by
The method getParent cannot be called on $phpSheet (of type string).

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

Loading history...
294 38
    }
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 38
    public function close()
303
    {
304 38
        $phpSheet = $this->phpSheet;
305
306
        // Write BOF record
307 38
        $this->storeBof(0x0010);
308
309
        // Write PRINTHEADERS
310 38
        $this->writePrintHeaders();
311
312
        // Write PRINTGRIDLINES
313 38
        $this->writePrintGridlines();
314
315
        // Write GRIDSET
316 38
        $this->writeGridset();
317
318
        // Calculate column widths
319 38
        $phpSheet->calculateColumnWidths();
320
321
        // Column dimensions
322 38
        if (($defaultWidth = $phpSheet->getDefaultColumnDimension()->getWidth()) < 0) {
323 37
            $defaultWidth = \PhpOffice\PhpSpreadsheet\Shared\Font::getDefaultColumnWidthByFont($phpSheet->getParent()->getDefaultStyle()->getFont());
324
        }
325
326 38
        $columnDimensions = $phpSheet->getColumnDimensions();
327 38
        $maxCol = $this->lastColumnIndex - 1;
328 38
        for ($i = 0; $i <= $maxCol; ++$i) {
329 38
            $hidden = 0;
330 38
            $level = 0;
331 38
            $xfIndex = 15; // there are 15 cell style Xfs
332
333 38
            $width = $defaultWidth;
334
335 38
            $columnLetter = Cell::stringFromColumnIndex($i);
336 38
            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 38
            $this->columnInfo[] = [$i, $i, $width, $xfIndex, $hidden, $level];
354
        }
355
356
        // Write GUTS
357 38
        $this->writeGuts();
358
359
        // Write DEFAULTROWHEIGHT
360 38
        $this->writeDefaultRowHeight();
361
        // Write WSBOOL
362 38
        $this->writeWsbool();
363
        // Write horizontal and vertical page breaks
364 38
        $this->writeBreaks();
365
        // Write page header
366 38
        $this->writeHeader();
367
        // Write page footer
368 38
        $this->writeFooter();
369
        // Write page horizontal centering
370 38
        $this->writeHcenter();
371
        // Write page vertical centering
372 38
        $this->writeVcenter();
373
        // Write left margin
374 38
        $this->writeMarginLeft();
375
        // Write right margin
376 38
        $this->writeMarginRight();
377
        // Write top margin
378 38
        $this->writeMarginTop();
379
        // Write bottom margin
380 38
        $this->writeMarginBottom();
381
        // Write page setup
382 38
        $this->writeSetup();
383
        // Write sheet protection
384 38
        $this->writeProtect();
385
        // Write SCENPROTECT
386 38
        $this->writeScenProtect();
387
        // Write OBJECTPROTECT
388 38
        $this->writeObjectProtect();
389
        // Write sheet password
390 38
        $this->writePassword();
391
        // Write DEFCOLWIDTH record
392 38
        $this->writeDefcol();
393
394
        // Write the COLINFO records if they exist
395 38
        if (!empty($this->columnInfo)) {
396 38
            $colcount = count($this->columnInfo);
397 38
            for ($i = 0; $i < $colcount; ++$i) {
398 38
                $this->writeColinfo($this->columnInfo[$i]);
399
            }
400
        }
401 38
        $autoFilterRange = $phpSheet->getAutoFilter()->getRange();
402 38
        if (!empty($autoFilterRange)) {
403
            // Write AUTOFILTERINFO
404 3
            $this->writeAutoFilterInfo();
405
        }
406
407
        // Write sheet dimensions
408 38
        $this->writeDimensions();
409
410
        // Row dimensions
411 38
        foreach ($phpSheet->getRowDimensions() as $rowDimension) {
412 37
            $xfIndex = $rowDimension->getXfIndex() + 15; // there are 15 cellXfs
413 37
            $this->writeRow($rowDimension->getRowIndex() - 1, $rowDimension->getRowHeight(), $xfIndex, ($rowDimension->getVisible() ? '0' : '1'), $rowDimension->getOutlineLevel());
0 ignored issues
show
Documentation introduced by
$rowDimension->getVisible() ? '0' : '1' is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
414
        }
415
416
        // Write Cells
417 38
        foreach ($phpSheet->getCoordinates() as $coordinate) {
418 38
            $cell = $phpSheet->getCell($coordinate);
419 38
            $row = $cell->getRow() - 1;
420 38
            $column = Cell::columnIndexFromString($cell->getColumn()) - 1;
421
422
            // Don't break Excel break the code!
423 38
            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 38
            $xfIndex = $cell->getXfIndex() + 15; // there are 15 cell style Xfs
429
430 38
            $cVal = $cell->getValue();
431 38
            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 37
                switch ($cell->getDatatype()) {
450 37
                    case Cell\DataType::TYPE_STRING:
451 30
                    case Cell\DataType::TYPE_NULL:
452 35
                        if ($cVal === '' || $cVal === null) {
453 18
                            $this->writeBlank($row, $column, $xfIndex);
454
                        } else {
455 33
                            $this->writeString($row, $column, $cVal, $xfIndex);
456
                        }
457 35
                        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 38
                        break;
472
                }
473
            }
474
        }
475
476
        // Append
477 38
        $this->writeMsoDrawing();
478
479
        // Write WINDOW2 record
480 38
        $this->writeWindow2();
481
482
        // Write PLV record
483 38
        $this->writePageLayoutView();
484
485
        // Write ZOOM record
486 38
        $this->writeZoom();
487 38
        if ($phpSheet->getFreezePane()) {
488 3
            $this->writePanes();
489
        }
490
491
        // Write SELECTION record
492 38
        $this->writeSelection();
493
494
        // Write MergedCellsTable Record
495 38
        $this->writeMergedCells();
496
497
        // Hyperlinks
498 38
        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 38
        $this->writeDataValidity();
517 38
        $this->writeSheetLayout();
518
519
        // Write SHEETPROTECTION record
520 38
        $this->writeSheetProtection();
521 38
        $this->writeRangeProtection();
522
523 38
        $arrConditionalStyles = $phpSheet->getConditionalStylesCollection();
524 38
        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 38
        $this->storeEof();
547 38
    }
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 38
    public function getData()
585
    {
586 38
        $buffer = 4096;
0 ignored issues
show
Unused Code introduced by
$buffer is not used, you could remove the assignment.

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

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

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

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

Loading history...
587
588
        // Return data stored in memory
589 38
        if (isset($this->_data)) {
590 38
            $tmp = $this->_data;
591 38
            unset($this->_data);
592
593 38
            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 33
    private function writeString($row, $col, $str, $xfIndex)
672
    {
673 33
        $this->writeLabelSst($row, $col, $str, $xfIndex);
674 33
    }
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 33 View Code Duplication
    private function writeLabelSst($row, $col, $str, $xfIndex)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
756
    {
757 33
        $record = 0x00FD; // Record identifier
758 33
        $length = 0x000A; // Bytes to follow
759
760 33
        $str = StringHelper::UTF8toBIFF8UnicodeLong($str);
761
762
        /* check if string is already present */
763 33
        if (!isset($this->stringTable[$str])) {
764 33
            $this->stringTable[$str] = $this->stringUnique++;
765
        }
766 33
        ++$this->stringTotal;
767
768 33
        $header = pack('vv', $record, $length);
769 33
        $data = pack('vvvV', $row, $col, $xfIndex, $this->stringTable[$str]);
770 33
        $this->append($header . $data);
771 33
    }
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 18 View Code Duplication
    public function writeBlank($row, $col, $xfIndex)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
821
    {
822 18
        $record = 0x0201; // Record identifier
823 18
        $length = 0x0006; // Number of bytes to follow
824
825 18
        $header = pack('vv', $record, $length);
826 18
        $data = pack('vvv', $row, $col, $xfIndex);
827 18
        $this->append($header . $data);
828
829 18
        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 37
    private function writeRow($row, $height, $xfIndex, $hidden = false, $level = 0)
1228
    {
1229 37
        $record = 0x0208; // Record identifier
1230 37
        $length = 0x0010; // Number of bytes to follow
1231
1232 37
        $colMic = 0x0000; // First defined column
1233 37
        $colMac = 0x0000; // Last defined column
1234 37
        $irwMac = 0x0000; // Used by Excel to optimise loading
1235 37
        $reserved = 0x0000; // Reserved
1236 37
        $grbit = 0x0000; // Option flags
1237 37
        $ixfe = $xfIndex;
1238
1239 37
        if ($height < 0) {
1240 36
            $height = null;
1241
        }
1242
1243
        // Use writeRow($row, null, $XF) to set XF format without setting height
1244 37
        if ($height != null) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $height of type null|integer against null; this is ambiguous if the integer can be zero. Consider using a strict comparison !== instead.
Loading history...
1245 6
            $miyRw = $height * 20; // row height
1246
        } else {
1247 36
            $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 37
        $grbit |= $level;
1257 37
        if ($hidden) {
1258 2
            $grbit |= 0x0030;
1259
        }
1260 37
        if ($height !== null) {
1261 6
            $grbit |= 0x0040; // fUnsynced
1262
        }
1263 37
        if ($xfIndex !== 0xF) {
1264
            $grbit |= 0x0080;
1265
        }
1266 37
        $grbit |= 0x0100;
1267
1268 37
        $header = pack('vv', $record, $length);
1269 37
        $data = pack('vvvvvvvv', $row, $colMic, $colMac, $miyRw, $irwMac, $reserved, $grbit, $ixfe);
1270 37
        $this->append($header . $data);
1271 37
    }
1272
1273
    /**
1274
     * Writes Excel DIMENSIONS to define the area in which there is data.
1275
     */
1276 38
    private function writeDimensions()
1277
    {
1278 38
        $record = 0x0200; // Record identifier
1279
1280 38
        $length = 0x000E;
1281 38
        $data = pack('VVvvv', $this->firstRowIndex, $this->lastRowIndex + 1, $this->firstColumnIndex, $this->lastColumnIndex + 1, 0x0000); // reserved
1282
1283 38
        $header = pack('vv', $record, $length);
1284 38
        $this->append($header . $data);
1285 38
    }
1286
1287
    /**
1288
     * Write BIFF record Window2.
1289
     */
1290 38
    private function writeWindow2()
1291
    {
1292 38
        $record = 0x023E; // Record identifier
1293 38
        $length = 0x0012;
1294
1295 38
        $grbit = 0x00B6; // Option flags
0 ignored issues
show
Unused Code introduced by
$grbit is not used, you could remove the assignment.

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

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

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

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

Loading history...
1296 38
        $rwTop = 0x0000; // Top row visible in window
1297 38
        $colLeft = 0x0000; // Leftmost column visible in window
1298
1299
        // The options flags that comprise $grbit
1300 38
        $fDspFmla = 0; // 0 - bit
1301 38
        $fDspGrid = $this->phpSheet->getShowGridlines() ? 1 : 0; // 1
1302 38
        $fDspRwCol = $this->phpSheet->getShowRowColHeaders() ? 1 : 0; // 2
1303 38
        $fFrozen = $this->phpSheet->getFreezePane() ? 1 : 0; // 3
1304 38
        $fDspZeros = 1; // 4
1305 38
        $fDefaultHdr = 1; // 5
1306 38
        $fArabic = $this->phpSheet->getRightToLeft() ? 1 : 0; // 6
1307 38
        $fDspGuts = $this->outlineOn; // 7
1308 38
        $fFrozenNoSplit = 0; // 0 - bit
1309
        // no support in PhpSpreadsheet for selected sheet, therefore sheet is only selected if it is the active sheet
1310 38
        $fSelected = ($this->phpSheet === $this->phpSheet->getParent()->getActiveSheet()) ? 1 : 0;
1311 38
        $fPaged = 1; // 2
1312 38
        $fPageBreakPreview = $this->phpSheet->getSheetView()->getView() === SheetView::SHEETVIEW_PAGE_BREAK_PREVIEW;
1313
1314 38
        $grbit = $fDspFmla;
1315 38
        $grbit |= $fDspGrid << 1;
1316 38
        $grbit |= $fDspRwCol << 2;
1317 38
        $grbit |= $fFrozen << 3;
1318 38
        $grbit |= $fDspZeros << 4;
1319 38
        $grbit |= $fDefaultHdr << 5;
1320 38
        $grbit |= $fArabic << 6;
1321 38
        $grbit |= $fDspGuts << 7;
1322 38
        $grbit |= $fFrozenNoSplit << 8;
1323 38
        $grbit |= $fSelected << 9;
1324 38
        $grbit |= $fPaged << 10;
1325 38
        $grbit |= $fPageBreakPreview << 11;
1326
1327 38
        $header = pack('vv', $record, $length);
1328 38
        $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 38
        $rgbHdr = 0x0040; // Row/column heading and gridline color index
1332 38
        $zoom_factor_page_break = ($fPageBreakPreview ? $this->phpSheet->getSheetView()->getZoomScale() : 0x0000);
1333 38
        $zoom_factor_normal = $this->phpSheet->getSheetView()->getZoomScaleNormal();
1334
1335 38
        $data .= pack('vvvvV', $rgbHdr, 0x0000, $zoom_factor_page_break, $zoom_factor_normal, 0x00000000);
1336
1337 38
        $this->append($header . $data);
1338 38
    }
1339
1340
    /**
1341
     * Write BIFF record DEFAULTROWHEIGHT.
1342
     */
1343 38
    private function writeDefaultRowHeight()
1344
    {
1345 38
        $defaultRowHeight = $this->phpSheet->getDefaultRowDimension()->getRowHeight();
1346
1347 38
        if ($defaultRowHeight < 0) {
1348 35
            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 38
    private function writeDefcol()
1366
    {
1367 38
        $defaultColWidth = 8;
1368
1369 38
        $record = 0x0055; // Record identifier
1370 38
        $length = 0x0002; // Number of bytes to follow
1371
1372 38
        $header = pack('vv', $record, $length);
1373 38
        $data = pack('v', $defaultColWidth);
1374 38
        $this->append($header . $data);
1375 38
    }
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 38
    private function writeColinfo($col_array)
1392
    {
1393 38
        if (isset($col_array[0])) {
1394 38
            $colFirst = $col_array[0];
1395
        }
1396 38
        if (isset($col_array[1])) {
1397 38
            $colLast = $col_array[1];
1398
        }
1399 38
        if (isset($col_array[2])) {
1400 38
            $coldx = $col_array[2];
1401
        } else {
1402
            $coldx = 8.43;
1403
        }
1404 38
        if (isset($col_array[3])) {
1405 38
            $xfIndex = $col_array[3];
1406
        } else {
1407
            $xfIndex = 15;
1408
        }
1409 38
        if (isset($col_array[4])) {
1410 38
            $grbit = $col_array[4];
1411
        } else {
1412
            $grbit = 0;
1413
        }
1414 38
        if (isset($col_array[5])) {
1415 38
            $level = $col_array[5];
1416
        } else {
1417
            $level = 0;
1418
        }
1419 38
        $record = 0x007D; // Record identifier
1420 38
        $length = 0x000C; // Number of bytes to follow
1421
1422 38
        $coldx *= 256; // Convert to units of 1/256 of a char
1423
1424 38
        $ixfe = $xfIndex;
1425 38
        $reserved = 0x0000; // Reserved
1426
1427 38
        $level = max(0, min($level, 7));
1428 38
        $grbit |= $level << 8;
1429
1430 38
        $header = pack('vv', $record, $length);
1431 38
        $data = pack('vvvvvv', $colFirst, $colLast, $coldx, $ixfe, $grbit, $reserved);
0 ignored issues
show
Bug introduced by
The variable $colFirst does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $colLast does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1432 38
        $this->append($header . $data);
1433 38
    }
1434
1435
    /**
1436
     * Write BIFF record SELECTION.
1437
     */
1438 38
    private function writeSelection()
1439
    {
1440
        // look up the selected cell range
1441 38
        $selectedCells = $this->phpSheet->getSelectedCells();
0 ignored issues
show
Unused Code introduced by
$selectedCells is not used, you could remove the assignment.

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

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

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

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

Loading history...
1442 38
        $selectedCells = Cell::splitRange($this->phpSheet->getSelectedCells());
1443 38
        $selectedCells = $selectedCells[0];
1444 38
        if (count($selectedCells) == 2) {
1445 13
            list($first, $last) = $selectedCells;
1446
        } else {
1447 31
            $first = $selectedCells[0];
1448 31
            $last = $selectedCells[0];
1449
        }
1450
1451 38
        list($colFirst, $rwFirst) = Cell::coordinateFromString($first);
1452 38
        $colFirst = Cell::columnIndexFromString($colFirst) - 1; // base 0 column index
1453 38
        --$rwFirst; // base 0 row index
1454
1455 38
        list($colLast, $rwLast) = Cell::coordinateFromString($last);
1456 38
        $colLast = Cell::columnIndexFromString($colLast) - 1; // base 0 column index
1457 38
        --$rwLast; // base 0 row index
1458
1459
        // make sure we are not out of bounds
1460 38
        $colFirst = min($colFirst, 255);
1461 38
        $colLast = min($colLast, 255);
1462
1463 38
        $rwFirst = min($rwFirst, 65535);
1464 38
        $rwLast = min($rwLast, 65535);
1465
1466 38
        $record = 0x001D; // Record identifier
1467 38
        $length = 0x000F; // Number of bytes to follow
1468
1469 38
        $pnn = $this->activePane; // Pane position
1470 38
        $rwAct = $rwFirst; // Active row
1471 38
        $colAct = $colFirst; // Active column
1472 38
        $irefAct = 0; // Active cell ref
1473 38
        $cref = 1; // Number of refs
1474
1475 38
        if (!isset($rwLast)) {
1476
            $rwLast = $rwFirst; // Last  row in reference
1477
        }
1478 38
        if (!isset($colLast)) {
1479
            $colLast = $colFirst; // Last  col in reference
1480
        }
1481
1482
        // Swap last row/col for first row/col as necessary
1483 38
        if ($rwFirst > $rwLast) {
1484
            list($rwFirst, $rwLast) = [$rwLast, $rwFirst];
1485
        }
1486
1487 38
        if ($colFirst > $colLast) {
1488
            list($colFirst, $colLast) = [$colLast, $colFirst];
1489
        }
1490
1491 38
        $header = pack('vv', $record, $length);
1492 38
        $data = pack('CvvvvvvCC', $pnn, $rwAct, $colAct, $irefAct, $cref, $rwFirst, $rwLast, $colFirst, $colLast);
1493 38
        $this->append($header . $data);
1494 38
    }
1495
1496
    /**
1497
     * Store the MERGEDCELLS records for all ranges of merged cells.
1498
     */
1499 38
    private function writeMergedCells()
1500
    {
1501 38
        $mergeCells = $this->phpSheet->getMergeCells();
1502 38
        $countMergeCells = count($mergeCells);
1503
1504 38
        if ($countMergeCells == 0) {
1505 37
            return;
1506
        }
1507
1508
        // maximum allowed number of merged cells per record
1509 9
        $maxCountMergeCellsPerRecord = 1027;
1510
1511
        // record identifier
1512 9
        $record = 0x00E5;
1513
1514
        // counter for total number of merged cells treated so far by the writer
1515 9
        $i = 0;
1516
1517
        // counter for number of merged cells written in record currently being written
1518 9
        $j = 0;
1519
1520
        // initialize record data
1521 9
        $recordData = '';
1522
1523
        // loop through the merged cells
1524 9
        foreach ($mergeCells as $mergeCell) {
1525 9
            ++$i;
1526 9
            ++$j;
1527
1528
            // extract the row and column indexes
1529 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...
1530 9
            list($first, $last) = $range[0];
1531 9
            list($firstColumn, $firstRow) = Cell::coordinateFromString($first);
1532 9
            list($lastColumn, $lastRow) = Cell::coordinateFromString($last);
1533
1534 9
            $recordData .= pack('vvvv', $firstRow - 1, $lastRow - 1, Cell::columnIndexFromString($firstColumn) - 1, Cell::columnIndexFromString($lastColumn) - 1);
1535
1536
            // flush record if we have reached limit for number of merged cells, or reached final merged cell
1537 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...
1538 9
                $recordData = pack('v', $j) . $recordData;
1539 9
                $length = strlen($recordData);
1540 9
                $header = pack('vv', $record, $length);
1541 9
                $this->append($header . $recordData);
1542
1543
                // initialize for next record, if any
1544 9
                $recordData = '';
1545 9
                $j = 0;
1546
            }
1547
        }
1548 9
    }
1549
1550
    /**
1551
     * Write SHEETLAYOUT record.
1552
     */
1553 38
    private function writeSheetLayout()
1554
    {
1555 38
        if (!$this->phpSheet->isTabColorSet()) {
1556 38
            return;
1557
        }
1558
1559 5
        $recordData = pack(
1560 5
            'vvVVVvv',
1561 5
            0x0862,
1562 5
            0x0000, // unused
1563 5
            0x00000000, // unused
1564 5
            0x00000000, // unused
1565 5
            0x00000014, // size of record data
1566 5
            $this->colors[$this->phpSheet->getTabColor()->getRGB()], // color index
1567 5
            0x0000        // unused
1568
        );
1569
1570 5
        $length = strlen($recordData);
1571
1572 5
        $record = 0x0862; // Record identifier
1573 5
        $header = pack('vv', $record, $length);
1574 5
        $this->append($header . $recordData);
1575 5
    }
1576
1577
    /**
1578
     * Write SHEETPROTECTION.
1579
     */
1580 38
    private function writeSheetProtection()
1581
    {
1582
        // record identifier
1583 38
        $record = 0x0867;
1584
1585
        // prepare options
1586 38
        $options = (int) !$this->phpSheet->getProtection()->getObjects()
1587 38
                    | (int) !$this->phpSheet->getProtection()->getScenarios() << 1
1588 38
                    | (int) !$this->phpSheet->getProtection()->getFormatCells() << 2
1589 38
                    | (int) !$this->phpSheet->getProtection()->getFormatColumns() << 3
1590 38
                    | (int) !$this->phpSheet->getProtection()->getFormatRows() << 4
1591 38
                    | (int) !$this->phpSheet->getProtection()->getInsertColumns() << 5
1592 38
                    | (int) !$this->phpSheet->getProtection()->getInsertRows() << 6
1593 38
                    | (int) !$this->phpSheet->getProtection()->getInsertHyperlinks() << 7
1594 38
                    | (int) !$this->phpSheet->getProtection()->getDeleteColumns() << 8
1595 38
                    | (int) !$this->phpSheet->getProtection()->getDeleteRows() << 9
1596 38
                    | (int) !$this->phpSheet->getProtection()->getSelectLockedCells() << 10
1597 38
                    | (int) !$this->phpSheet->getProtection()->getSort() << 11
1598 38
                    | (int) !$this->phpSheet->getProtection()->getAutoFilter() << 12
1599 38
                    | (int) !$this->phpSheet->getProtection()->getPivotTables() << 13
1600 38
                    | (int) !$this->phpSheet->getProtection()->getSelectUnlockedCells() << 14;
1601
1602
        // record data
1603 38
        $recordData = pack(
1604 38
            'vVVCVVvv',
1605 38
            0x0867, // repeated record identifier
1606 38
            0x0000, // not used
1607 38
            0x0000, // not used
1608 38
            0x00, // not used
1609 38
            0x01000200, // unknown data
1610 38
            0xFFFFFFFF, // unknown data
1611
            $options, // options
1612 38
            0x0000 // not used
1613
        );
1614
1615 38
        $length = strlen($recordData);
1616 38
        $header = pack('vv', $record, $length);
1617
1618 38
        $this->append($header . $recordData);
1619 38
    }
1620
1621
    /**
1622
     * Write BIFF record RANGEPROTECTION.
1623
     *
1624
     * Openoffice.org's Documentaion of the Microsoft Excel File Format uses term RANGEPROTECTION for these records
1625
     * Microsoft Office Excel 97-2007 Binary File Format Specification uses term FEAT for these records
1626
     */
1627 38
    private function writeRangeProtection()
1628
    {
1629 38
        foreach ($this->phpSheet->getProtectedCells() as $range => $password) {
1630
            // number of ranges, e.g. 'A1:B3 C20:D25'
1631 5
            $cellRanges = explode(' ', $range);
1632 5
            $cref = count($cellRanges);
1633
1634 5
            $recordData = pack(
1635 5
                'vvVVvCVvVv',
1636 5
                0x0868,
1637 5
                0x00,
1638 5
                0x0000,
1639 5
                0x0000,
1640 5
                0x02,
1641 5
                0x0,
1642 5
                0x0000,
1643
                $cref,
1644 5
                0x0000,
1645 5
                0x00
1646
            );
1647
1648 5
            foreach ($cellRanges as $cellRange) {
1649 5
                $recordData .= $this->writeBIFF8CellRangeAddressFixed($cellRange);
1650
            }
1651
1652
            // the rgbFeat structure
1653 5
            $recordData .= pack(
1654 5
                'VV',
1655 5
                0x0000,
1656
                hexdec($password)
1657
            );
1658
1659 5
            $recordData .= StringHelper::UTF8toBIFF8UnicodeLong('p' . md5($recordData));
1660
1661 5
            $length = strlen($recordData);
1662
1663 5
            $record = 0x0868; // Record identifier
1664 5
            $header = pack('vv', $record, $length);
1665 5
            $this->append($header . $recordData);
1666
        }
1667 38
    }
1668
1669
    /**
1670
     * Write BIFF record EXTERNCOUNT to indicate the number of external sheet
1671
     * references in a worksheet.
1672
     *
1673
     * Excel only stores references to external sheets that are used in formulas.
1674
     * For simplicity we store references to all the sheets in the workbook
1675
     * regardless of whether they are used or not. This reduces the overall
1676
     * complexity and eliminates the need for a two way dialogue between the formula
1677
     * parser the worksheet objects.
1678
     *
1679
     * @param int $count The number of external sheet references in this worksheet
1680
     */
1681 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...
1682
    {
1683
        $record = 0x0016; // Record identifier
1684
        $length = 0x0002; // Number of bytes to follow
1685
1686
        $header = pack('vv', $record, $length);
1687
        $data = pack('v', $count);
1688
        $this->append($header . $data);
1689
    }
1690
1691
    /**
1692
     * Writes the Excel BIFF EXTERNSHEET record. These references are used by
1693
     * formulas. A formula references a sheet name via an index. Since we store a
1694
     * reference to all of the external worksheets the EXTERNSHEET index is the same
1695
     * as the worksheet index.
1696
     *
1697
     * @param string $sheetname The name of a external worksheet
1698
     */
1699
    private function writeExternsheet($sheetname)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
1700
    {
1701
        $record = 0x0017; // Record identifier
1702
1703
        // References to the current sheet are encoded differently to references to
1704
        // external sheets.
1705
        //
1706
        if ($this->phpSheet->getTitle() == $sheetname) {
1707
            $sheetname = '';
1708
            $length = 0x02; // The following 2 bytes
1709
            $cch = 1; // The following byte
1710
            $rgch = 0x02; // Self reference
1711
        } else {
1712
            $length = 0x02 + strlen($sheetname);
1713
            $cch = strlen($sheetname);
1714
            $rgch = 0x03; // Reference to a sheet in the current workbook
1715
        }
1716
1717
        $header = pack('vv', $record, $length);
1718
        $data = pack('CC', $cch, $rgch);
1719
        $this->append($header . $data . $sheetname);
1720
    }
1721
1722
    /**
1723
     * Writes the Excel BIFF PANE record.
1724
     * The panes can either be frozen or thawed (unfrozen).
1725
     * Frozen panes are specified in terms of an integer number of rows and columns.
1726
     * Thawed panes are specified in terms of Excel's units for rows and columns.
1727
     */
1728 3
    private function writePanes()
1729
    {
1730 3
        $panes = [];
1731 3
        if ($freezePane = $this->phpSheet->getFreezePane()) {
1732 3
            list($column, $row) = Cell::coordinateFromString($freezePane);
1733 3
            $panes[0] = $row - 1;
1734 3
            $panes[1] = Cell::columnIndexFromString($column) - 1;
1735
        } else {
1736
            // thaw panes
1737
            return;
1738
        }
1739
1740 3
        $y = isset($panes[0]) ? $panes[0] : null;
1741 3
        $x = isset($panes[1]) ? $panes[1] : null;
1742 3
        $rwTop = isset($panes[2]) ? $panes[2] : null;
1743 3
        $colLeft = isset($panes[3]) ? $panes[3] : null;
1744 3
        if (count($panes) > 4) { // if Active pane was received
1745
            $pnnAct = $panes[4];
1746
        } else {
1747 3
            $pnnAct = null;
1748
        }
1749 3
        $record = 0x0041; // Record identifier
1750 3
        $length = 0x000A; // Number of bytes to follow
1751
1752
        // Code specific to frozen or thawed panes.
1753 3
        if ($this->phpSheet->getFreezePane()) {
1754
            // 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...
1755 3
            if (!isset($rwTop)) {
1756 3
                $rwTop = $y;
1757
            }
1758 3
            if (!isset($colLeft)) {
1759 3
                $colLeft = $x;
1760
            }
1761
        } else {
1762
            // 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...
1763
            if (!isset($rwTop)) {
1764
                $rwTop = 0;
1765
            }
1766
            if (!isset($colLeft)) {
1767
                $colLeft = 0;
1768
            }
1769
1770
            // Convert Excel's row and column units to the internal units.
1771
            // The default row height is 12.75
1772
            // The default column width is 8.43
1773
            // The following slope and intersection values were interpolated.
1774
            //
1775
            $y = 20 * $y + 255;
1776
            $x = 113.879 * $x + 390;
1777
        }
1778
1779
        // Determine which pane should be active. There is also the undocumented
1780
        // option to override this should it be necessary: may be removed later.
1781
        //
1782 3
        if (!isset($pnnAct)) {
1783 3
            if ($x != 0 && $y != 0) {
1784
                $pnnAct = 0; // Bottom right
1785
            }
1786 3
            if ($x != 0 && $y == 0) {
1787
                $pnnAct = 1; // Top right
1788
            }
1789 3
            if ($x == 0 && $y != 0) {
1790 3
                $pnnAct = 2; // Bottom left
1791
            }
1792 3
            if ($x == 0 && $y == 0) {
1793
                $pnnAct = 3; // Top left
1794
            }
1795
        }
1796
1797 3
        $this->activePane = $pnnAct; // Used in writeSelection
1798
1799 3
        $header = pack('vv', $record, $length);
1800 3
        $data = pack('vvvvv', $x, $y, $rwTop, $colLeft, $pnnAct);
1801 3
        $this->append($header . $data);
1802 3
    }
1803
1804
    /**
1805
     * Store the page setup SETUP BIFF record.
1806
     */
1807 38
    private function writeSetup()
1808
    {
1809 38
        $record = 0x00A1; // Record identifier
1810 38
        $length = 0x0022; // Number of bytes to follow
1811
1812 38
        $iPaperSize = $this->phpSheet->getPageSetup()->getPaperSize(); // Paper size
1813
1814 38
        $iScale = $this->phpSheet->getPageSetup()->getScale() ?
1815 38
            $this->phpSheet->getPageSetup()->getScale() : 100; // Print scaling factor
1816
1817 38
        $iPageStart = 0x01; // Starting page number
1818 38
        $iFitWidth = (int) $this->phpSheet->getPageSetup()->getFitToWidth(); // Fit to number of pages wide
1819 38
        $iFitHeight = (int) $this->phpSheet->getPageSetup()->getFitToHeight(); // Fit to number of pages high
1820 38
        $grbit = 0x00; // Option flags
0 ignored issues
show
Unused Code introduced by
$grbit is not used, you could remove the assignment.

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

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

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

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

Loading history...
1821 38
        $iRes = 0x0258; // Print resolution
1822 38
        $iVRes = 0x0258; // Vertical print resolution
1823
1824 38
        $numHdr = $this->phpSheet->getPageMargins()->getHeader(); // Header Margin
1825
1826 38
        $numFtr = $this->phpSheet->getPageMargins()->getFooter(); // Footer Margin
1827 38
        $iCopies = 0x01; // Number of copies
1828
1829 38
        $fLeftToRight = 0x0; // Print over then down
1830
1831
        // Page orientation
1832 38
        $fLandscape = ($this->phpSheet->getPageSetup()->getOrientation() == PageSetup::ORIENTATION_LANDSCAPE) ?
1833 38
            0x0 : 0x1;
1834
1835 38
        $fNoPls = 0x0; // Setup not read from printer
1836 38
        $fNoColor = 0x0; // Print black and white
1837 38
        $fDraft = 0x0; // Print draft quality
1838 38
        $fNotes = 0x0; // Print notes
1839 38
        $fNoOrient = 0x0; // Orientation not set
1840 38
        $fUsePage = 0x0; // Use custom starting page
1841
1842 38
        $grbit = $fLeftToRight;
1843 38
        $grbit |= $fLandscape << 1;
1844 38
        $grbit |= $fNoPls << 2;
1845 38
        $grbit |= $fNoColor << 3;
1846 38
        $grbit |= $fDraft << 4;
1847 38
        $grbit |= $fNotes << 5;
1848 38
        $grbit |= $fNoOrient << 6;
1849 38
        $grbit |= $fUsePage << 7;
1850
1851 38
        $numHdr = pack('d', $numHdr);
1852 38
        $numFtr = pack('d', $numFtr);
1853 38
        if (self::getByteOrder()) { // if it's Big Endian
1854
            $numHdr = strrev($numHdr);
1855
            $numFtr = strrev($numFtr);
1856
        }
1857
1858 38
        $header = pack('vv', $record, $length);
1859 38
        $data1 = pack('vvvvvvvv', $iPaperSize, $iScale, $iPageStart, $iFitWidth, $iFitHeight, $grbit, $iRes, $iVRes);
1860 38
        $data2 = $numHdr . $numFtr;
1861 38
        $data3 = pack('v', $iCopies);
1862 38
        $this->append($header . $data1 . $data2 . $data3);
1863 38
    }
1864
1865
    /**
1866
     * Store the header caption BIFF record.
1867
     */
1868 38 View Code Duplication
    private function writeHeader()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1869
    {
1870 38
        $record = 0x0014; // Record identifier
1871
1872
        /* 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...
1873
        // need to fix character count (multibyte!)
1874
        if (strlen($this->phpSheet->getHeaderFooter()->getOddHeader()) <= 255) {
1875
            $str      = $this->phpSheet->getHeaderFooter()->getOddHeader();       // header string
1876
        } else {
1877
            $str = '';
1878
        }
1879
        */
1880
1881 38
        $recordData = StringHelper::UTF8toBIFF8UnicodeLong($this->phpSheet->getHeaderFooter()->getOddHeader());
1882 38
        $length = strlen($recordData);
1883
1884 38
        $header = pack('vv', $record, $length);
1885
1886 38
        $this->append($header . $recordData);
1887 38
    }
1888
1889
    /**
1890
     * Store the footer caption BIFF record.
1891
     */
1892 38 View Code Duplication
    private function writeFooter()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1893
    {
1894 38
        $record = 0x0015; // Record identifier
1895
1896
        /* 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...
1897
        // need to fix character count (multibyte!)
1898
        if (strlen($this->phpSheet->getHeaderFooter()->getOddFooter()) <= 255) {
1899
            $str = $this->phpSheet->getHeaderFooter()->getOddFooter();
1900
        } else {
1901
            $str = '';
1902
        }
1903
        */
1904
1905 38
        $recordData = StringHelper::UTF8toBIFF8UnicodeLong($this->phpSheet->getHeaderFooter()->getOddFooter());
1906 38
        $length = strlen($recordData);
1907
1908 38
        $header = pack('vv', $record, $length);
1909
1910 38
        $this->append($header . $recordData);
1911 38
    }
1912
1913
    /**
1914
     * Store the horizontal centering HCENTER BIFF record.
1915
     */
1916 38 View Code Duplication
    private function writeHcenter()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1917
    {
1918 38
        $record = 0x0083; // Record identifier
1919 38
        $length = 0x0002; // Bytes to follow
1920
1921 38
        $fHCenter = $this->phpSheet->getPageSetup()->getHorizontalCentered() ? 1 : 0; // Horizontal centering
1922
1923 38
        $header = pack('vv', $record, $length);
1924 38
        $data = pack('v', $fHCenter);
1925
1926 38
        $this->append($header . $data);
1927 38
    }
1928
1929
    /**
1930
     * Store the vertical centering VCENTER BIFF record.
1931
     */
1932 38 View Code Duplication
    private function writeVcenter()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1933
    {
1934 38
        $record = 0x0084; // Record identifier
1935 38
        $length = 0x0002; // Bytes to follow
1936
1937 38
        $fVCenter = $this->phpSheet->getPageSetup()->getVerticalCentered() ? 1 : 0; // Horizontal centering
1938
1939 38
        $header = pack('vv', $record, $length);
1940 38
        $data = pack('v', $fVCenter);
1941 38
        $this->append($header . $data);
1942 38
    }
1943
1944
    /**
1945
     * Store the LEFTMARGIN BIFF record.
1946
     */
1947 38 View Code Duplication
    private function writeMarginLeft()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1948
    {
1949 38
        $record = 0x0026; // Record identifier
1950 38
        $length = 0x0008; // Bytes to follow
1951
1952 38
        $margin = $this->phpSheet->getPageMargins()->getLeft(); // Margin in inches
1953
1954 38
        $header = pack('vv', $record, $length);
1955 38
        $data = pack('d', $margin);
1956 38
        if (self::getByteOrder()) { // if it's Big Endian
1957
            $data = strrev($data);
1958
        }
1959
1960 38
        $this->append($header . $data);
1961 38
    }
1962
1963
    /**
1964
     * Store the RIGHTMARGIN BIFF record.
1965
     */
1966 38 View Code Duplication
    private function writeMarginRight()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1967
    {
1968 38
        $record = 0x0027; // Record identifier
1969 38
        $length = 0x0008; // Bytes to follow
1970
1971 38
        $margin = $this->phpSheet->getPageMargins()->getRight(); // Margin in inches
1972
1973 38
        $header = pack('vv', $record, $length);
1974 38
        $data = pack('d', $margin);
1975 38
        if (self::getByteOrder()) { // if it's Big Endian
1976
            $data = strrev($data);
1977
        }
1978
1979 38
        $this->append($header . $data);
1980 38
    }
1981
1982
    /**
1983
     * Store the TOPMARGIN BIFF record.
1984
     */
1985 38 View Code Duplication
    private function writeMarginTop()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1986
    {
1987 38
        $record = 0x0028; // Record identifier
1988 38
        $length = 0x0008; // Bytes to follow
1989
1990 38
        $margin = $this->phpSheet->getPageMargins()->getTop(); // Margin in inches
1991
1992 38
        $header = pack('vv', $record, $length);
1993 38
        $data = pack('d', $margin);
1994 38
        if (self::getByteOrder()) { // if it's Big Endian
1995
            $data = strrev($data);
1996
        }
1997
1998 38
        $this->append($header . $data);
1999 38
    }
2000
2001
    /**
2002
     * Store the BOTTOMMARGIN BIFF record.
2003
     */
2004 38 View Code Duplication
    private function writeMarginBottom()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2005
    {
2006 38
        $record = 0x0029; // Record identifier
2007 38
        $length = 0x0008; // Bytes to follow
2008
2009 38
        $margin = $this->phpSheet->getPageMargins()->getBottom(); // Margin in inches
2010
2011 38
        $header = pack('vv', $record, $length);
2012 38
        $data = pack('d', $margin);
2013 38
        if (self::getByteOrder()) { // if it's Big Endian
2014
            $data = strrev($data);
2015
        }
2016
2017 38
        $this->append($header . $data);
2018 38
    }
2019
2020
    /**
2021
     * Write the PRINTHEADERS BIFF record.
2022
     */
2023 38 View Code Duplication
    private function writePrintHeaders()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2024
    {
2025 38
        $record = 0x002a; // Record identifier
2026 38
        $length = 0x0002; // Bytes to follow
2027
2028 38
        $fPrintRwCol = $this->printHeaders; // Boolean flag
2029
2030 38
        $header = pack('vv', $record, $length);
2031 38
        $data = pack('v', $fPrintRwCol);
2032 38
        $this->append($header . $data);
2033 38
    }
2034
2035
    /**
2036
     * Write the PRINTGRIDLINES BIFF record. Must be used in conjunction with the
2037
     * GRIDSET record.
2038
     */
2039 38 View Code Duplication
    private function writePrintGridlines()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2040
    {
2041 38
        $record = 0x002b; // Record identifier
2042 38
        $length = 0x0002; // Bytes to follow
2043
2044 38
        $fPrintGrid = $this->phpSheet->getPrintGridlines() ? 1 : 0; // Boolean flag
2045
2046 38
        $header = pack('vv', $record, $length);
2047 38
        $data = pack('v', $fPrintGrid);
2048 38
        $this->append($header . $data);
2049 38
    }
2050
2051
    /**
2052
     * Write the GRIDSET BIFF record. Must be used in conjunction with the
2053
     * PRINTGRIDLINES record.
2054
     */
2055 38
    private function writeGridset()
2056
    {
2057 38
        $record = 0x0082; // Record identifier
2058 38
        $length = 0x0002; // Bytes to follow
2059
2060 38
        $fGridSet = !$this->phpSheet->getPrintGridlines(); // Boolean flag
2061
2062 38
        $header = pack('vv', $record, $length);
2063 38
        $data = pack('v', $fGridSet);
2064 38
        $this->append($header . $data);
2065 38
    }
2066
2067
    /**
2068
     * Write the AUTOFILTERINFO BIFF record. This is used to configure the number of autofilter select used in the sheet.
2069
     */
2070 3
    private function writeAutoFilterInfo()
2071
    {
2072 3
        $record = 0x009D; // Record identifier
2073 3
        $length = 0x0002; // Bytes to follow
2074
2075 3
        $rangeBounds = Cell::rangeBoundaries($this->phpSheet->getAutoFilter()->getRange());
2076 3
        $iNumFilters = 1 + $rangeBounds[1][0] - $rangeBounds[0][0];
2077
2078 3
        $header = pack('vv', $record, $length);
2079 3
        $data = pack('v', $iNumFilters);
2080 3
        $this->append($header . $data);
2081 3
    }
2082
2083
    /**
2084
     * Write the GUTS BIFF record. This is used to configure the gutter margins
2085
     * where Excel outline symbols are displayed. The visibility of the gutters is
2086
     * controlled by a flag in WSBOOL.
2087
     *
2088
     * @see writeWsbool()
2089
     */
2090 38
    private function writeGuts()
2091
    {
2092 38
        $record = 0x0080; // Record identifier
2093 38
        $length = 0x0008; // Bytes to follow
2094
2095 38
        $dxRwGut = 0x0000; // Size of row gutter
2096 38
        $dxColGut = 0x0000; // Size of col gutter
2097
2098
        // determine maximum row outline level
2099 38
        $maxRowOutlineLevel = 0;
2100 38
        foreach ($this->phpSheet->getRowDimensions() as $rowDimension) {
2101 37
            $maxRowOutlineLevel = max($maxRowOutlineLevel, $rowDimension->getOutlineLevel());
2102
        }
2103
2104 38
        $col_level = 0;
2105
2106
        // Calculate the maximum column outline level. The equivalent calculation
2107
        // for the row outline level is carried out in writeRow().
2108 38
        $colcount = count($this->columnInfo);
2109 38
        for ($i = 0; $i < $colcount; ++$i) {
2110 38
            $col_level = max($this->columnInfo[$i][5], $col_level);
2111
        }
2112
2113
        // Set the limits for the outline levels (0 <= x <= 7).
2114 38
        $col_level = max(0, min($col_level, 7));
2115
2116
        // The displayed level is one greater than the max outline levels
2117 38
        if ($maxRowOutlineLevel) {
2118
            ++$maxRowOutlineLevel;
2119
        }
2120 38
        if ($col_level) {
2121 1
            ++$col_level;
2122
        }
2123
2124 38
        $header = pack('vv', $record, $length);
2125 38
        $data = pack('vvvv', $dxRwGut, $dxColGut, $maxRowOutlineLevel, $col_level);
2126
2127 38
        $this->append($header . $data);
2128 38
    }
2129
2130
    /**
2131
     * Write the WSBOOL BIFF record, mainly for fit-to-page. Used in conjunction
2132
     * with the SETUP record.
2133
     */
2134 38
    private function writeWsbool()
2135
    {
2136 38
        $record = 0x0081; // Record identifier
2137 38
        $length = 0x0002; // Bytes to follow
2138 38
        $grbit = 0x0000;
2139
2140
        // The only option that is of interest is the flag for fit to page. So we
2141
        // set all the options in one go.
2142
        //
2143
        // Set the option flags
2144 38
        $grbit |= 0x0001; // Auto page breaks visible
2145 38
        if ($this->outlineStyle) {
2146
            $grbit |= 0x0020; // Auto outline styles
2147
        }
2148 38
        if ($this->phpSheet->getShowSummaryBelow()) {
2149 38
            $grbit |= 0x0040; // Outline summary below
2150
        }
2151 38
        if ($this->phpSheet->getShowSummaryRight()) {
2152 38
            $grbit |= 0x0080; // Outline summary right
2153
        }
2154 38
        if ($this->phpSheet->getPageSetup()->getFitToPage()) {
2155
            $grbit |= 0x0100; // Page setup fit to page
2156
        }
2157 38
        if ($this->outlineOn) {
2158 38
            $grbit |= 0x0400; // Outline symbols displayed
2159
        }
2160
2161 38
        $header = pack('vv', $record, $length);
2162 38
        $data = pack('v', $grbit);
2163 38
        $this->append($header . $data);
2164 38
    }
2165
2166
    /**
2167
     * Write the HORIZONTALPAGEBREAKS and VERTICALPAGEBREAKS BIFF records.
2168
     */
2169 38
    private function writeBreaks()
2170
    {
2171
        // initialize
2172 38
        $vbreaks = [];
2173 38
        $hbreaks = [];
2174
2175 38
        foreach ($this->phpSheet->getBreaks() as $cell => $breakType) {
2176
            // Fetch coordinates
2177 1
            $coordinates = Cell::coordinateFromString($cell);
2178
2179
            // Decide what to do by the type of break
2180
            switch ($breakType) {
2181 1
                case \PhpOffice\PhpSpreadsheet\Worksheet::BREAK_COLUMN:
2182
                    // Add to list of vertical breaks
2183
                    $vbreaks[] = Cell::columnIndexFromString($coordinates[0]) - 1;
2184
                    break;
2185 1
                case \PhpOffice\PhpSpreadsheet\Worksheet::BREAK_ROW:
2186
                    // Add to list of horizontal breaks
2187 1
                    $hbreaks[] = $coordinates[1];
2188 1
                    break;
2189
                case \PhpOffice\PhpSpreadsheet\Worksheet::BREAK_NONE:
2190
                default:
2191
                    // Nothing to do
2192 1
                    break;
2193
            }
2194
        }
2195
2196
        //horizontal page breaks
2197 38
        if (!empty($hbreaks)) {
2198
            // Sort and filter array of page breaks
2199 1
            sort($hbreaks, SORT_NUMERIC);
2200 1
            if ($hbreaks[0] == 0) { // don't use first break if it's 0
2201
                array_shift($hbreaks);
2202
            }
2203
2204 1
            $record = 0x001b; // Record identifier
2205 1
            $cbrk = count($hbreaks); // Number of page breaks
2206 1
            $length = 2 + 6 * $cbrk; // Bytes to follow
2207
2208 1
            $header = pack('vv', $record, $length);
2209 1
            $data = pack('v', $cbrk);
2210
2211
            // Append each page break
2212 1
            foreach ($hbreaks as $hbreak) {
2213 1
                $data .= pack('vvv', $hbreak, 0x0000, 0x00ff);
2214
            }
2215
2216 1
            $this->append($header . $data);
2217
        }
2218
2219
        // vertical page breaks
2220 38
        if (!empty($vbreaks)) {
2221
            // 1000 vertical pagebreaks appears to be an internal Excel 5 limit.
2222
            // It is slightly higher in Excel 97/200, approx. 1026
2223
            $vbreaks = array_slice($vbreaks, 0, 1000);
2224
2225
            // Sort and filter array of page breaks
2226
            sort($vbreaks, SORT_NUMERIC);
2227
            if ($vbreaks[0] == 0) { // don't use first break if it's 0
2228
                array_shift($vbreaks);
2229
            }
2230
2231
            $record = 0x001a; // Record identifier
2232
            $cbrk = count($vbreaks); // Number of page breaks
2233
            $length = 2 + 6 * $cbrk; // Bytes to follow
2234
2235
            $header = pack('vv', $record, $length);
2236
            $data = pack('v', $cbrk);
2237
2238
            // Append each page break
2239
            foreach ($vbreaks as $vbreak) {
2240
                $data .= pack('vvv', $vbreak, 0x0000, 0xffff);
2241
            }
2242
2243
            $this->append($header . $data);
2244
        }
2245 38
    }
2246
2247
    /**
2248
     * Set the Biff PROTECT record to indicate that the worksheet is protected.
2249
     */
2250 38 View Code Duplication
    private function writeProtect()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2251
    {
2252
        // Exit unless sheet protection has been specified
2253 38
        if (!$this->phpSheet->getProtection()->getSheet()) {
2254 36
            return;
2255
        }
2256
2257 7
        $record = 0x0012; // Record identifier
2258 7
        $length = 0x0002; // Bytes to follow
2259
2260 7
        $fLock = 1; // Worksheet is protected
2261
2262 7
        $header = pack('vv', $record, $length);
2263 7
        $data = pack('v', $fLock);
2264
2265 7
        $this->append($header . $data);
2266 7
    }
2267
2268
    /**
2269
     * Write SCENPROTECT.
2270
     */
2271 38 View Code Duplication
    private function writeScenProtect()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2272
    {
2273
        // Exit if sheet protection is not active
2274 38
        if (!$this->phpSheet->getProtection()->getSheet()) {
2275 36
            return;
2276
        }
2277
2278
        // Exit if scenarios are not protected
2279 7
        if (!$this->phpSheet->getProtection()->getScenarios()) {
2280 7
            return;
2281
        }
2282
2283
        $record = 0x00DD; // Record identifier
2284
        $length = 0x0002; // Bytes to follow
2285
2286
        $header = pack('vv', $record, $length);
2287
        $data = pack('v', 1);
2288
2289
        $this->append($header . $data);
2290
    }
2291
2292
    /**
2293
     * Write OBJECTPROTECT.
2294
     */
2295 38 View Code Duplication
    private function writeObjectProtect()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2296
    {
2297
        // Exit if sheet protection is not active
2298 38
        if (!$this->phpSheet->getProtection()->getSheet()) {
2299 36
            return;
2300
        }
2301
2302
        // Exit if objects are not protected
2303 7
        if (!$this->phpSheet->getProtection()->getObjects()) {
2304 7
            return;
2305
        }
2306
2307
        $record = 0x0063; // Record identifier
2308
        $length = 0x0002; // Bytes to follow
2309
2310
        $header = pack('vv', $record, $length);
2311
        $data = pack('v', 1);
2312
2313
        $this->append($header . $data);
2314
    }
2315
2316
    /**
2317
     * Write the worksheet PASSWORD record.
2318
     */
2319 38
    private function writePassword()
2320
    {
2321
        // Exit unless sheet protection and password have been specified
2322 38
        if (!$this->phpSheet->getProtection()->getSheet() || !$this->phpSheet->getProtection()->getPassword()) {
2323 37
            return;
2324
        }
2325
2326 1
        $record = 0x0013; // Record identifier
2327 1
        $length = 0x0002; // Bytes to follow
2328
2329 1
        $wPassword = hexdec($this->phpSheet->getProtection()->getPassword()); // Encoded password
2330
2331 1
        $header = pack('vv', $record, $length);
2332 1
        $data = pack('v', $wPassword);
2333
2334 1
        $this->append($header . $data);
2335 1
    }
2336
2337
    /**
2338
     * Insert a 24bit bitmap image in a worksheet.
2339
     *
2340
     * @param int $row The row we are going to insert the bitmap into
2341
     * @param int $col The column we are going to insert the bitmap into
2342
     * @param mixed $bitmap The bitmap filename or GD-image resource
2343
     * @param int $x the horizontal position (offset) of the image inside the cell
2344
     * @param int $y the vertical position (offset) of the image inside the cell
2345
     * @param float $scale_x The horizontal scale
2346
     * @param float $scale_y The vertical scale
2347
     */
2348
    public function insertBitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1)
2349
    {
2350
        $bitmap_array = (is_resource($bitmap) ? $this->processBitmapGd($bitmap) : $this->processBitmap($bitmap));
2351
        list($width, $height, $size, $data) = $bitmap_array;
2352
2353
        // Scale the frame of the image.
2354
        $width *= $scale_x;
2355
        $height *= $scale_y;
2356
2357
        // Calculate the vertices of the image and write the OBJ record
2358
        $this->positionImage($col, $row, $x, $y, $width, $height);
2359
2360
        // Write the IMDATA record to store the bitmap data
2361
        $record = 0x007f;
2362
        $length = 8 + $size;
2363
        $cf = 0x09;
2364
        $env = 0x01;
2365
        $lcb = $size;
2366
2367
        $header = pack('vvvvV', $record, $length, $cf, $env, $lcb);
2368
        $this->append($header . $data);
2369
    }
2370
2371
    /**
2372
     * Calculate the vertices that define the position of the image as required by
2373
     * the OBJ record.
2374
     *
2375
     *         +------------+------------+
2376
     *         |     A      |      B     |
2377
     *   +-----+------------+------------+
2378
     *   |     |(x1,y1)     |            |
2379
     *   |  1  |(A1)._______|______      |
2380
     *   |     |    |              |     |
2381
     *   |     |    |              |     |
2382
     *   +-----+----|    BITMAP    |-----+
2383
     *   |     |    |              |     |
2384
     *   |  2  |    |______________.     |
2385
     *   |     |            |        (B2)|
2386
     *   |     |            |     (x2,y2)|
2387
     *   +---- +------------+------------+
2388
     *
2389
     * Example of a bitmap that covers some of the area from cell A1 to cell B2.
2390
     *
2391
     * Based on the width and height of the bitmap we need to calculate 8 vars:
2392
     *     $col_start, $row_start, $col_end, $row_end, $x1, $y1, $x2, $y2.
2393
     * The width and height of the cells are also variable and have to be taken into
2394
     * account.
2395
     * The values of $col_start and $row_start are passed in from the calling
2396
     * function. The values of $col_end and $row_end are calculated by subtracting
2397
     * the width and height of the bitmap from the width and height of the
2398
     * underlying cells.
2399
     * The vertices are expressed as a percentage of the underlying cell width as
2400
     * follows (rhs values are in pixels):
2401
     *
2402
     *       x1 = X / W *1024
2403
     *       y1 = Y / H *256
2404
     *       x2 = (X-1) / W *1024
2405
     *       y2 = (Y-1) / H *256
2406
     *
2407
     *       Where:  X is distance from the left side of the underlying cell
2408
     *               Y is distance from the top of the underlying cell
2409
     *               W is the width of the cell
2410
     *               H is the height of the cell
2411
     * The SDK incorrectly states that the height should be expressed as a
2412
     *        percentage of 1024.
2413
     *
2414
     * @param int $col_start Col containing upper left corner of object
2415
     * @param int $row_start Row containing top left corner of object
2416
     * @param int $x1 Distance to left side of object
2417
     * @param int $y1 Distance to top of object
2418
     * @param int $width Width of image frame
2419
     * @param int $height Height of image frame
2420
     */
2421
    public function positionImage($col_start, $row_start, $x1, $y1, $width, $height)
2422
    {
2423
        // Initialise end cell to the same as the start cell
2424
        $col_end = $col_start; // Col containing lower right corner of object
2425
        $row_end = $row_start; // Row containing bottom right corner of object
2426
2427
        // Zero the specified offset if greater than the cell dimensions
2428
        if ($x1 >= Xls::sizeCol($this->phpSheet, Cell::stringFromColumnIndex($col_start))) {
2429
            $x1 = 0;
2430
        }
2431
        if ($y1 >= Xls::sizeRow($this->phpSheet, $row_start + 1)) {
2432
            $y1 = 0;
2433
        }
2434
2435
        $width = $width + $x1 - 1;
2436
        $height = $height + $y1 - 1;
2437
2438
        // Subtract the underlying cell widths to find the end cell of the image
2439
        while ($width >= Xls::sizeCol($this->phpSheet, Cell::stringFromColumnIndex($col_end))) {
2440
            $width -= Xls::sizeCol($this->phpSheet, Cell::stringFromColumnIndex($col_end));
2441
            ++$col_end;
2442
        }
2443
2444
        // Subtract the underlying cell heights to find the end cell of the image
2445
        while ($height >= Xls::sizeRow($this->phpSheet, $row_end + 1)) {
2446
            $height -= Xls::sizeRow($this->phpSheet, $row_end + 1);
2447
            ++$row_end;
2448
        }
2449
2450
        // Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell
2451
        // with zero eight or width.
2452
        //
2453
        if (Xls::sizeCol($this->phpSheet, Cell::stringFromColumnIndex($col_start)) == 0) {
2454
            return;
2455
        }
2456
        if (Xls::sizeCol($this->phpSheet, Cell::stringFromColumnIndex($col_end)) == 0) {
2457
            return;
2458
        }
2459
        if (Xls::sizeRow($this->phpSheet, $row_start + 1) == 0) {
2460
            return;
2461
        }
2462
        if (Xls::sizeRow($this->phpSheet, $row_end + 1) == 0) {
2463
            return;
2464
        }
2465
2466
        // Convert the pixel values to the percentage value expected by Excel
2467
        $x1 = $x1 / Xls::sizeCol($this->phpSheet, Cell::stringFromColumnIndex($col_start)) * 1024;
2468
        $y1 = $y1 / Xls::sizeRow($this->phpSheet, $row_start + 1) * 256;
2469
        $x2 = $width / Xls::sizeCol($this->phpSheet, Cell::stringFromColumnIndex($col_end)) * 1024; // Distance to right side of object
2470
        $y2 = $height / Xls::sizeRow($this->phpSheet, $row_end + 1) * 256; // Distance to bottom of object
2471
2472
        $this->writeObjPicture($col_start, $x1, $row_start, $y1, $col_end, $x2, $row_end, $y2);
2473
    }
2474
2475
    /**
2476
     * Store the OBJ record that precedes an IMDATA record. This could be generalise
2477
     * to support other Excel objects.
2478
     *
2479
     * @param int $colL Column containing upper left corner of object
2480
     * @param int $dxL Distance from left side of cell
2481
     * @param int $rwT Row containing top left corner of object
2482
     * @param int $dyT Distance from top of cell
2483
     * @param int $colR Column containing lower right corner of object
2484
     * @param int $dxR Distance from right of cell
2485
     * @param int $rwB Row containing bottom right corner of object
2486
     * @param int $dyB Distance from bottom of cell
2487
     */
2488
    private function writeObjPicture($colL, $dxL, $rwT, $dyT, $colR, $dxR, $rwB, $dyB)
2489
    {
2490
        $record = 0x005d; // Record identifier
2491
        $length = 0x003c; // Bytes to follow
2492
2493
        $cObj = 0x0001; // Count of objects in file (set to 1)
2494
        $OT = 0x0008; // Object type. 8 = Picture
2495
        $id = 0x0001; // Object ID
2496
        $grbit = 0x0614; // Option flags
2497
2498
        $cbMacro = 0x0000; // Length of FMLA structure
2499
        $Reserved1 = 0x0000; // Reserved
2500
        $Reserved2 = 0x0000; // Reserved
2501
2502
        $icvBack = 0x09; // Background colour
2503
        $icvFore = 0x09; // Foreground colour
2504
        $fls = 0x00; // Fill pattern
2505
        $fAuto = 0x00; // Automatic fill
2506
        $icv = 0x08; // Line colour
2507
        $lns = 0xff; // Line style
2508
        $lnw = 0x01; // Line weight
2509
        $fAutoB = 0x00; // Automatic border
2510
        $frs = 0x0000; // Frame style
2511
        $cf = 0x0009; // Image format, 9 = bitmap
2512
        $Reserved3 = 0x0000; // Reserved
2513
        $cbPictFmla = 0x0000; // Length of FMLA structure
2514
        $Reserved4 = 0x0000; // Reserved
2515
        $grbit2 = 0x0001; // Option flags
2516
        $Reserved5 = 0x0000; // Reserved
2517
2518
        $header = pack('vv', $record, $length);
2519
        $data = pack('V', $cObj);
2520
        $data .= pack('v', $OT);
2521
        $data .= pack('v', $id);
2522
        $data .= pack('v', $grbit);
2523
        $data .= pack('v', $colL);
2524
        $data .= pack('v', $dxL);
2525
        $data .= pack('v', $rwT);
2526
        $data .= pack('v', $dyT);
2527
        $data .= pack('v', $colR);
2528
        $data .= pack('v', $dxR);
2529
        $data .= pack('v', $rwB);
2530
        $data .= pack('v', $dyB);
2531
        $data .= pack('v', $cbMacro);
2532
        $data .= pack('V', $Reserved1);
2533
        $data .= pack('v', $Reserved2);
2534
        $data .= pack('C', $icvBack);
2535
        $data .= pack('C', $icvFore);
2536
        $data .= pack('C', $fls);
2537
        $data .= pack('C', $fAuto);
2538
        $data .= pack('C', $icv);
2539
        $data .= pack('C', $lns);
2540
        $data .= pack('C', $lnw);
2541
        $data .= pack('C', $fAutoB);
2542
        $data .= pack('v', $frs);
2543
        $data .= pack('V', $cf);
2544
        $data .= pack('v', $Reserved3);
2545
        $data .= pack('v', $cbPictFmla);
2546
        $data .= pack('v', $Reserved4);
2547
        $data .= pack('v', $grbit2);
2548
        $data .= pack('V', $Reserved5);
2549
2550
        $this->append($header . $data);
2551
    }
2552
2553
    /**
2554
     * Convert a GD-image into the internal format.
2555
     *
2556
     * @param resource $image The image to process
2557
     *
2558
     * @return array Array with data and properties of the bitmap
2559
     */
2560
    public function processBitmapGd($image)
2561
    {
2562
        $width = imagesx($image);
2563
        $height = imagesy($image);
2564
2565
        $data = pack('Vvvvv', 0x000c, $width, $height, 0x01, 0x18);
2566
        for ($j = $height; --$j;) {
2567
            for ($i = 0; $i < $width; ++$i) {
2568
                $color = imagecolorsforindex($image, imagecolorat($image, $i, $j));
2569
                foreach (['red', 'green', 'blue'] as $key) {
2570
                    $color[$key] = $color[$key] + round((255 - $color[$key]) * $color['alpha'] / 127);
2571
                }
2572
                $data .= chr($color['blue']) . chr($color['green']) . chr($color['red']);
2573
            }
2574
            if (3 * $width % 4) {
2575
                $data .= str_repeat("\x00", 4 - 3 * $width % 4);
2576
            }
2577
        }
2578
2579
        return [$width, $height, strlen($data), $data];
2580
    }
2581
2582
    /**
2583
     * Convert a 24 bit bitmap into the modified internal format used by Windows.
2584
     * This is described in BITMAPCOREHEADER and BITMAPCOREINFO structures in the
2585
     * MSDN library.
2586
     *
2587
     * @param string $bitmap The bitmap to process
2588
     *
2589
     * @return array Array with data and properties of the bitmap
2590
     */
2591
    public function processBitmap($bitmap)
2592
    {
2593
        // Open file.
2594
        $bmp_fd = @fopen($bitmap, 'rb');
2595
        if (!$bmp_fd) {
2596
            throw new WriterException("Couldn't import $bitmap");
2597
        }
2598
2599
        // Slurp the file into a string.
2600
        $data = fread($bmp_fd, filesize($bitmap));
2601
2602
        // Check that the file is big enough to be a bitmap.
2603
        if (strlen($data) <= 0x36) {
2604
            throw new WriterException("$bitmap doesn't contain enough data.\n");
2605
        }
2606
2607
        // The first 2 bytes are used to identify the bitmap.
2608
        $identity = unpack('A2ident', $data);
2609
        if ($identity['ident'] != 'BM') {
2610
            throw new WriterException("$bitmap doesn't appear to be a valid bitmap image.\n");
2611
        }
2612
2613
        // Remove bitmap data: ID.
2614
        $data = substr($data, 2);
2615
2616
        // Read and remove the bitmap size. This is more reliable than reading
2617
        // the data size at offset 0x22.
2618
        //
2619
        $size_array = unpack('Vsa', substr($data, 0, 4));
2620
        $size = $size_array['sa'];
2621
        $data = substr($data, 4);
2622
        $size -= 0x36; // Subtract size of bitmap header.
2623
        $size += 0x0C; // Add size of BIFF header.
2624
2625
        // Remove bitmap data: reserved, offset, header length.
2626
        $data = substr($data, 12);
2627
2628
        // Read and remove the bitmap width and height. Verify the sizes.
2629
        $width_and_height = unpack('V2', substr($data, 0, 8));
2630
        $width = $width_and_height[1];
2631
        $height = $width_and_height[2];
2632
        $data = substr($data, 8);
2633
        if ($width > 0xFFFF) {
2634
            throw new WriterException("$bitmap: largest image width supported is 65k.\n");
2635
        }
2636
        if ($height > 0xFFFF) {
2637
            throw new WriterException("$bitmap: largest image height supported is 65k.\n");
2638
        }
2639
2640
        // Read and remove the bitmap planes and bpp data. Verify them.
2641
        $planes_and_bitcount = unpack('v2', substr($data, 0, 4));
2642
        $data = substr($data, 4);
2643
        if ($planes_and_bitcount[2] != 24) { // Bitcount
2644
            throw new WriterException("$bitmap isn't a 24bit true color bitmap.\n");
2645
        }
2646
        if ($planes_and_bitcount[1] != 1) {
2647
            throw new WriterException("$bitmap: only 1 plane supported in bitmap image.\n");
2648
        }
2649
2650
        // Read and remove the bitmap compression. Verify compression.
2651
        $compression = unpack('Vcomp', substr($data, 0, 4));
2652
        $data = substr($data, 4);
2653
2654
        if ($compression['comp'] != 0) {
2655
            throw new WriterException("$bitmap: compression not supported in bitmap image.\n");
2656
        }
2657
2658
        // Remove bitmap data: data size, hres, vres, colours, imp. colours.
2659
        $data = substr($data, 20);
2660
2661
        // Add the BITMAPCOREHEADER data
2662
        $header = pack('Vvvvv', 0x000c, $width, $height, 0x01, 0x18);
2663
        $data = $header . $data;
2664
2665
        return [$width, $height, $size, $data];
2666
    }
2667
2668
    /**
2669
     * Store the window zoom factor. This should be a reduced fraction but for
2670
     * simplicity we will store all fractions with a numerator of 100.
2671
     */
2672 38 View Code Duplication
    private function writeZoom()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2673
    {
2674
        // If scale is 100 we don't need to write a record
2675 38
        if ($this->phpSheet->getSheetView()->getZoomScale() == 100) {
2676 38
            return;
2677
        }
2678
2679
        $record = 0x00A0; // Record identifier
2680
        $length = 0x0004; // Bytes to follow
2681
2682
        $header = pack('vv', $record, $length);
2683
        $data = pack('vv', $this->phpSheet->getSheetView()->getZoomScale(), 100);
2684
        $this->append($header . $data);
2685
    }
2686
2687
    /**
2688
     * Get Escher object.
2689
     *
2690
     * @return \PhpOffice\PhpSpreadsheet\Shared\Escher
2691
     */
2692
    public function getEscher()
2693
    {
2694
        return $this->escher;
2695
    }
2696
2697
    /**
2698
     * Set Escher object.
2699
     *
2700
     * @param \PhpOffice\PhpSpreadsheet\Shared\Escher $pValue
2701
     */
2702 10
    public function setEscher(\PhpOffice\PhpSpreadsheet\Shared\Escher $pValue = null)
2703
    {
2704 10
        $this->escher = $pValue;
2705 10
    }
2706
2707
    /**
2708
     * Write MSODRAWING record.
2709
     */
2710 38
    private function writeMsoDrawing()
2711
    {
2712
        // write the Escher stream if necessary
2713 38
        if (isset($this->escher)) {
2714 10
            $writer = new Escher($this->escher);
2715 10
            $data = $writer->close();
2716 10
            $spOffsets = $writer->getSpOffsets();
2717 10
            $spTypes = $writer->getSpTypes();
2718
            // write the neccesary MSODRAWING, OBJ records
2719
2720
            // split the Escher stream
2721 10
            $spOffsets[0] = 0;
2722 10
            $nm = count($spOffsets) - 1; // number of shapes excluding first shape
2723 10
            for ($i = 1; $i <= $nm; ++$i) {
2724
                // MSODRAWING record
2725 10
                $record = 0x00EC; // Record identifier
2726
2727
                // chunk of Escher stream for one shape
2728 10
                $dataChunk = substr($data, $spOffsets[$i - 1], $spOffsets[$i] - $spOffsets[$i - 1]);
2729
2730 10
                $length = strlen($dataChunk);
2731 10
                $header = pack('vv', $record, $length);
2732
2733 10
                $this->append($header . $dataChunk);
2734
2735
                // OBJ record
2736 10
                $record = 0x005D; // record identifier
2737 10
                $objData = '';
2738
2739
                // ftCmo
2740 10
                if ($spTypes[$i] == 0x00C9) {
2741
                    // Add ftCmo (common object data) subobject
2742
                    $objData .=
2743 3
                        pack(
2744 3
                            'vvvvvVVV',
2745 3
                            0x0015, // 0x0015 = ftCmo
2746 3
                            0x0012, // length of ftCmo data
2747 3
                            0x0014, // object type, 0x0014 = filter
2748
                            $i, // object id number, Excel seems to use 1-based index, local for the sheet
2749 3
                            0x2101, // option flags, 0x2001 is what OpenOffice.org uses
2750 3
                            0, // reserved
2751 3
                            0, // reserved
2752 3
                            0  // reserved
2753
                        );
2754
2755
                    // Add ftSbs Scroll bar subobject
2756 3
                    $objData .= pack('vv', 0x00C, 0x0014);
2757 3
                    $objData .= pack('H*', '0000000000000000640001000A00000010000100');
2758
                    // Add ftLbsData (List box data) subobject
2759 3
                    $objData .= pack('vv', 0x0013, 0x1FEE);
2760 3
                    $objData .= pack('H*', '00000000010001030000020008005700');
2761
                } else {
2762
                    // Add ftCmo (common object data) subobject
2763
                    $objData .=
2764 7
                        pack(
2765 7
                            'vvvvvVVV',
2766 7
                            0x0015, // 0x0015 = ftCmo
2767 7
                            0x0012, // length of ftCmo data
2768 7
                            0x0008, // object type, 0x0008 = picture
2769
                            $i, // object id number, Excel seems to use 1-based index, local for the sheet
2770 7
                            0x6011, // option flags, 0x6011 is what OpenOffice.org uses
2771 7
                            0, // reserved
2772 7
                            0, // reserved
2773 7
                            0  // reserved
2774
                        );
2775
                }
2776
2777
                // ftEnd
2778
                $objData .=
2779 10
                    pack(
2780 10
                        'vv',
2781 10
                        0x0000, // 0x0000 = ftEnd
2782 10
                        0x0000  // length of ftEnd data
2783
                    );
2784
2785 10
                $length = strlen($objData);
2786 10
                $header = pack('vv', $record, $length);
2787 10
                $this->append($header . $objData);
2788
            }
2789
        }
2790 38
    }
2791
2792
    /**
2793
     * Store the DATAVALIDATIONS and DATAVALIDATION records.
2794
     *
2795
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
2796
     */
2797 38
    private function writeDataValidity()
2798
    {
2799
        // Datavalidation collection
2800 38
        $dataValidationCollection = $this->phpSheet->getDataValidationCollection();
2801
2802
        // Write data validations?
2803 38
        if (!empty($dataValidationCollection)) {
2804
            // DATAVALIDATIONS record
2805 2
            $record = 0x01B2; // Record identifier
2806 2
            $length = 0x0012; // Bytes to follow
2807
2808 2
            $grbit = 0x0000; // Prompt box at cell, no cached validity data at DV records
2809 2
            $horPos = 0x00000000; // Horizontal position of prompt box, if fixed position
2810 2
            $verPos = 0x00000000; // Vertical position of prompt box, if fixed position
2811 2
            $objId = 0xFFFFFFFF; // Object identifier of drop down arrow object, or -1 if not visible
2812
2813 2
            $header = pack('vv', $record, $length);
2814 2
            $data = pack('vVVVV', $grbit, $horPos, $verPos, $objId, count($dataValidationCollection));
2815 2
            $this->append($header . $data);
2816
2817
            // DATAVALIDATION records
2818 2
            $record = 0x01BE; // Record identifier
2819
2820 2
            foreach ($dataValidationCollection as $cellCoordinate => $dataValidation) {
2821
                // initialize record data
2822 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...
2823
2824
                // options
2825 2
                $options = 0x00000000;
2826
2827
                // data type
2828 2
                $type = 0x00;
2829 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...
2830 2
                    case DataValidation::TYPE_NONE:
2831
                        $type = 0x00;
2832
                        break;
2833 2
                    case DataValidation::TYPE_WHOLE:
2834 1
                        $type = 0x01;
2835 1
                        break;
2836 2
                    case DataValidation::TYPE_DECIMAL:
2837
                        $type = 0x02;
2838
                        break;
2839 2
                    case DataValidation::TYPE_LIST:
2840 2
                        $type = 0x03;
2841 2
                        break;
2842
                    case DataValidation::TYPE_DATE:
2843
                        $type = 0x04;
2844
                        break;
2845
                    case DataValidation::TYPE_TIME:
2846
                        $type = 0x05;
2847
                        break;
2848
                    case DataValidation::TYPE_TEXTLENGTH:
2849
                        $type = 0x06;
2850
                        break;
2851
                    case DataValidation::TYPE_CUSTOM:
2852
                        $type = 0x07;
2853
                        break;
2854
                }
2855
2856 2
                $options |= $type << 0;
2857
2858
                // error style
2859 2
                $errorStyle = 0x00;
2860 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...
2861 2
                    case DataValidation::STYLE_STOP:
2862 1
                        $errorStyle = 0x00;
2863 1
                        break;
2864 2
                    case DataValidation::STYLE_WARNING:
2865
                        $errorStyle = 0x01;
2866
                        break;
2867 2
                    case DataValidation::STYLE_INFORMATION:
2868 2
                        $errorStyle = 0x02;
2869 2
                        break;
2870
                }
2871
2872 2
                $options |= $errorStyle << 4;
2873
2874
                // explicit formula?
2875 2
                if ($type == 0x03 && preg_match('/^\".*\"$/', $dataValidation->getFormula1())) {
2876 1
                    $options |= 0x01 << 7;
2877
                }
2878
2879
                // empty cells allowed
2880 2
                $options |= $dataValidation->getAllowBlank() << 8;
2881
2882
                // show drop down
2883 2
                $options |= (!$dataValidation->getShowDropDown()) << 9;
2884
2885
                // show input message
2886 2
                $options |= $dataValidation->getShowInputMessage() << 18;
2887
2888
                // show error message
2889 2
                $options |= $dataValidation->getShowErrorMessage() << 19;
2890
2891
                // condition operator
2892 2
                $operator = 0x00;
2893 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...
2894 2
                    case DataValidation::OPERATOR_BETWEEN:
2895 2
                        $operator = 0x00;
2896 2
                        break;
2897
                    case DataValidation::OPERATOR_NOTBETWEEN:
2898
                        $operator = 0x01;
2899
                        break;
2900
                    case DataValidation::OPERATOR_EQUAL:
2901
                        $operator = 0x02;
2902
                        break;
2903
                    case DataValidation::OPERATOR_NOTEQUAL:
2904
                        $operator = 0x03;
2905
                        break;
2906
                    case DataValidation::OPERATOR_GREATERTHAN:
2907
                        $operator = 0x04;
2908
                        break;
2909
                    case DataValidation::OPERATOR_LESSTHAN:
2910
                        $operator = 0x05;
2911
                        break;
2912
                    case DataValidation::OPERATOR_GREATERTHANOREQUAL:
2913
                        $operator = 0x06;
2914
                        break;
2915
                    case DataValidation::OPERATOR_LESSTHANOREQUAL:
2916
                        $operator = 0x07;
2917
                        break;
2918
                }
2919
2920 2
                $options |= $operator << 20;
2921
2922 2
                $data = pack('V', $options);
2923
2924
                // prompt title
2925 2
                $promptTitle = $dataValidation->getPromptTitle() !== '' ?
2926 2
                    $dataValidation->getPromptTitle() : chr(0);
2927 2
                $data .= StringHelper::UTF8toBIFF8UnicodeLong($promptTitle);
2928
2929
                // error title
2930 2
                $errorTitle = $dataValidation->getErrorTitle() !== '' ?
2931 2
                    $dataValidation->getErrorTitle() : chr(0);
2932 2
                $data .= StringHelper::UTF8toBIFF8UnicodeLong($errorTitle);
2933
2934
                // prompt text
2935 2
                $prompt = $dataValidation->getPrompt() !== '' ?
2936 2
                    $dataValidation->getPrompt() : chr(0);
2937 2
                $data .= StringHelper::UTF8toBIFF8UnicodeLong($prompt);
2938
2939
                // error text
2940 2
                $error = $dataValidation->getError() !== '' ?
2941 2
                    $dataValidation->getError() : chr(0);
2942 2
                $data .= StringHelper::UTF8toBIFF8UnicodeLong($error);
2943
2944
                // formula 1
2945
                try {
2946 2
                    $formula1 = $dataValidation->getFormula1();
2947 2
                    if ($type == 0x03) { // list type
2948 2
                        $formula1 = str_replace(',', chr(0), $formula1);
2949
                    }
2950 2
                    $this->parser->parse($formula1);
2951 1
                    $formula1 = $this->parser->toReversePolish();
2952 1
                    $sz1 = strlen($formula1);
2953 2
                } catch (PhpSpreadsheetException $e) {
2954 2
                    $sz1 = 0;
2955 2
                    $formula1 = '';
2956
                }
2957 2
                $data .= pack('vv', $sz1, 0x0000);
2958 2
                $data .= $formula1;
2959
2960
                // formula 2
2961
                try {
2962 2
                    $formula2 = $dataValidation->getFormula2();
2963 2
                    if ($formula2 === '') {
2964 2
                        throw new WriterException('No formula2');
2965
                    }
2966 1
                    $this->parser->parse($formula2);
2967
                    $formula2 = $this->parser->toReversePolish();
2968
                    $sz2 = strlen($formula2);
2969 2
                } catch (PhpSpreadsheetException $e) {
2970 2
                    $sz2 = 0;
2971 2
                    $formula2 = '';
2972
                }
2973 2
                $data .= pack('vv', $sz2, 0x0000);
2974 2
                $data .= $formula2;
2975
2976
                // cell range address list
2977 2
                $data .= pack('v', 0x0001);
2978 2
                $data .= $this->writeBIFF8CellRangeAddressFixed($cellCoordinate);
2979
2980 2
                $length = strlen($data);
2981 2
                $header = pack('vv', $record, $length);
2982
2983 2
                $this->append($header . $data);
2984
            }
2985
        }
2986 38
    }
2987
2988
    /**
2989
     * Map Error code.
2990
     *
2991
     * @param string $errorCode
2992
     *
2993
     * @return int
2994
     */
2995 4
    private static function mapErrorCode($errorCode)
2996
    {
2997
        switch ($errorCode) {
2998 4
            case '#NULL!':
2999
                return 0x00;
3000 4
            case '#DIV/0!':
3001 3
                return 0x07;
3002 2
            case '#VALUE!':
3003 1
                return 0x0F;
3004 1
            case '#REF!':
3005
                return 0x17;
3006 1
            case '#NAME?':
3007
                return 0x1D;
3008 1
            case '#NUM!':
3009
                return 0x24;
3010 1
            case '#N/A':
3011 1
                return 0x2A;
3012
        }
3013
3014
        return 0;
3015
    }
3016
3017
    /**
3018
     * Write PLV Record.
3019
     */
3020 38
    private function writePageLayoutView()
3021
    {
3022 38
        $record = 0x088B; // Record identifier
3023 38
        $length = 0x0010; // Bytes to follow
3024
3025 38
        $rt = 0x088B; // 2
3026 38
        $grbitFrt = 0x0000; // 2
3027 38
        $reserved = 0x0000000000000000; // 8
0 ignored issues
show
Unused Code introduced by
$reserved is not used, you could remove the assignment.

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

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

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

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

Loading history...
3028 38
        $wScalvePLV = $this->phpSheet->getSheetView()->getZoomScale(); // 2
3029
3030
        // The options flags that comprise $grbit
3031 38
        if ($this->phpSheet->getSheetView()->getView() == SheetView::SHEETVIEW_PAGE_LAYOUT) {
3032 1
            $fPageLayoutView = 1;
3033
        } else {
3034 37
            $fPageLayoutView = 0;
3035
        }
3036 38
        $fRulerVisible = 0;
3037 38
        $fWhitespaceHidden = 0;
3038
3039 38
        $grbit = $fPageLayoutView; // 2
3040 38
        $grbit |= $fRulerVisible << 1;
3041 38
        $grbit |= $fWhitespaceHidden << 3;
3042
3043 38
        $header = pack('vv', $record, $length);
3044 38
        $data = pack('vvVVvv', $rt, $grbitFrt, 0x00000000, 0x00000000, $wScalvePLV, $grbit);
3045 38
        $this->append($header . $data);
3046 38
    }
3047
3048
    /**
3049
     * Write CFRule Record.
3050
     *
3051
     * @param Conditional $conditional
3052
     */
3053 2
    private function writeCFRule(Conditional $conditional)
3054
    {
3055 2
        $record = 0x01B1; // Record identifier
3056
3057
        // $type : Type of the CF
3058
        // $operatorType : Comparison operator
3059 2
        if ($conditional->getConditionType() == Conditional::CONDITION_EXPRESSION) {
3060
            $type = 0x02;
3061
            $operatorType = 0x00;
3062 2
        } elseif ($conditional->getConditionType() == Conditional::CONDITION_CELLIS) {
3063 2
            $type = 0x01;
3064
3065 2
            switch ($conditional->getOperatorType()) {
3066 2
                case Conditional::OPERATOR_NONE:
3067
                    $operatorType = 0x00;
3068
                    break;
3069 2
                case Conditional::OPERATOR_EQUAL:
3070
                    $operatorType = 0x03;
3071
                    break;
3072 2
                case Conditional::OPERATOR_GREATERTHAN:
3073
                    $operatorType = 0x05;
3074
                    break;
3075 2
                case Conditional::OPERATOR_GREATERTHANOREQUAL:
3076 2
                    $operatorType = 0x07;
3077 2
                    break;
3078 2
                case Conditional::OPERATOR_LESSTHAN:
3079 2
                    $operatorType = 0x06;
3080 2
                    break;
3081 1
                case Conditional::OPERATOR_LESSTHANOREQUAL:
3082
                    $operatorType = 0x08;
3083
                    break;
3084 1
                case Conditional::OPERATOR_NOTEQUAL:
3085
                    $operatorType = 0x04;
3086
                    break;
3087 1
                case Conditional::OPERATOR_BETWEEN:
3088 1
                    $operatorType = 0x01;
3089 1
                    break;
3090
                    // not OPERATOR_NOTBETWEEN 0x02
3091
            }
3092
        }
3093
3094
        // $szValue1 : size of the formula data for first value or formula
3095
        // $szValue2 : size of the formula data for second value or formula
3096 2
        $arrConditions = $conditional->getConditions();
3097 2
        $numConditions = count($arrConditions);
3098 2
        if ($numConditions == 1) {
3099 2
            $szValue1 = ($arrConditions[0] <= 65535 ? 3 : 0x0000);
3100 2
            $szValue2 = 0x0000;
3101 2
            $operand1 = pack('Cv', 0x1E, $arrConditions[0]);
3102 2
            $operand2 = null;
3103 1
        } elseif ($numConditions == 2 && ($conditional->getOperatorType() == Conditional::OPERATOR_BETWEEN)) {
3104 1
            $szValue1 = ($arrConditions[0] <= 65535 ? 3 : 0x0000);
3105 1
            $szValue2 = ($arrConditions[1] <= 65535 ? 3 : 0x0000);
3106 1
            $operand1 = pack('Cv', 0x1E, $arrConditions[0]);
3107 1
            $operand2 = pack('Cv', 0x1E, $arrConditions[1]);
3108
        } else {
3109
            $szValue1 = 0x0000;
3110
            $szValue2 = 0x0000;
3111
            $operand1 = null;
3112
            $operand2 = null;
3113
        }
3114
3115
        // $flags : Option flags
3116
        // Alignment
3117 2
        $bAlignHz = ($conditional->getStyle()->getAlignment()->getHorizontal() == null ? 1 : 0);
3118 2
        $bAlignVt = ($conditional->getStyle()->getAlignment()->getVertical() == null ? 1 : 0);
3119 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...
3120 2
        $bTxRotation = ($conditional->getStyle()->getAlignment()->getTextRotation() == null ? 1 : 0);
3121 2
        $bIndent = ($conditional->getStyle()->getAlignment()->getIndent() == 0 ? 1 : 0);
3122 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...
3123 2
        if ($bAlignHz == 0 || $bAlignVt == 0 || $bAlignWrapTx == 0 || $bTxRotation == 0 || $bIndent == 0 || $bShrinkToFit == 0) {
3124
            $bFormatAlign = 1;
3125
        } else {
3126 2
            $bFormatAlign = 0;
3127
        }
3128
        // Protection
3129 2
        $bProtLocked = ($conditional->getStyle()->getProtection()->getLocked() == null ? 1 : 0);
3130 2
        $bProtHidden = ($conditional->getStyle()->getProtection()->getHidden() == null ? 1 : 0);
3131 2
        if ($bProtLocked == 0 || $bProtHidden == 0) {
3132
            $bFormatProt = 1;
3133
        } else {
3134 2
            $bFormatProt = 0;
3135
        }
3136
        // Border
3137 2
        $bBorderLeft = ($conditional->getStyle()->getBorders()->getLeft()->getColor()->getARGB() == Color::COLOR_BLACK
3138 2
                        && $conditional->getStyle()->getBorders()->getLeft()->getBorderStyle() == Border::BORDER_NONE ? 1 : 0);
3139 2
        $bBorderRight = ($conditional->getStyle()->getBorders()->getRight()->getColor()->getARGB() == Color::COLOR_BLACK
3140 2
                        && $conditional->getStyle()->getBorders()->getRight()->getBorderStyle() == Border::BORDER_NONE ? 1 : 0);
3141 2
        $bBorderTop = ($conditional->getStyle()->getBorders()->getTop()->getColor()->getARGB() == Color::COLOR_BLACK
3142 2
                        && $conditional->getStyle()->getBorders()->getTop()->getBorderStyle() == Border::BORDER_NONE ? 1 : 0);
3143 2
        $bBorderBottom = ($conditional->getStyle()->getBorders()->getBottom()->getColor()->getARGB() == Color::COLOR_BLACK
3144 2
                        && $conditional->getStyle()->getBorders()->getBottom()->getBorderStyle() == Border::BORDER_NONE ? 1 : 0);
3145 2
        if ($bBorderLeft == 0 || $bBorderRight == 0 || $bBorderTop == 0 || $bBorderBottom == 0) {
3146
            $bFormatBorder = 1;
3147
        } else {
3148 2
            $bFormatBorder = 0;
3149
        }
3150
        // Pattern
3151 2
        $bFillStyle = ($conditional->getStyle()->getFill()->getFillType() == null ? 0 : 1);
3152 2
        $bFillColor = ($conditional->getStyle()->getFill()->getStartColor()->getARGB() == null ? 0 : 1);
3153 2
        $bFillColorBg = ($conditional->getStyle()->getFill()->getEndColor()->getARGB() == null ? 0 : 1);
3154 2
        if ($bFillStyle == 0 || $bFillColor == 0 || $bFillColorBg == 0) {
3155 2
            $bFormatFill = 1;
3156
        } else {
3157
            $bFormatFill = 0;
3158
        }
3159
        // Font
3160 2
        if ($conditional->getStyle()->getFont()->getName() != null
3161 2
            || $conditional->getStyle()->getFont()->getSize() != null
3162 2
            || $conditional->getStyle()->getFont()->getBold() != null
3163 2
            || $conditional->getStyle()->getFont()->getItalic() != null
3164 1
            || $conditional->getStyle()->getFont()->getSuperScript() != null
3165 1
            || $conditional->getStyle()->getFont()->getSubScript() != null
3166 1
            || $conditional->getStyle()->getFont()->getUnderline() != null
3167 1
            || $conditional->getStyle()->getFont()->getStrikethrough() != null
3168 2
            || $conditional->getStyle()->getFont()->getColor()->getARGB() != null) {
3169 2
            $bFormatFont = 1;
3170
        } else {
3171
            $bFormatFont = 0;
3172
        }
3173
        // Alignment
3174 2
        $flags = 0;
3175 2
        $flags |= (1 == $bAlignHz ? 0x00000001 : 0);
3176 2
        $flags |= (1 == $bAlignVt ? 0x00000002 : 0);
3177 2
        $flags |= (1 == $bAlignWrapTx ? 0x00000004 : 0);
3178 2
        $flags |= (1 == $bTxRotation ? 0x00000008 : 0);
3179
        // Justify last line flag
3180 2
        $flags |= (1 == 1 ? 0x00000010 : 0);
3181 2
        $flags |= (1 == $bIndent ? 0x00000020 : 0);
3182 2
        $flags |= (1 == $bShrinkToFit ? 0x00000040 : 0);
3183
        // Default
3184 2
        $flags |= (1 == 1 ? 0x00000080 : 0);
3185
        // Protection
3186 2
        $flags |= (1 == $bProtLocked ? 0x00000100 : 0);
3187 2
        $flags |= (1 == $bProtHidden ? 0x00000200 : 0);
3188
        // Border
3189 2
        $flags |= (1 == $bBorderLeft ? 0x00000400 : 0);
3190 2
        $flags |= (1 == $bBorderRight ? 0x00000800 : 0);
3191 2
        $flags |= (1 == $bBorderTop ? 0x00001000 : 0);
3192 2
        $flags |= (1 == $bBorderBottom ? 0x00002000 : 0);
3193 2
        $flags |= (1 == 1 ? 0x00004000 : 0); // Top left to Bottom right border
3194 2
        $flags |= (1 == 1 ? 0x00008000 : 0); // Bottom left to Top right border
3195
        // Pattern
3196 2
        $flags |= (1 == $bFillStyle ? 0x00010000 : 0);
3197 2
        $flags |= (1 == $bFillColor ? 0x00020000 : 0);
3198 2
        $flags |= (1 == $bFillColorBg ? 0x00040000 : 0);
3199 2
        $flags |= (1 == 1 ? 0x00380000 : 0);
3200
        // Font
3201 2
        $flags |= (1 == $bFormatFont ? 0x04000000 : 0);
3202
        // Alignment:
3203 2
        $flags |= (1 == $bFormatAlign ? 0x08000000 : 0);
3204
        // Border
3205 2
        $flags |= (1 == $bFormatBorder ? 0x10000000 : 0);
3206
        // Pattern
3207 2
        $flags |= (1 == $bFormatFill ? 0x20000000 : 0);
3208
        // Protection
3209 2
        $flags |= (1 == $bFormatProt ? 0x40000000 : 0);
3210
        // Text direction
3211 2
        $flags |= (1 == 0 ? 0x80000000 : 0);
3212
3213
        // Data Blocks
3214 2
        if ($bFormatFont == 1) {
3215
            // Font Name
3216 2
            if ($conditional->getStyle()->getFont()->getName() == null) {
3217 2
                $dataBlockFont = pack('VVVVVVVV', 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
3218 2
                $dataBlockFont .= pack('VVVVVVVV', 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
3219
            } else {
3220
                $dataBlockFont = StringHelper::UTF8toBIFF8UnicodeLong($conditional->getStyle()->getFont()->getName());
3221
            }
3222
            // Font Size
3223 2
            if ($conditional->getStyle()->getFont()->getSize() == null) {
3224 2
                $dataBlockFont .= pack('V', 20 * 11);
3225
            } else {
3226
                $dataBlockFont .= pack('V', 20 * $conditional->getStyle()->getFont()->getSize());
3227
            }
3228
            // Font Options
3229 2
            $dataBlockFont .= pack('V', 0);
3230
            // Font weight
3231 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...
3232 1
                $dataBlockFont .= pack('v', 0x02BC);
3233
            } else {
3234 2
                $dataBlockFont .= pack('v', 0x0190);
3235
            }
3236
            // Escapement type
3237 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...
3238
                $dataBlockFont .= pack('v', 0x02);
3239
                $fontEscapement = 0;
3240 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...
3241
                $dataBlockFont .= pack('v', 0x01);
3242
                $fontEscapement = 0;
3243
            } else {
3244 2
                $dataBlockFont .= pack('v', 0x00);
3245 2
                $fontEscapement = 1;
3246
            }
3247
            // Underline type
3248 2
            switch ($conditional->getStyle()->getFont()->getUnderline()) {
3249 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_NONE:
3250
                    $dataBlockFont .= pack('C', 0x00);
3251
                    $fontUnderline = 0;
3252
                    break;
3253 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_DOUBLE:
3254
                    $dataBlockFont .= pack('C', 0x02);
3255
                    $fontUnderline = 0;
3256
                    break;
3257 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_DOUBLEACCOUNTING:
3258
                    $dataBlockFont .= pack('C', 0x22);
3259
                    $fontUnderline = 0;
3260
                    break;
3261 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_SINGLE:
3262
                    $dataBlockFont .= pack('C', 0x01);
3263
                    $fontUnderline = 0;
3264
                    break;
3265 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_SINGLEACCOUNTING:
3266
                    $dataBlockFont .= pack('C', 0x21);
3267
                    $fontUnderline = 0;
3268
                    break;
3269
                default:
3270 2
                    $dataBlockFont .= pack('C', 0x00);
3271 2
                    $fontUnderline = 1;
3272 2
                    break;
3273
            }
3274
            // 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...
3275 2
            $dataBlockFont .= pack('vC', 0x0000, 0x00);
3276
            // Font color index
3277 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...
3278 2
                case '000000':
3279
                    $colorIdx = 0x08;
3280
                    break;
3281 2
                case 'FFFFFF':
3282
                    $colorIdx = 0x09;
3283
                    break;
3284 2
                case 'FF0000':
3285 2
                    $colorIdx = 0x0A;
3286 2
                    break;
3287 2
                case '00FF00':
3288 2
                    $colorIdx = 0x0B;
3289 2
                    break;
3290 1
                case '0000FF':
3291
                    $colorIdx = 0x0C;
3292
                    break;
3293 1
                case 'FFFF00':
3294 1
                    $colorIdx = 0x0D;
3295 1
                    break;
3296
                case 'FF00FF':
3297
                    $colorIdx = 0x0E;
3298
                    break;
3299
                case '00FFFF':
3300
                    $colorIdx = 0x0F;
3301
                    break;
3302
                case '800000':
3303
                    $colorIdx = 0x10;
3304
                    break;
3305
                case '008000':
3306
                    $colorIdx = 0x11;
3307
                    break;
3308
                case '000080':
3309
                    $colorIdx = 0x12;
3310
                    break;
3311
                case '808000':
3312
                    $colorIdx = 0x13;
3313
                    break;
3314
                case '800080':
3315
                    $colorIdx = 0x14;
3316
                    break;
3317
                case '008080':
3318
                    $colorIdx = 0x15;
3319
                    break;
3320
                case 'C0C0C0':
3321
                    $colorIdx = 0x16;
3322
                    break;
3323
                case '808080':
3324
                    $colorIdx = 0x17;
3325
                    break;
3326
                case '9999FF':
3327
                    $colorIdx = 0x18;
3328
                    break;
3329
                case '993366':
3330
                    $colorIdx = 0x19;
3331
                    break;
3332
                case 'FFFFCC':
3333
                    $colorIdx = 0x1A;
3334
                    break;
3335
                case 'CCFFFF':
3336
                    $colorIdx = 0x1B;
3337
                    break;
3338
                case '660066':
3339
                    $colorIdx = 0x1C;
3340
                    break;
3341
                case 'FF8080':
3342
                    $colorIdx = 0x1D;
3343
                    break;
3344
                case '0066CC':
3345
                    $colorIdx = 0x1E;
3346
                    break;
3347
                case 'CCCCFF':
3348
                    $colorIdx = 0x1F;
3349
                    break;
3350
                case '000080':
3351
                    $colorIdx = 0x20;
3352
                    break;
3353
                case 'FF00FF':
3354
                    $colorIdx = 0x21;
3355
                    break;
3356
                case 'FFFF00':
3357
                    $colorIdx = 0x22;
3358
                    break;
3359
                case '00FFFF':
3360
                    $colorIdx = 0x23;
3361
                    break;
3362
                case '800080':
3363
                    $colorIdx = 0x24;
3364
                    break;
3365
                case '800000':
3366
                    $colorIdx = 0x25;
3367
                    break;
3368
                case '008080':
3369
                    $colorIdx = 0x26;
3370
                    break;
3371
                case '0000FF':
3372
                    $colorIdx = 0x27;
3373
                    break;
3374
                case '00CCFF':
3375
                    $colorIdx = 0x28;
3376
                    break;
3377
                case 'CCFFFF':
3378
                    $colorIdx = 0x29;
3379
                    break;
3380
                case 'CCFFCC':
3381
                    $colorIdx = 0x2A;
3382
                    break;
3383
                case 'FFFF99':
3384
                    $colorIdx = 0x2B;
3385
                    break;
3386
                case '99CCFF':
3387
                    $colorIdx = 0x2C;
3388
                    break;
3389
                case 'FF99CC':
3390
                    $colorIdx = 0x2D;
3391
                    break;
3392
                case 'CC99FF':
3393
                    $colorIdx = 0x2E;
3394
                    break;
3395
                case 'FFCC99':
3396
                    $colorIdx = 0x2F;
3397
                    break;
3398
                case '3366FF':
3399
                    $colorIdx = 0x30;
3400
                    break;
3401
                case '33CCCC':
3402
                    $colorIdx = 0x31;
3403
                    break;
3404
                case '99CC00':
3405
                    $colorIdx = 0x32;
3406
                    break;
3407
                case 'FFCC00':
3408
                    $colorIdx = 0x33;
3409
                    break;
3410
                case 'FF9900':
3411
                    $colorIdx = 0x34;
3412
                    break;
3413
                case 'FF6600':
3414
                    $colorIdx = 0x35;
3415
                    break;
3416
                case '666699':
3417
                    $colorIdx = 0x36;
3418
                    break;
3419
                case '969696':
3420
                    $colorIdx = 0x37;
3421
                    break;
3422
                case '003366':
3423
                    $colorIdx = 0x38;
3424
                    break;
3425
                case '339966':
3426
                    $colorIdx = 0x39;
3427
                    break;
3428
                case '003300':
3429
                    $colorIdx = 0x3A;
3430
                    break;
3431
                case '333300':
3432
                    $colorIdx = 0x3B;
3433
                    break;
3434
                case '993300':
3435
                    $colorIdx = 0x3C;
3436
                    break;
3437
                case '993366':
3438
                    $colorIdx = 0x3D;
3439
                    break;
3440
                case '333399':
3441
                    $colorIdx = 0x3E;
3442
                    break;
3443
                case '333333':
3444
                    $colorIdx = 0x3F;
3445
                    break;
3446
                default:
3447
                    $colorIdx = 0x00;
3448
                    break;
3449
            }
3450 2
            $dataBlockFont .= pack('V', $colorIdx);
3451
            // 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...
3452 2
            $dataBlockFont .= pack('V', 0x00000000);
3453
            // Options flags for modified font attributes
3454 2
            $optionsFlags = 0;
3455 2
            $optionsFlagsBold = ($conditional->getStyle()->getFont()->getBold() == null ? 1 : 0);
3456 2
            $optionsFlags |= (1 == $optionsFlagsBold ? 0x00000002 : 0);
3457 2
            $optionsFlags |= (1 == 1 ? 0x00000008 : 0);
3458 2
            $optionsFlags |= (1 == 1 ? 0x00000010 : 0);
3459 2
            $optionsFlags |= (1 == 0 ? 0x00000020 : 0);
3460 2
            $optionsFlags |= (1 == 1 ? 0x00000080 : 0);
3461 2
            $dataBlockFont .= pack('V', $optionsFlags);
3462
            // Escapement type
3463 2
            $dataBlockFont .= pack('V', $fontEscapement);
3464
            // Underline type
3465 2
            $dataBlockFont .= pack('V', $fontUnderline);
3466
            // Always
3467 2
            $dataBlockFont .= pack('V', 0x00000000);
3468
            // Always
3469 2
            $dataBlockFont .= pack('V', 0x00000000);
3470
            // 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...
3471 2
            $dataBlockFont .= pack('VV', 0x00000000, 0x00000000);
3472
            // Always
3473 2
            $dataBlockFont .= pack('v', 0x0001);
3474
        }
3475 2
        if ($bFormatAlign == 1) {
3476
            $blockAlign = 0;
3477
            // Alignment and text break
3478
            switch ($conditional->getStyle()->getAlignment()->getHorizontal()) {
3479
                case Alignment::HORIZONTAL_GENERAL:
3480
                    $blockAlign = 0;
3481
                    break;
3482
                case Alignment::HORIZONTAL_LEFT:
3483
                    $blockAlign = 1;
3484
                    break;
3485
                case Alignment::HORIZONTAL_RIGHT:
3486
                    $blockAlign = 3;
3487
                    break;
3488
                case Alignment::HORIZONTAL_CENTER:
3489
                    $blockAlign = 2;
3490
                    break;
3491
                case Alignment::HORIZONTAL_CENTER_CONTINUOUS:
3492
                    $blockAlign = 6;
3493
                    break;
3494
                case Alignment::HORIZONTAL_JUSTIFY:
3495
                    $blockAlign = 5;
3496
                    break;
3497
            }
3498
            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...
3499
                $blockAlign |= 1 << 3;
3500
            } else {
3501
                $blockAlign |= 0 << 3;
3502
            }
3503
            switch ($conditional->getStyle()->getAlignment()->getVertical()) {
3504
                case Alignment::VERTICAL_BOTTOM:
3505
                    $blockAlign = 2 << 4;
3506
                    break;
3507
                case Alignment::VERTICAL_TOP:
3508
                    $blockAlign = 0 << 4;
3509
                    break;
3510
                case Alignment::VERTICAL_CENTER:
3511
                    $blockAlign = 1 << 4;
3512
                    break;
3513
                case Alignment::VERTICAL_JUSTIFY:
3514
                    $blockAlign = 3 << 4;
3515
                    break;
3516
            }
3517
            $blockAlign |= 0 << 7;
3518
3519
            // Text rotation angle
3520
            $blockRotation = $conditional->getStyle()->getAlignment()->getTextRotation();
3521
3522
            // Indentation
3523
            $blockIndent = $conditional->getStyle()->getAlignment()->getIndent();
3524
            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...
3525
                $blockIndent |= 1 << 4;
3526
            } else {
3527
                $blockIndent |= 0 << 4;
3528
            }
3529
            $blockIndent |= 0 << 6;
3530
3531
            // Relative indentation
3532
            $blockIndentRelative = 255;
3533
3534
            $dataBlockAlign = pack('CCvvv', $blockAlign, $blockRotation, $blockIndent, $blockIndentRelative, 0x0000);
3535
        }
3536 2
        if ($bFormatBorder == 1) {
3537
            $blockLineStyle = 0;
3538
            switch ($conditional->getStyle()->getBorders()->getLeft()->getBorderStyle()) {
3539
                case Border::BORDER_NONE:
3540
                    $blockLineStyle |= 0x00;
3541
                    break;
3542
                case Border::BORDER_THIN:
3543
                    $blockLineStyle |= 0x01;
3544
                    break;
3545
                case Border::BORDER_MEDIUM:
3546
                    $blockLineStyle |= 0x02;
3547
                    break;
3548
                case Border::BORDER_DASHED:
3549
                    $blockLineStyle |= 0x03;
3550
                    break;
3551
                case Border::BORDER_DOTTED:
3552
                    $blockLineStyle |= 0x04;
3553
                    break;
3554
                case Border::BORDER_THICK:
3555
                    $blockLineStyle |= 0x05;
3556
                    break;
3557
                case Border::BORDER_DOUBLE:
3558
                    $blockLineStyle |= 0x06;
3559
                    break;
3560
                case Border::BORDER_HAIR:
3561
                    $blockLineStyle |= 0x07;
3562
                    break;
3563
                case Border::BORDER_MEDIUMDASHED:
3564
                    $blockLineStyle |= 0x08;
3565
                    break;
3566
                case Border::BORDER_DASHDOT:
3567
                    $blockLineStyle |= 0x09;
3568
                    break;
3569
                case Border::BORDER_MEDIUMDASHDOT:
3570
                    $blockLineStyle |= 0x0A;
3571
                    break;
3572
                case Border::BORDER_DASHDOTDOT:
3573
                    $blockLineStyle |= 0x0B;
3574
                    break;
3575
                case Border::BORDER_MEDIUMDASHDOTDOT:
3576
                    $blockLineStyle |= 0x0C;
3577
                    break;
3578
                case Border::BORDER_SLANTDASHDOT:
3579
                    $blockLineStyle |= 0x0D;
3580
                    break;
3581
            }
3582 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...
3583
                case Border::BORDER_NONE:
3584
                    $blockLineStyle |= 0x00 << 4;
3585
                    break;
3586
                case Border::BORDER_THIN:
3587
                    $blockLineStyle |= 0x01 << 4;
3588
                    break;
3589
                case Border::BORDER_MEDIUM:
3590
                    $blockLineStyle |= 0x02 << 4;
3591
                    break;
3592
                case Border::BORDER_DASHED:
3593
                    $blockLineStyle |= 0x03 << 4;
3594
                    break;
3595
                case Border::BORDER_DOTTED:
3596
                    $blockLineStyle |= 0x04 << 4;
3597
                    break;
3598
                case Border::BORDER_THICK:
3599
                    $blockLineStyle |= 0x05 << 4;
3600
                    break;
3601
                case Border::BORDER_DOUBLE:
3602
                    $blockLineStyle |= 0x06 << 4;
3603
                    break;
3604
                case Border::BORDER_HAIR:
3605
                    $blockLineStyle |= 0x07 << 4;
3606
                    break;
3607
                case Border::BORDER_MEDIUMDASHED:
3608
                    $blockLineStyle |= 0x08 << 4;
3609
                    break;
3610
                case Border::BORDER_DASHDOT:
3611
                    $blockLineStyle |= 0x09 << 4;
3612
                    break;
3613
                case Border::BORDER_MEDIUMDASHDOT:
3614
                    $blockLineStyle |= 0x0A << 4;
3615
                    break;
3616
                case Border::BORDER_DASHDOTDOT:
3617
                    $blockLineStyle |= 0x0B << 4;
3618
                    break;
3619
                case Border::BORDER_MEDIUMDASHDOTDOT:
3620
                    $blockLineStyle |= 0x0C << 4;
3621
                    break;
3622
                case Border::BORDER_SLANTDASHDOT:
3623
                    $blockLineStyle |= 0x0D << 4;
3624
                    break;
3625
            }
3626 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...
3627
                case Border::BORDER_NONE:
3628
                    $blockLineStyle |= 0x00 << 8;
3629
                    break;
3630
                case Border::BORDER_THIN:
3631
                    $blockLineStyle |= 0x01 << 8;
3632
                    break;
3633
                case Border::BORDER_MEDIUM:
3634
                    $blockLineStyle |= 0x02 << 8;
3635
                    break;
3636
                case Border::BORDER_DASHED:
3637
                    $blockLineStyle |= 0x03 << 8;
3638
                    break;
3639
                case Border::BORDER_DOTTED:
3640
                    $blockLineStyle |= 0x04 << 8;
3641
                    break;
3642
                case Border::BORDER_THICK:
3643
                    $blockLineStyle |= 0x05 << 8;
3644
                    break;
3645
                case Border::BORDER_DOUBLE:
3646
                    $blockLineStyle |= 0x06 << 8;
3647
                    break;
3648
                case Border::BORDER_HAIR:
3649
                    $blockLineStyle |= 0x07 << 8;
3650
                    break;
3651
                case Border::BORDER_MEDIUMDASHED:
3652
                    $blockLineStyle |= 0x08 << 8;
3653
                    break;
3654
                case Border::BORDER_DASHDOT:
3655
                    $blockLineStyle |= 0x09 << 8;
3656
                    break;
3657
                case Border::BORDER_MEDIUMDASHDOT:
3658
                    $blockLineStyle |= 0x0A << 8;
3659
                    break;
3660
                case Border::BORDER_DASHDOTDOT:
3661
                    $blockLineStyle |= 0x0B << 8;
3662
                    break;
3663
                case Border::BORDER_MEDIUMDASHDOTDOT:
3664
                    $blockLineStyle |= 0x0C << 8;
3665
                    break;
3666
                case Border::BORDER_SLANTDASHDOT:
3667
                    $blockLineStyle |= 0x0D << 8;
3668
                    break;
3669
            }
3670 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...
3671
                case Border::BORDER_NONE:
3672
                    $blockLineStyle |= 0x00 << 12;
3673
                    break;
3674
                case Border::BORDER_THIN:
3675
                    $blockLineStyle |= 0x01 << 12;
3676
                    break;
3677
                case Border::BORDER_MEDIUM:
3678
                    $blockLineStyle |= 0x02 << 12;
3679
                    break;
3680
                case Border::BORDER_DASHED:
3681
                    $blockLineStyle |= 0x03 << 12;
3682
                    break;
3683
                case Border::BORDER_DOTTED:
3684
                    $blockLineStyle |= 0x04 << 12;
3685
                    break;
3686
                case Border::BORDER_THICK:
3687
                    $blockLineStyle |= 0x05 << 12;
3688
                    break;
3689
                case Border::BORDER_DOUBLE:
3690
                    $blockLineStyle |= 0x06 << 12;
3691
                    break;
3692
                case Border::BORDER_HAIR:
3693
                    $blockLineStyle |= 0x07 << 12;
3694
                    break;
3695
                case Border::BORDER_MEDIUMDASHED:
3696
                    $blockLineStyle |= 0x08 << 12;
3697
                    break;
3698
                case Border::BORDER_DASHDOT:
3699
                    $blockLineStyle |= 0x09 << 12;
3700
                    break;
3701
                case Border::BORDER_MEDIUMDASHDOT:
3702
                    $blockLineStyle |= 0x0A << 12;
3703
                    break;
3704
                case Border::BORDER_DASHDOTDOT:
3705
                    $blockLineStyle |= 0x0B << 12;
3706
                    break;
3707
                case Border::BORDER_MEDIUMDASHDOTDOT:
3708
                    $blockLineStyle |= 0x0C << 12;
3709
                    break;
3710
                case Border::BORDER_SLANTDASHDOT:
3711
                    $blockLineStyle |= 0x0D << 12;
3712
                    break;
3713
            }
3714
            //@todo writeCFRule() => $blockLineStyle => Index Color for left line
3715
            //@todo writeCFRule() => $blockLineStyle => Index Color for right line
3716
            //@todo writeCFRule() => $blockLineStyle => Top-left to bottom-right on/off
3717
            //@todo writeCFRule() => $blockLineStyle => Bottom-left to top-right on/off
3718
            $blockColor = 0;
3719
            //@todo writeCFRule() => $blockColor => Index Color for top line
3720
            //@todo writeCFRule() => $blockColor => Index Color for bottom line
3721
            //@todo writeCFRule() => $blockColor => Index Color for diagonal line
3722 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...
3723
                case Border::BORDER_NONE:
3724
                    $blockColor |= 0x00 << 21;
3725
                    break;
3726
                case Border::BORDER_THIN:
3727
                    $blockColor |= 0x01 << 21;
3728
                    break;
3729
                case Border::BORDER_MEDIUM:
3730
                    $blockColor |= 0x02 << 21;
3731
                    break;
3732
                case Border::BORDER_DASHED:
3733
                    $blockColor |= 0x03 << 21;
3734
                    break;
3735
                case Border::BORDER_DOTTED:
3736
                    $blockColor |= 0x04 << 21;
3737
                    break;
3738
                case Border::BORDER_THICK:
3739
                    $blockColor |= 0x05 << 21;
3740
                    break;
3741
                case Border::BORDER_DOUBLE:
3742
                    $blockColor |= 0x06 << 21;
3743
                    break;
3744
                case Border::BORDER_HAIR:
3745
                    $blockColor |= 0x07 << 21;
3746
                    break;
3747
                case Border::BORDER_MEDIUMDASHED:
3748
                    $blockColor |= 0x08 << 21;
3749
                    break;
3750
                case Border::BORDER_DASHDOT:
3751
                    $blockColor |= 0x09 << 21;
3752
                    break;
3753
                case Border::BORDER_MEDIUMDASHDOT:
3754
                    $blockColor |= 0x0A << 21;
3755
                    break;
3756
                case Border::BORDER_DASHDOTDOT:
3757
                    $blockColor |= 0x0B << 21;
3758
                    break;
3759
                case Border::BORDER_MEDIUMDASHDOTDOT:
3760
                    $blockColor |= 0x0C << 21;
3761
                    break;
3762
                case Border::BORDER_SLANTDASHDOT:
3763
                    $blockColor |= 0x0D << 21;
3764
                    break;
3765
            }
3766
            $dataBlockBorder = pack('vv', $blockLineStyle, $blockColor);
3767
        }
3768 2
        if ($bFormatFill == 1) {
3769
            // Fill Patern Style
3770 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...
3771 2
            switch ($conditional->getStyle()->getFill()->getFillType()) {
3772 2
                case Fill::FILL_NONE:
3773
                    $blockFillPatternStyle = 0x00;
3774
                    break;
3775 2
                case Fill::FILL_SOLID:
3776
                    $blockFillPatternStyle = 0x01;
3777
                    break;
3778 2
                case Fill::FILL_PATTERN_MEDIUMGRAY:
3779
                    $blockFillPatternStyle = 0x02;
3780
                    break;
3781 2
                case Fill::FILL_PATTERN_DARKGRAY:
3782
                    $blockFillPatternStyle = 0x03;
3783
                    break;
3784 2
                case Fill::FILL_PATTERN_LIGHTGRAY:
3785
                    $blockFillPatternStyle = 0x04;
3786
                    break;
3787 2
                case Fill::FILL_PATTERN_DARKHORIZONTAL:
3788
                    $blockFillPatternStyle = 0x05;
3789
                    break;
3790 2
                case Fill::FILL_PATTERN_DARKVERTICAL:
3791
                    $blockFillPatternStyle = 0x06;
3792
                    break;
3793 2
                case Fill::FILL_PATTERN_DARKDOWN:
3794
                    $blockFillPatternStyle = 0x07;
3795
                    break;
3796 2
                case Fill::FILL_PATTERN_DARKUP:
3797
                    $blockFillPatternStyle = 0x08;
3798
                    break;
3799 2
                case Fill::FILL_PATTERN_DARKGRID:
3800
                    $blockFillPatternStyle = 0x09;
3801
                    break;
3802 2
                case Fill::FILL_PATTERN_DARKTRELLIS:
3803
                    $blockFillPatternStyle = 0x0A;
3804
                    break;
3805 2
                case Fill::FILL_PATTERN_LIGHTHORIZONTAL:
3806
                    $blockFillPatternStyle = 0x0B;
3807
                    break;
3808 2
                case Fill::FILL_PATTERN_LIGHTVERTICAL:
3809
                    $blockFillPatternStyle = 0x0C;
3810
                    break;
3811 2
                case Fill::FILL_PATTERN_LIGHTDOWN:
3812
                    $blockFillPatternStyle = 0x0D;
3813
                    break;
3814 2
                case Fill::FILL_PATTERN_LIGHTUP:
3815
                    $blockFillPatternStyle = 0x0E;
3816
                    break;
3817 2
                case Fill::FILL_PATTERN_LIGHTGRID:
3818
                    $blockFillPatternStyle = 0x0F;
3819
                    break;
3820 2
                case Fill::FILL_PATTERN_LIGHTTRELLIS:
3821
                    $blockFillPatternStyle = 0x10;
3822
                    break;
3823 2
                case Fill::FILL_PATTERN_GRAY125:
3824
                    $blockFillPatternStyle = 0x11;
3825
                    break;
3826 2
                case Fill::FILL_PATTERN_GRAY0625:
3827
                    $blockFillPatternStyle = 0x12;
3828
                    break;
3829 2
                case Fill::FILL_GRADIENT_LINEAR:
3830
                    $blockFillPatternStyle = 0x00;
3831
                    break; // does not exist in BIFF8
3832 2
                case Fill::FILL_GRADIENT_PATH:
3833
                    $blockFillPatternStyle = 0x00;
3834
                    break; // does not exist in BIFF8
3835
                default:
3836 2
                    $blockFillPatternStyle = 0x00;
3837 2
                    break;
3838
            }
3839
            // Color
3840 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...
3841 2
                case '000000':
3842
                    $colorIdxBg = 0x08;
3843
                    break;
3844 2
                case 'FFFFFF':
3845
                    $colorIdxBg = 0x09;
3846
                    break;
3847 2
                case 'FF0000':
3848
                    $colorIdxBg = 0x0A;
3849
                    break;
3850 2
                case '00FF00':
3851
                    $colorIdxBg = 0x0B;
3852
                    break;
3853 2
                case '0000FF':
3854
                    $colorIdxBg = 0x0C;
3855
                    break;
3856 2
                case 'FFFF00':
3857
                    $colorIdxBg = 0x0D;
3858
                    break;
3859 2
                case 'FF00FF':
3860
                    $colorIdxBg = 0x0E;
3861
                    break;
3862 2
                case '00FFFF':
3863
                    $colorIdxBg = 0x0F;
3864
                    break;
3865 2
                case '800000':
3866
                    $colorIdxBg = 0x10;
3867
                    break;
3868 2
                case '008000':
3869
                    $colorIdxBg = 0x11;
3870
                    break;
3871 2
                case '000080':
3872
                    $colorIdxBg = 0x12;
3873
                    break;
3874 2
                case '808000':
3875
                    $colorIdxBg = 0x13;
3876
                    break;
3877 2
                case '800080':
3878
                    $colorIdxBg = 0x14;
3879
                    break;
3880 2
                case '008080':
3881
                    $colorIdxBg = 0x15;
3882
                    break;
3883 2
                case 'C0C0C0':
3884
                    $colorIdxBg = 0x16;
3885
                    break;
3886 2
                case '808080':
3887
                    $colorIdxBg = 0x17;
3888
                    break;
3889 2
                case '9999FF':
3890
                    $colorIdxBg = 0x18;
3891
                    break;
3892 2
                case '993366':
3893
                    $colorIdxBg = 0x19;
3894
                    break;
3895 2
                case 'FFFFCC':
3896
                    $colorIdxBg = 0x1A;
3897
                    break;
3898 2
                case 'CCFFFF':
3899
                    $colorIdxBg = 0x1B;
3900
                    break;
3901 2
                case '660066':
3902
                    $colorIdxBg = 0x1C;
3903
                    break;
3904 2
                case 'FF8080':
3905
                    $colorIdxBg = 0x1D;
3906
                    break;
3907 2
                case '0066CC':
3908
                    $colorIdxBg = 0x1E;
3909
                    break;
3910 2
                case 'CCCCFF':
3911
                    $colorIdxBg = 0x1F;
3912
                    break;
3913 2
                case '000080':
3914
                    $colorIdxBg = 0x20;
3915
                    break;
3916 2
                case 'FF00FF':
3917
                    $colorIdxBg = 0x21;
3918
                    break;
3919 2
                case 'FFFF00':
3920
                    $colorIdxBg = 0x22;
3921
                    break;
3922 2
                case '00FFFF':
3923
                    $colorIdxBg = 0x23;
3924
                    break;
3925 2
                case '800080':
3926
                    $colorIdxBg = 0x24;
3927
                    break;
3928 2
                case '800000':
3929
                    $colorIdxBg = 0x25;
3930
                    break;
3931 2
                case '008080':
3932
                    $colorIdxBg = 0x26;
3933
                    break;
3934 2
                case '0000FF':
3935
                    $colorIdxBg = 0x27;
3936
                    break;
3937 2
                case '00CCFF':
3938
                    $colorIdxBg = 0x28;
3939
                    break;
3940 2
                case 'CCFFFF':
3941
                    $colorIdxBg = 0x29;
3942
                    break;
3943 2
                case 'CCFFCC':
3944
                    $colorIdxBg = 0x2A;
3945
                    break;
3946 2
                case 'FFFF99':
3947
                    $colorIdxBg = 0x2B;
3948
                    break;
3949 2
                case '99CCFF':
3950
                    $colorIdxBg = 0x2C;
3951
                    break;
3952 2
                case 'FF99CC':
3953
                    $colorIdxBg = 0x2D;
3954
                    break;
3955 2
                case 'CC99FF':
3956
                    $colorIdxBg = 0x2E;
3957
                    break;
3958 2
                case 'FFCC99':
3959
                    $colorIdxBg = 0x2F;
3960
                    break;
3961 2
                case '3366FF':
3962
                    $colorIdxBg = 0x30;
3963
                    break;
3964 2
                case '33CCCC':
3965
                    $colorIdxBg = 0x31;
3966
                    break;
3967 2
                case '99CC00':
3968
                    $colorIdxBg = 0x32;
3969
                    break;
3970 2
                case 'FFCC00':
3971
                    $colorIdxBg = 0x33;
3972
                    break;
3973 2
                case 'FF9900':
3974
                    $colorIdxBg = 0x34;
3975
                    break;
3976 2
                case 'FF6600':
3977
                    $colorIdxBg = 0x35;
3978
                    break;
3979 2
                case '666699':
3980
                    $colorIdxBg = 0x36;
3981
                    break;
3982 2
                case '969696':
3983
                    $colorIdxBg = 0x37;
3984
                    break;
3985 2
                case '003366':
3986
                    $colorIdxBg = 0x38;
3987
                    break;
3988 2
                case '339966':
3989
                    $colorIdxBg = 0x39;
3990
                    break;
3991 2
                case '003300':
3992
                    $colorIdxBg = 0x3A;
3993
                    break;
3994 2
                case '333300':
3995
                    $colorIdxBg = 0x3B;
3996
                    break;
3997 2
                case '993300':
3998
                    $colorIdxBg = 0x3C;
3999
                    break;
4000 2
                case '993366':
4001
                    $colorIdxBg = 0x3D;
4002
                    break;
4003 2
                case '333399':
4004
                    $colorIdxBg = 0x3E;
4005
                    break;
4006 2
                case '333333':
4007
                    $colorIdxBg = 0x3F;
4008
                    break;
4009
                default:
4010 2
                          $colorIdxBg = 0x41;
4011 2
                    break;
4012
            }
4013
            // Fg Color
4014 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...
4015 2
                case '000000':
4016
                    $colorIdxFg = 0x08;
4017
                    break;
4018 2
                case 'FFFFFF':
4019
                    $colorIdxFg = 0x09;
4020
                    break;
4021 2
                case 'FF0000':
4022
                    $colorIdxFg = 0x0A;
4023
                    break;
4024 2
                case '00FF00':
4025
                    $colorIdxFg = 0x0B;
4026
                    break;
4027 2
                case '0000FF':
4028
                    $colorIdxFg = 0x0C;
4029
                    break;
4030 2
                case 'FFFF00':
4031
                    $colorIdxFg = 0x0D;
4032
                    break;
4033 2
                case 'FF00FF':
4034
                    $colorIdxFg = 0x0E;
4035
                    break;
4036 2
                case '00FFFF':
4037
                    $colorIdxFg = 0x0F;
4038
                    break;
4039 2
                case '800000':
4040
                    $colorIdxFg = 0x10;
4041
                    break;
4042 2
                case '008000':
4043
                    $colorIdxFg = 0x11;
4044
                    break;
4045 2
                case '000080':
4046
                    $colorIdxFg = 0x12;
4047
                    break;
4048 2
                case '808000':
4049
                    $colorIdxFg = 0x13;
4050
                    break;
4051 2
                case '800080':
4052
                    $colorIdxFg = 0x14;
4053
                    break;
4054 2
                case '008080':
4055
                    $colorIdxFg = 0x15;
4056
                    break;
4057 2
                case 'C0C0C0':
4058
                    $colorIdxFg = 0x16;
4059
                    break;
4060 2
                case '808080':
4061
                    $colorIdxFg = 0x17;
4062
                    break;
4063 2
                case '9999FF':
4064
                    $colorIdxFg = 0x18;
4065
                    break;
4066 2
                case '993366':
4067
                    $colorIdxFg = 0x19;
4068
                    break;
4069 2
                case 'FFFFCC':
4070
                    $colorIdxFg = 0x1A;
4071
                    break;
4072 2
                case 'CCFFFF':
4073
                    $colorIdxFg = 0x1B;
4074
                    break;
4075 2
                case '660066':
4076
                    $colorIdxFg = 0x1C;
4077
                    break;
4078 2
                case 'FF8080':
4079
                    $colorIdxFg = 0x1D;
4080
                    break;
4081 2
                case '0066CC':
4082
                    $colorIdxFg = 0x1E;
4083
                    break;
4084 2
                case 'CCCCFF':
4085
                    $colorIdxFg = 0x1F;
4086
                    break;
4087 2
                case '000080':
4088
                    $colorIdxFg = 0x20;
4089
                    break;
4090 2
                case 'FF00FF':
4091
                    $colorIdxFg = 0x21;
4092
                    break;
4093 2
                case 'FFFF00':
4094
                    $colorIdxFg = 0x22;
4095
                    break;
4096 2
                case '00FFFF':
4097
                    $colorIdxFg = 0x23;
4098
                    break;
4099 2
                case '800080':
4100
                    $colorIdxFg = 0x24;
4101
                    break;
4102 2
                case '800000':
4103
                    $colorIdxFg = 0x25;
4104
                    break;
4105 2
                case '008080':
4106
                    $colorIdxFg = 0x26;
4107
                    break;
4108 2
                case '0000FF':
4109
                    $colorIdxFg = 0x27;
4110
                    break;
4111 2
                case '00CCFF':
4112
                    $colorIdxFg = 0x28;
4113
                    break;
4114 2
                case 'CCFFFF':
4115
                    $colorIdxFg = 0x29;
4116
                    break;
4117 2
                case 'CCFFCC':
4118
                    $colorIdxFg = 0x2A;
4119
                    break;
4120 2
                case 'FFFF99':
4121
                    $colorIdxFg = 0x2B;
4122
                    break;
4123 2
                case '99CCFF':
4124
                    $colorIdxFg = 0x2C;
4125
                    break;
4126 2
                case 'FF99CC':
4127
                    $colorIdxFg = 0x2D;
4128
                    break;
4129 2
                case 'CC99FF':
4130
                    $colorIdxFg = 0x2E;
4131
                    break;
4132 2
                case 'FFCC99':
4133
                    $colorIdxFg = 0x2F;
4134
                    break;
4135 2
                case '3366FF':
4136
                    $colorIdxFg = 0x30;
4137
                    break;
4138 2
                case '33CCCC':
4139
                    $colorIdxFg = 0x31;
4140
                    break;
4141 2
                case '99CC00':
4142
                    $colorIdxFg = 0x32;
4143
                    break;
4144 2
                case 'FFCC00':
4145
                    $colorIdxFg = 0x33;
4146
                    break;
4147 2
                case 'FF9900':
4148
                    $colorIdxFg = 0x34;
4149
                    break;
4150 2
                case 'FF6600':
4151
                    $colorIdxFg = 0x35;
4152
                    break;
4153 2
                case '666699':
4154
                    $colorIdxFg = 0x36;
4155
                    break;
4156 2
                case '969696':
4157
                    $colorIdxFg = 0x37;
4158
                    break;
4159 2
                case '003366':
4160
                    $colorIdxFg = 0x38;
4161
                    break;
4162 2
                case '339966':
4163
                    $colorIdxFg = 0x39;
4164
                    break;
4165 2
                case '003300':
4166
                    $colorIdxFg = 0x3A;
4167
                    break;
4168 2
                case '333300':
4169
                    $colorIdxFg = 0x3B;
4170
                    break;
4171 2
                case '993300':
4172
                    $colorIdxFg = 0x3C;
4173
                    break;
4174 2
                case '993366':
4175
                    $colorIdxFg = 0x3D;
4176
                    break;
4177 2
                case '333399':
4178
                    $colorIdxFg = 0x3E;
4179
                    break;
4180 2
                case '333333':
4181
                    $colorIdxFg = 0x3F;
4182
                    break;
4183
                default:
4184 2
                          $colorIdxFg = 0x40;
4185 2
                    break;
4186
            }
4187 2
            $dataBlockFill = pack('v', $blockFillPatternStyle);
4188 2
            $dataBlockFill .= pack('v', $colorIdxFg | ($colorIdxBg << 7));
4189
        }
4190 2
        if ($bFormatProt == 1) {
4191
            $dataBlockProtection = 0;
4192
            if ($conditional->getStyle()->getProtection()->getLocked() == Protection::PROTECTION_PROTECTED) {
4193
                $dataBlockProtection = 1;
4194
            }
4195
            if ($conditional->getStyle()->getProtection()->getHidden() == Protection::PROTECTION_PROTECTED) {
4196
                $dataBlockProtection = 1 << 1;
4197
            }
4198
        }
4199
4200 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...
4201 2
        if ($bFormatFont == 1) { // Block Formatting : OK
4202 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...
4203
        }
4204 2
        if ($bFormatAlign == 1) {
4205
            $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...
4206
        }
4207 2
        if ($bFormatBorder == 1) {
4208
            $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...
4209
        }
4210 2
        if ($bFormatFill == 1) { // Block Formatting : OK
4211 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...
4212
        }
4213 2
        if ($bFormatProt == 1) {
4214
            $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...
4215
        }
4216 2
        if (!is_null($operand1)) {
4217 2
            $data .= $operand1;
4218
        }
4219 2
        if (!is_null($operand2)) {
4220 1
            $data .= $operand2;
4221
        }
4222 2
        $header = pack('vv', $record, strlen($data));
4223 2
        $this->append($header . $data);
4224 2
    }
4225
4226
    /**
4227
     * Write CFHeader record.
4228
     */
4229 2
    private function writeCFHeader()
4230
    {
4231 2
        $record = 0x01B0; // Record identifier
4232 2
        $length = 0x0016; // Bytes to follow
4233
4234 2
        $numColumnMin = null;
4235 2
        $numColumnMax = null;
4236 2
        $numRowMin = null;
4237 2
        $numRowMax = null;
4238 2
        $arrConditional = [];
4239 2
        foreach ($this->phpSheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) {
4240 2
            foreach ($conditionalStyles as $conditional) {
4241 2
                if ($conditional->getConditionType() == Conditional::CONDITION_EXPRESSION
4242 2
                        || $conditional->getConditionType() == Conditional::CONDITION_CELLIS) {
4243 2
                    if (!in_array($conditional->getHashCode(), $arrConditional)) {
4244 2
                        $arrConditional[] = $conditional->getHashCode();
4245
                    }
4246
                    // Cells
4247 2
                    $arrCoord = Cell::coordinateFromString($cellCoordinate);
4248 2
                    if (!is_numeric($arrCoord[0])) {
4249 2
                        $arrCoord[0] = Cell::columnIndexFromString($arrCoord[0]);
4250
                    }
4251 2
                    if (is_null($numColumnMin) || ($numColumnMin > $arrCoord[0])) {
4252 2
                        $numColumnMin = $arrCoord[0];
4253
                    }
4254 2
                    if (is_null($numColumnMax) || ($numColumnMax < $arrCoord[0])) {
4255 2
                        $numColumnMax = $arrCoord[0];
4256
                    }
4257 2
                    if (is_null($numRowMin) || ($numRowMin > $arrCoord[1])) {
4258 2
                        $numRowMin = $arrCoord[1];
4259
                    }
4260 2
                    if (is_null($numRowMax) || ($numRowMax < $arrCoord[1])) {
4261 2
                        $numRowMax = $arrCoord[1];
4262
                    }
4263
                }
4264
            }
4265
        }
4266 2
        $needRedraw = 1;
4267 2
        $cellRange = pack('vvvv', $numRowMin - 1, $numRowMax - 1, $numColumnMin - 1, $numColumnMax - 1);
4268
4269 2
        $header = pack('vv', $record, $length);
4270 2
        $data = pack('vv', count($arrConditional), $needRedraw);
4271 2
        $data .= $cellRange;
4272 2
        $data .= pack('v', 0x0001);
4273 2
        $data .= $cellRange;
4274 2
        $this->append($header . $data);
4275 2
    }
4276
}
4277