Failed Conditions
Push — develop ( 11b055...32a55a )
by Adrien
30:13
created

Worksheet::writePrintHeaders()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 10
Ratio 100 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 0
dl 10
loc 10
ccs 7
cts 7
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\Coordinate;
6
use PhpOffice\PhpSpreadsheet\Cell\DataType;
7
use PhpOffice\PhpSpreadsheet\Cell\DataValidation;
8
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
9
use PhpOffice\PhpSpreadsheet\RichText\RichText;
10
use PhpOffice\PhpSpreadsheet\RichText\Run;
11
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
12
use PhpOffice\PhpSpreadsheet\Shared\Xls;
13
use PhpOffice\PhpSpreadsheet\Style\Alignment;
14
use PhpOffice\PhpSpreadsheet\Style\Border;
15
use PhpOffice\PhpSpreadsheet\Style\Color;
16
use PhpOffice\PhpSpreadsheet\Style\Conditional;
17
use PhpOffice\PhpSpreadsheet\Style\Fill;
18
use PhpOffice\PhpSpreadsheet\Style\Protection;
19
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
20
use PhpOffice\PhpSpreadsheet\Worksheet\SheetView;
21
use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;
22
23
// Original file header of PEAR::Spreadsheet_Excel_Writer_Worksheet (used as the base for this class):
24
// -----------------------------------------------------------------------------------------
25
// /*
26
// *  Module written/ported by Xavier Noguer <[email protected]>
27
// *
28
// *  The majority of this is _NOT_ my code.  I simply ported it from the
29
// *  PERL Spreadsheet::WriteExcel module.
30
// *
31
// *  The author of the Spreadsheet::WriteExcel module is John McNamara
32
// *  <[email protected]>
33
// *
34
// *  I _DO_ maintain this code, and John McNamara has nothing to do with the
35
// *  porting of this code to PHP.  Any questions directly related to this
36
// *  class library should be directed to me.
37
// *
38
// *  License Information:
39
// *
40
// *    Spreadsheet_Excel_Writer:  A library for generating Excel Spreadsheets
41
// *    Copyright (c) 2002-2003 Xavier Noguer [email protected]
42
// *
43
// *    This library is free software; you can redistribute it and/or
44
// *    modify it under the terms of the GNU Lesser General Public
45
// *    License as published by the Free Software Foundation; either
46
// *    version 2.1 of the License, or (at your option) any later version.
47
// *
48
// *    This library is distributed in the hope that it will be useful,
49
// *    but WITHOUT ANY WARRANTY; without even the implied warranty of
50
// *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
51
// *    Lesser General Public License for more details.
52
// *
53
// *    You should have received a copy of the GNU Lesser General Public
54
// *    License along with this library; if not, write to the Free Software
55
// *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
56
// */
57
class Worksheet extends BIFFwriter
58
{
59
    /**
60
     * Formula parser.
61
     *
62
     * @var \PhpOffice\PhpSpreadsheet\Writer\Xls\Parser
63
     */
64
    private $parser;
65
66
    /**
67
     * Maximum number of characters for a string (LABEL record in BIFF5).
68
     *
69
     * @var int
70
     */
71
    private $xlsStringMaxLength;
72
73
    /**
74
     * Array containing format information for columns.
75
     *
76
     * @var array
77
     */
78
    private $columnInfo;
79
80
    /**
81
     * Array containing the selected area for the worksheet.
82
     *
83
     * @var array
84
     */
85
    private $selection;
86
87
    /**
88
     * The active pane for the worksheet.
89
     *
90
     * @var int
91
     */
92
    private $activePane;
93
94
    /**
95
     * Whether to use outline.
96
     *
97
     * @var int
98
     */
99
    private $outlineOn;
100
101
    /**
102
     * Auto outline styles.
103
     *
104
     * @var bool
105
     */
106
    private $outlineStyle;
107
108
    /**
109
     * Whether to have outline summary below.
110
     *
111
     * @var bool
112
     */
113
    private $outlineBelow;
114
115
    /**
116
     * Whether to have outline summary at the right.
117
     *
118
     * @var bool
119
     */
120
    private $outlineRight;
121
122
    /**
123
     * Reference to the total number of strings in the workbook.
124
     *
125
     * @var int
126
     */
127
    private $stringTotal;
128
129
    /**
130
     * Reference to the number of unique strings in the workbook.
131
     *
132
     * @var int
133
     */
134
    private $stringUnique;
135
136
    /**
137
     * Reference to the array containing all the unique strings in the workbook.
138
     *
139
     * @var array
140
     */
141
    private $stringTable;
142
143
    /**
144
     * Color cache.
145
     */
146
    private $colors;
147
148
    /**
149
     * Index of first used row (at least 0).
150
     *
151
     * @var int
152
     */
153
    private $firstRowIndex;
154
155
    /**
156
     * Index of last used row. (no used rows means -1).
157
     *
158
     * @var int
159
     */
160
    private $lastRowIndex;
161
162
    /**
163
     * Index of first used column (at least 0).
164
     *
165
     * @var int
166
     */
167
    private $firstColumnIndex;
168
169
    /**
170
     * Index of last used column (no used columns means -1).
171
     *
172
     * @var int
173
     */
174
    private $lastColumnIndex;
175
176
    /**
177
     * Sheet object.
178
     *
179
     * @var \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet
180
     */
181
    public $phpSheet;
182
183
    /**
184
     * Count cell style Xfs.
185
     *
186
     * @var int
187
     */
188
    private $countCellStyleXfs;
189
190
    /**
191
     * Escher object corresponding to MSODRAWING.
192
     *
193
     * @var \PhpOffice\PhpSpreadsheet\Shared\Escher
194
     */
195
    private $escher;
196
197
    /**
198
     * Array of font hashes associated to FONT records index.
199
     *
200
     * @var array
201
     */
202
    public $fontHashIndex;
203
204
    /**
205
     * @var bool
206
     */
207
    private $preCalculateFormulas;
208
209
    /**
210
     * @var int
211
     */
212
    private $printHeaders;
213
214
    /**
215
     * Constructor.
216
     *
217
     * @param int $str_total Total number of strings
218
     * @param int $str_unique Total number of unique strings
219
     * @param array &$str_table String Table
220
     * @param array &$colors Colour Table
221
     * @param Parser $parser The formula parser created for the Workbook
222
     * @param bool $preCalculateFormulas Flag indicating whether formulas should be calculated or just written
223
     * @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $phpSheet The worksheet to write
224
     */
225 39
    public function __construct(&$str_total, &$str_unique, &$str_table, &$colors, Parser $parser, $preCalculateFormulas, \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $phpSheet)
226
    {
227
        // It needs to call its parent's constructor explicitly
228 39
        parent::__construct();
229
230 39
        $this->preCalculateFormulas = $preCalculateFormulas;
231 39
        $this->stringTotal = &$str_total;
232 39
        $this->stringUnique = &$str_unique;
233 39
        $this->stringTable = &$str_table;
234 39
        $this->colors = &$colors;
235 39
        $this->parser = $parser;
236
237 39
        $this->phpSheet = $phpSheet;
238
239 39
        $this->xlsStringMaxLength = 255;
240 39
        $this->columnInfo = [];
241 39
        $this->selection = [0, 0, 0, 0];
242 39
        $this->activePane = 3;
243
244 39
        $this->printHeaders = 0;
245
246 39
        $this->outlineStyle = 0;
247 39
        $this->outlineBelow = 1;
248 39
        $this->outlineRight = 1;
249 39
        $this->outlineOn = 1;
250
251 39
        $this->fontHashIndex = [];
252
253
        // calculate values for DIMENSIONS record
254 39
        $minR = 1;
255 39
        $minC = 'A';
256
257 39
        $maxR = $this->phpSheet->getHighestRow();
258 39
        $maxC = $this->phpSheet->getHighestColumn();
259
260
        // Determine lowest and highest column and row
261 39
        $this->lastRowIndex = ($maxR > 65535) ? 65535 : $maxR;
262
263 39
        $this->firstColumnIndex = Coordinate::columnIndexFromString($minC);
264 39
        $this->lastColumnIndex = Coordinate::columnIndexFromString($maxC);
265
266
//        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...
267 39
        if ($this->lastColumnIndex > 255) {
268
            $this->lastColumnIndex = 255;
269
        }
270
271 39
        $this->countCellStyleXfs = count($phpSheet->getParent()->getCellStyleXfCollection());
272 39
    }
273
274
    /**
275
     * Add data to the beginning of the workbook (note the reverse order)
276
     * and to the end of the workbook.
277
     *
278
     * @see \PhpOffice\PhpSpreadsheet\Writer\Xls\Workbook::storeWorkbook()
279
     */
280 39
    public function close()
281
    {
282 39
        $phpSheet = $this->phpSheet;
283
284
        // Write BOF record
285 39
        $this->storeBof(0x0010);
286
287
        // Write PRINTHEADERS
288 39
        $this->writePrintHeaders();
289
290
        // Write PRINTGRIDLINES
291 39
        $this->writePrintGridlines();
292
293
        // Write GRIDSET
294 39
        $this->writeGridset();
295
296
        // Calculate column widths
297 39
        $phpSheet->calculateColumnWidths();
298
299
        // Column dimensions
300 39
        if (($defaultWidth = $phpSheet->getDefaultColumnDimension()->getWidth()) < 0) {
301 38
            $defaultWidth = \PhpOffice\PhpSpreadsheet\Shared\Font::getDefaultColumnWidthByFont($phpSheet->getParent()->getDefaultStyle()->getFont());
302
        }
303
304 39
        $columnDimensions = $phpSheet->getColumnDimensions();
305 39
        $maxCol = $this->lastColumnIndex - 1;
306 39
        for ($i = 0; $i <= $maxCol; ++$i) {
307 39
            $hidden = 0;
308 39
            $level = 0;
309 39
            $xfIndex = 15; // there are 15 cell style Xfs
310
311 39
            $width = $defaultWidth;
312
313 39
            $columnLetter = Coordinate::stringFromColumnIndex($i + 1);
314 39
            if (isset($columnDimensions[$columnLetter])) {
315 19
                $columnDimension = $columnDimensions[$columnLetter];
316 19
                if ($columnDimension->getWidth() >= 0) {
317 19
                    $width = $columnDimension->getWidth();
318
                }
319 19
                $hidden = $columnDimension->getVisible() ? 0 : 1;
320 19
                $level = $columnDimension->getOutlineLevel();
321 19
                $xfIndex = $columnDimension->getXfIndex() + 15; // there are 15 cell style Xfs
322
            }
323
324
            // Components of columnInfo:
325
            // $firstcol first column on the range
326
            // $lastcol  last column on the range
327
            // $width    width to set
328
            // $xfIndex  The optional cell style Xf index to apply to the columns
329
            // $hidden   The optional hidden atribute
330
            // $level    The optional outline level
331 39
            $this->columnInfo[] = [$i, $i, $width, $xfIndex, $hidden, $level];
332
        }
333
334
        // Write GUTS
335 39
        $this->writeGuts();
336
337
        // Write DEFAULTROWHEIGHT
338 39
        $this->writeDefaultRowHeight();
339
        // Write WSBOOL
340 39
        $this->writeWsbool();
341
        // Write horizontal and vertical page breaks
342 39
        $this->writeBreaks();
343
        // Write page header
344 39
        $this->writeHeader();
345
        // Write page footer
346 39
        $this->writeFooter();
347
        // Write page horizontal centering
348 39
        $this->writeHcenter();
349
        // Write page vertical centering
350 39
        $this->writeVcenter();
351
        // Write left margin
352 39
        $this->writeMarginLeft();
353
        // Write right margin
354 39
        $this->writeMarginRight();
355
        // Write top margin
356 39
        $this->writeMarginTop();
357
        // Write bottom margin
358 39
        $this->writeMarginBottom();
359
        // Write page setup
360 39
        $this->writeSetup();
361
        // Write sheet protection
362 39
        $this->writeProtect();
363
        // Write SCENPROTECT
364 39
        $this->writeScenProtect();
365
        // Write OBJECTPROTECT
366 39
        $this->writeObjectProtect();
367
        // Write sheet password
368 39
        $this->writePassword();
369
        // Write DEFCOLWIDTH record
370 39
        $this->writeDefcol();
371
372
        // Write the COLINFO records if they exist
373 39
        if (!empty($this->columnInfo)) {
374 39
            $colcount = count($this->columnInfo);
375 39
            for ($i = 0; $i < $colcount; ++$i) {
376 39
                $this->writeColinfo($this->columnInfo[$i]);
377
            }
378
        }
379 39
        $autoFilterRange = $phpSheet->getAutoFilter()->getRange();
380 39
        if (!empty($autoFilterRange)) {
381
            // Write AUTOFILTERINFO
382 3
            $this->writeAutoFilterInfo();
383
        }
384
385
        // Write sheet dimensions
386 39
        $this->writeDimensions();
387
388
        // Row dimensions
389 39
        foreach ($phpSheet->getRowDimensions() as $rowDimension) {
390 38
            $xfIndex = $rowDimension->getXfIndex() + 15; // there are 15 cellXfs
391 38
            $this->writeRow($rowDimension->getRowIndex() - 1, $rowDimension->getRowHeight(), $xfIndex, ($rowDimension->getVisible() ? '0' : '1'), $rowDimension->getOutlineLevel());
392
        }
393
394
        // Write Cells
395 39
        foreach ($phpSheet->getCoordinates() as $coordinate) {
396 39
            $cell = $phpSheet->getCell($coordinate);
397 39
            $row = $cell->getRow() - 1;
398 39
            $column = Coordinate::columnIndexFromString($cell->getColumn()) - 1;
399
400
            // Don't break Excel break the code!
401 39
            if ($row > 65535 || $column > 255) {
402
                throw new WriterException('Rows or columns overflow! Excel5 has limit to 65535 rows and 255 columns. Use XLSX instead.');
403
            }
404
405
            // Write cell value
406 39
            $xfIndex = $cell->getXfIndex() + 15; // there are 15 cell style Xfs
407
408 39
            $cVal = $cell->getValue();
409 39
            if ($cVal instanceof RichText) {
410 9
                $arrcRun = [];
411 9
                $str_len = StringHelper::countCharacters($cVal->getPlainText(), 'UTF-8');
412 9
                $str_pos = 0;
413 9
                $elements = $cVal->getRichTextElements();
414 9
                foreach ($elements as $element) {
415
                    // FONT Index
416 9
                    if ($element instanceof Run) {
417 9
                        $str_fontidx = $this->fontHashIndex[$element->getFont()->getHashCode()];
418
                    } else {
419 8
                        $str_fontidx = 0;
420
                    }
421 9
                    $arrcRun[] = ['strlen' => $str_pos, 'fontidx' => $str_fontidx];
422
                    // Position FROM
423 9
                    $str_pos += StringHelper::countCharacters($element->getText(), 'UTF-8');
424
                }
425 9
                $this->writeRichTextString($row, $column, $cVal->getPlainText(), $xfIndex, $arrcRun);
426
            } else {
427 38
                switch ($cell->getDatatype()) {
428 38
                    case DataType::TYPE_STRING:
429 31
                    case DataType::TYPE_NULL:
430 36
                        if ($cVal === '' || $cVal === null) {
431 19
                            $this->writeBlank($row, $column, $xfIndex);
432
                        } else {
433 34
                            $this->writeString($row, $column, $cVal, $xfIndex);
434
                        }
435
436 36
                        break;
437 26
                    case DataType::TYPE_NUMERIC:
438 23
                        $this->writeNumber($row, $column, $cVal, $xfIndex);
439
440 23
                        break;
441 18
                    case DataType::TYPE_FORMULA:
442 16
                        $calculatedValue = $this->preCalculateFormulas ?
443 16
                            $cell->getCalculatedValue() : null;
444 16
                        $this->writeFormula($row, $column, $cVal, $xfIndex, $calculatedValue);
445
446 16
                        break;
447 8
                    case DataType::TYPE_BOOL:
448 8
                        $this->writeBoolErr($row, $column, $cVal, 0, $xfIndex);
449
450 8
                        break;
451
                    case DataType::TYPE_ERROR:
452
                        $this->writeBoolErr($row, $column, self::mapErrorCode($cVal), 1, $xfIndex);
453
454 39
                        break;
455
                }
456
            }
457
        }
458
459
        // Append
460 39
        $this->writeMsoDrawing();
461
462
        // Write WINDOW2 record
463 39
        $this->writeWindow2();
464
465
        // Write PLV record
466 39
        $this->writePageLayoutView();
467
468
        // Write ZOOM record
469 39
        $this->writeZoom();
470 39
        if ($phpSheet->getFreezePane()) {
471 3
            $this->writePanes();
472
        }
473
474
        // Write SELECTION record
475 39
        $this->writeSelection();
476
477
        // Write MergedCellsTable Record
478 39
        $this->writeMergedCells();
479
480
        // Hyperlinks
481 39
        foreach ($phpSheet->getHyperLinkCollection() as $coordinate => $hyperlink) {
482 9
            list($column, $row) = Coordinate::coordinateFromString($coordinate);
483
484 9
            $url = $hyperlink->getUrl();
485
486 9
            if (strpos($url, 'sheet://') !== false) {
487
                // internal to current workbook
488 6
                $url = str_replace('sheet://', 'internal:', $url);
489 9
            } 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...
490
                // URL
491
            } else {
492
                // external (local file)
493
                $url = 'external:' . $url;
494
            }
495
496 9
            $this->writeUrl($row - 1, Coordinate::columnIndexFromString($column) - 1, $url);
497
        }
498
499 39
        $this->writeDataValidity();
500 39
        $this->writeSheetLayout();
501
502
        // Write SHEETPROTECTION record
503 39
        $this->writeSheetProtection();
504 39
        $this->writeRangeProtection();
505
506 39
        $arrConditionalStyles = $phpSheet->getConditionalStylesCollection();
507 39
        if (!empty($arrConditionalStyles)) {
508 2
            $arrConditional = [];
509
            // @todo CFRule & CFHeader
510
            // Write CFHEADER record
511 2
            $this->writeCFHeader();
512
            // Write ConditionalFormattingTable records
513 2
            foreach ($arrConditionalStyles as $cellCoordinate => $conditionalStyles) {
514 2
                foreach ($conditionalStyles as $conditional) {
515 2
                    if ($conditional->getConditionType() == Conditional::CONDITION_EXPRESSION
516 2
                        || $conditional->getConditionType() == Conditional::CONDITION_CELLIS) {
517 2
                        if (!isset($arrConditional[$conditional->getHashCode()])) {
518
                            // This hash code has been handled
519 2
                            $arrConditional[$conditional->getHashCode()] = true;
520
521
                            // Write CFRULE record
522 2
                            $this->writeCFRule($conditional);
523
                        }
524
                    }
525
                }
526
            }
527
        }
528
529 39
        $this->storeEof();
530 39
    }
531
532
    /**
533
     * Write a cell range address in BIFF8
534
     * always fixed range
535
     * See section 2.5.14 in OpenOffice.org's Documentation of the Microsoft Excel File Format.
536
     *
537
     * @param string $range E.g. 'A1' or 'A1:B6'
538
     *
539
     * @return string Binary data
540
     */
541 7
    private function writeBIFF8CellRangeAddressFixed($range)
542
    {
543 7
        $explodes = explode(':', $range);
544
545
        // extract first cell, e.g. 'A1'
546 7
        $firstCell = $explodes[0];
547
548
        // extract last cell, e.g. 'B6'
549 7
        if (count($explodes) == 1) {
550 2
            $lastCell = $firstCell;
551
        } else {
552 5
            $lastCell = $explodes[1];
553
        }
554
555 7
        $firstCellCoordinates = Coordinate::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...
556 7
        $lastCellCoordinates = Coordinate::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...
557
558 7
        return pack('vvvv', $firstCellCoordinates[1] - 1, $lastCellCoordinates[1] - 1, Coordinate::columnIndexFromString($firstCellCoordinates[0]) - 1, Coordinate::columnIndexFromString($lastCellCoordinates[0]) - 1);
559
    }
560
561
    /**
562
     * Retrieves data from memory in one chunk, or from disk in $buffer
563
     * sized chunks.
564
     *
565
     * @return string The data
566
     */
567 39
    public function getData()
568
    {
569 39
        $buffer = 4096;
570
571
        // Return data stored in memory
572 39
        if (isset($this->_data)) {
573 39
            $tmp = $this->_data;
574 39
            unset($this->_data);
575
576 39
            return $tmp;
577
        }
578
        // No data to return
579
        return false;
580
    }
581
582
    /**
583
     * Set the option to print the row and column headers on the printed page.
584
     *
585
     * @param int $print Whether to print the headers or not. Defaults to 1 (print).
586
     */
587
    public function printRowColHeaders($print = 1)
588
    {
589
        $this->printHeaders = $print;
590
    }
591
592
    /**
593
     * This method sets the properties for outlining and grouping. The defaults
594
     * correspond to Excel's defaults.
595
     *
596
     * @param bool $visible
597
     * @param bool $symbols_below
598
     * @param bool $symbols_right
599
     * @param bool $auto_style
600
     */
601
    public function setOutline($visible = true, $symbols_below = true, $symbols_right = true, $auto_style = false)
602
    {
603
        $this->outlineOn = $visible;
604
        $this->outlineBelow = $symbols_below;
605
        $this->outlineRight = $symbols_right;
606
        $this->outlineStyle = $auto_style;
607
608
        // Ensure this is a boolean vale for Window2
609
        if ($this->outlineOn) {
610
            $this->outlineOn = 1;
611
        }
612
    }
613
614
    /**
615
     * Write a double to the specified row and column (zero indexed).
616
     * An integer can be written as a double. Excel will display an
617
     * integer. $format is optional.
618
     *
619
     * Returns  0 : normal termination
620
     *         -2 : row or column out of range
621
     *
622
     * @param int $row Zero indexed row
623
     * @param int $col Zero indexed column
624
     * @param float $num The number to write
625
     * @param mixed $xfIndex The optional XF format
626
     *
627
     * @return int
628
     */
629 23
    private function writeNumber($row, $col, $num, $xfIndex)
630
    {
631 23
        $record = 0x0203; // Record identifier
632 23
        $length = 0x000E; // Number of bytes to follow
633
634 23
        $header = pack('vv', $record, $length);
635 23
        $data = pack('vvv', $row, $col, $xfIndex);
636 23
        $xl_double = pack('d', $num);
637 23
        if (self::getByteOrder()) { // if it's Big Endian
638
            $xl_double = strrev($xl_double);
639
        }
640
641 23
        $this->append($header . $data . $xl_double);
642
643 23
        return 0;
644
    }
645
646
    /**
647
     * Write a LABELSST record or a LABEL record. Which one depends on BIFF version.
648
     *
649
     * @param int $row Row index (0-based)
650
     * @param int $col Column index (0-based)
651
     * @param string $str The string
652
     * @param int $xfIndex Index to XF record
653
     */
654 34
    private function writeString($row, $col, $str, $xfIndex)
655
    {
656 34
        $this->writeLabelSst($row, $col, $str, $xfIndex);
657 34
    }
658
659
    /**
660
     * Write a LABELSST record or a LABEL record. Which one depends on BIFF version
661
     * It differs from writeString by the writing of rich text strings.
662
     *
663
     * @param int $row Row index (0-based)
664
     * @param int $col Column index (0-based)
665
     * @param string $str The string
666
     * @param int $xfIndex The XF format index for the cell
667
     * @param array $arrcRun Index to Font record and characters beginning
668
     */
669 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...
670
    {
671 9
        $record = 0x00FD; // Record identifier
672 9
        $length = 0x000A; // Bytes to follow
673 9
        $str = StringHelper::UTF8toBIFF8UnicodeShort($str, $arrcRun);
674
675
        // check if string is already present
676 9
        if (!isset($this->stringTable[$str])) {
677 9
            $this->stringTable[$str] = $this->stringUnique++;
678
        }
679 9
        ++$this->stringTotal;
680
681 9
        $header = pack('vv', $record, $length);
682 9
        $data = pack('vvvV', $row, $col, $xfIndex, $this->stringTable[$str]);
683 9
        $this->append($header . $data);
684 9
    }
685
686
    /**
687
     * Write a string to the specified row and column (zero indexed).
688
     * This is the BIFF8 version (no 255 chars limit).
689
     * $format is optional.
690
     * Returns  0 : normal termination
691
     *         -2 : row or column out of range
692
     *         -3 : long string truncated to 255 chars.
693
     *
694
     * @param int $row Zero indexed row
695
     * @param int $col Zero indexed column
696
     * @param string $str The string to write
697
     * @param mixed $xfIndex The XF format index for the cell
698
     *
699
     * @return int
700
     */
701 34 View Code Duplication
    private function writeLabelSst($row, $col, $str, $xfIndex)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
702
    {
703 34
        $record = 0x00FD; // Record identifier
704 34
        $length = 0x000A; // Bytes to follow
705
706 34
        $str = StringHelper::UTF8toBIFF8UnicodeLong($str);
707
708
        // check if string is already present
709 34
        if (!isset($this->stringTable[$str])) {
710 34
            $this->stringTable[$str] = $this->stringUnique++;
711
        }
712 34
        ++$this->stringTotal;
713
714 34
        $header = pack('vv', $record, $length);
715 34
        $data = pack('vvvV', $row, $col, $xfIndex, $this->stringTable[$str]);
716 34
        $this->append($header . $data);
717 34
    }
718
719
    /**
720
     * Write a blank cell to the specified row and column (zero indexed).
721
     * A blank cell is used to specify formatting without adding a string
722
     * or a number.
723
     *
724
     * A blank cell without a format serves no purpose. Therefore, we don't write
725
     * a BLANK record unless a format is specified.
726
     *
727
     * Returns  0 : normal termination (including no format)
728
     *         -1 : insufficient number of arguments
729
     *         -2 : row or column out of range
730
     *
731
     * @param int $row Zero indexed row
732
     * @param int $col Zero indexed column
733
     * @param mixed $xfIndex The XF format index
734
     */
735 19 View Code Duplication
    public function writeBlank($row, $col, $xfIndex)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
736
    {
737 19
        $record = 0x0201; // Record identifier
738 19
        $length = 0x0006; // Number of bytes to follow
739
740 19
        $header = pack('vv', $record, $length);
741 19
        $data = pack('vvv', $row, $col, $xfIndex);
742 19
        $this->append($header . $data);
743
744 19
        return 0;
745
    }
746
747
    /**
748
     * Write a boolean or an error type to the specified row and column (zero indexed).
749
     *
750
     * @param int $row Row index (0-based)
751
     * @param int $col Column index (0-based)
752
     * @param int $value
753
     * @param bool $isError Error or Boolean?
754
     * @param int $xfIndex
755
     */
756 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...
757
    {
758 8
        $record = 0x0205;
759 8
        $length = 8;
760
761 8
        $header = pack('vv', $record, $length);
762 8
        $data = pack('vvvCC', $row, $col, $xfIndex, $value, $isError);
763 8
        $this->append($header . $data);
764
765 8
        return 0;
766
    }
767
768
    /**
769
     * Write a formula to the specified row and column (zero indexed).
770
     * The textual representation of the formula is passed to the parser in
771
     * Parser.php which returns a packed binary string.
772
     *
773
     * Returns  0 : normal termination
774
     *         -1 : formula errors (bad formula)
775
     *         -2 : row or column out of range
776
     *
777
     * @param int $row Zero indexed row
778
     * @param int $col Zero indexed column
779
     * @param string $formula The formula text string
780
     * @param mixed $xfIndex The XF format index
781
     * @param mixed $calculatedValue Calculated value
782
     *
783
     * @return int
784
     */
785 16
    private function writeFormula($row, $col, $formula, $xfIndex, $calculatedValue)
786
    {
787 16
        $record = 0x0006; // Record identifier
788
789
        // Initialize possible additional value for STRING record that should be written after the FORMULA record?
790 16
        $stringValue = null;
791
792
        // calculated value
793 16
        if (isset($calculatedValue)) {
794
            // Since we can't yet get the data type of the calculated value,
795
            // we use best effort to determine data type
796 16
            if (is_bool($calculatedValue)) {
797
                // Boolean value
798 3
                $num = pack('CCCvCv', 0x01, 0x00, (int) $calculatedValue, 0x00, 0x00, 0xFFFF);
799 16
            } elseif (is_int($calculatedValue) || is_float($calculatedValue)) {
800
                // Numeric value
801 14
                $num = pack('d', $calculatedValue);
802 12
            } elseif (is_string($calculatedValue)) {
803 12
                $errorCodes = DataType::getErrorCodes();
804 12
                if (isset($errorCodes[$calculatedValue])) {
805
                    // Error value
806 4
                    $num = pack('CCCvCv', 0x02, 0x00, self::mapErrorCode($calculatedValue), 0x00, 0x00, 0xFFFF);
807 12
                } elseif ($calculatedValue === '') {
808
                    // 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...
809 5
                    $num = pack('CCCvCv', 0x03, 0x00, 0x00, 0x00, 0x00, 0xFFFF);
810
                } else {
811
                    // Non-empty string value (or empty string BIFF5)
812 7
                    $stringValue = $calculatedValue;
813 12
                    $num = pack('CCCvCv', 0x00, 0x00, 0x00, 0x00, 0x00, 0xFFFF);
814
                }
815
            } else {
816
                // We are really not supposed to reach here
817 16
                $num = pack('d', 0x00);
818
            }
819
        } else {
820
            $num = pack('d', 0x00);
821
        }
822
823 16
        $grbit = 0x03; // Option flags
824 16
        $unknown = 0x0000; // Must be zero
825
826
        // Strip the '=' or '@' sign at the beginning of the formula string
827 16
        if ($formula[0] == '=') {
828 16
            $formula = substr($formula, 1);
829
        } else {
830
            // Error handling
831
            $this->writeString($row, $col, 'Unrecognised character for formula');
832
833
            return -1;
834
        }
835
836
        // Parse the formula using the parser in Parser.php
837
        try {
838 16
            $error = $this->parser->parse($formula);
839 16
            $formula = $this->parser->toReversePolish();
840
841 16
            $formlen = strlen($formula); // Length of the binary string
842 16
            $length = 0x16 + $formlen; // Length of the record data
843
844 16
            $header = pack('vv', $record, $length);
845
846 16
            $data = pack('vvv', $row, $col, $xfIndex)
847 16
                        . $num
848 16
                        . pack('vVv', $grbit, $unknown, $formlen);
849 16
            $this->append($header . $data . $formula);
850
851
            // Append also a STRING record if necessary
852 16
            if ($stringValue !== null) {
853 7
                $this->writeStringRecord($stringValue);
854
            }
855
856 16
            return 0;
857 5
        } catch (PhpSpreadsheetException $e) {
858
            // do nothing
859
        }
860 5
    }
861
862
    /**
863
     * Write a STRING record. This.
864
     *
865
     * @param string $stringValue
866
     */
867 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...
868
    {
869 7
        $record = 0x0207; // Record identifier
870 7
        $data = StringHelper::UTF8toBIFF8UnicodeLong($stringValue);
871
872 7
        $length = strlen($data);
873 7
        $header = pack('vv', $record, $length);
874
875 7
        $this->append($header . $data);
876 7
    }
877
878
    /**
879
     * Write a hyperlink.
880
     * This is comprised of two elements: the visible label and
881
     * the invisible link. The visible label is the same as the link unless an
882
     * alternative string is specified. The label is written using the
883
     * writeString() method. Therefore the 255 characters string limit applies.
884
     * $string and $format are optional.
885
     *
886
     * The hyperlink can be to a http, ftp, mail, internal sheet (not yet), or external
887
     * directory url.
888
     *
889
     * Returns  0 : normal termination
890
     *         -2 : row or column out of range
891
     *         -3 : long string truncated to 255 chars
892
     *
893
     * @param int $row Row
894
     * @param int $col Column
895
     * @param string $url URL string
896
     *
897
     * @return int
898
     */
899 9
    private function writeUrl($row, $col, $url)
900
    {
901
        // Add start row and col to arg list
902 9
        return $this->writeUrlRange($row, $col, $row, $col, $url);
903
    }
904
905
    /**
906
     * This is the more general form of writeUrl(). It allows a hyperlink to be
907
     * written to a range of cells. This function also decides the type of hyperlink
908
     * to be written. These are either, Web (http, ftp, mailto), Internal
909
     * (Sheet1!A1) or external ('c:\temp\foo.xls#Sheet1!A1').
910
     *
911
     * @see writeUrl()
912
     *
913
     * @param int $row1 Start row
914
     * @param int $col1 Start column
915
     * @param int $row2 End row
916
     * @param int $col2 End column
917
     * @param string $url URL string
918
     *
919
     * @return int
920
     */
921 9
    public function writeUrlRange($row1, $col1, $row2, $col2, $url)
922
    {
923
        // Check for internal/external sheet links or default to web link
924 9
        if (preg_match('[^internal:]', $url)) {
925 6
            return $this->writeUrlInternal($row1, $col1, $row2, $col2, $url);
926
        }
927 9
        if (preg_match('[^external:]', $url)) {
928
            return $this->writeUrlExternal($row1, $col1, $row2, $col2, $url);
929
        }
930
931 9
        return $this->writeUrlWeb($row1, $col1, $row2, $col2, $url);
932
    }
933
934
    /**
935
     * Used to write http, ftp and mailto hyperlinks.
936
     * The link type ($options) is 0x03 is the same as absolute dir ref without
937
     * sheet. However it is differentiated by the $unknown2 data stream.
938
     *
939
     * @see writeUrl()
940
     *
941
     * @param int $row1 Start row
942
     * @param int $col1 Start column
943
     * @param int $row2 End row
944
     * @param int $col2 End column
945
     * @param string $url URL string
946
     *
947
     * @return int
948
     */
949 9
    public function writeUrlWeb($row1, $col1, $row2, $col2, $url)
950
    {
951 9
        $record = 0x01B8; // Record identifier
952 9
        $length = 0x00000; // Bytes to follow
953
954
        // Pack the undocumented parts of the hyperlink stream
955 9
        $unknown1 = pack('H*', 'D0C9EA79F9BACE118C8200AA004BA90B02000000');
956 9
        $unknown2 = pack('H*', 'E0C9EA79F9BACE118C8200AA004BA90B');
957
958
        // Pack the option flags
959 9
        $options = pack('V', 0x03);
960
961
        // Convert URL to a null terminated wchar string
962 9
        $url = implode("\0", preg_split("''", $url, -1, PREG_SPLIT_NO_EMPTY));
963 9
        $url = $url . "\0\0\0";
964
965
        // Pack the length of the URL
966 9
        $url_len = pack('V', strlen($url));
967
968
        // Calculate the data length
969 9
        $length = 0x34 + strlen($url);
970
971
        // Pack the header data
972 9
        $header = pack('vv', $record, $length);
973 9
        $data = pack('vvvv', $row1, $row2, $col1, $col2);
974
975
        // Write the packed data
976 9
        $this->append($header . $data . $unknown1 . $options . $unknown2 . $url_len . $url);
977
978 9
        return 0;
979
    }
980
981
    /**
982
     * Used to write internal reference hyperlinks such as "Sheet1!A1".
983
     *
984
     * @see writeUrl()
985
     *
986
     * @param int $row1 Start row
987
     * @param int $col1 Start column
988
     * @param int $row2 End row
989
     * @param int $col2 End column
990
     * @param string $url URL string
991
     *
992
     * @return int
993
     */
994 6
    public function writeUrlInternal($row1, $col1, $row2, $col2, $url)
995
    {
996 6
        $record = 0x01B8; // Record identifier
997 6
        $length = 0x00000; // Bytes to follow
998
999
        // Strip URL type
1000 6
        $url = preg_replace('/^internal:/', '', $url);
1001
1002
        // Pack the undocumented parts of the hyperlink stream
1003 6
        $unknown1 = pack('H*', 'D0C9EA79F9BACE118C8200AA004BA90B02000000');
1004
1005
        // Pack the option flags
1006 6
        $options = pack('V', 0x08);
1007
1008
        // Convert the URL type and to a null terminated wchar string
1009 6
        $url .= "\0";
1010
1011
        // character count
1012 6
        $url_len = StringHelper::countCharacters($url);
1013 6
        $url_len = pack('V', $url_len);
1014
1015 6
        $url = StringHelper::convertEncoding($url, 'UTF-16LE', 'UTF-8');
1016
1017
        // Calculate the data length
1018 6
        $length = 0x24 + strlen($url);
1019
1020
        // Pack the header data
1021 6
        $header = pack('vv', $record, $length);
1022 6
        $data = pack('vvvv', $row1, $row2, $col1, $col2);
1023
1024
        // Write the packed data
1025 6
        $this->append($header . $data . $unknown1 . $options . $url_len . $url);
1026
1027 6
        return 0;
1028
    }
1029
1030
    /**
1031
     * Write links to external directory names such as 'c:\foo.xls',
1032
     * c:\foo.xls#Sheet1!A1', '../../foo.xls'. and '../../foo.xls#Sheet1!A1'.
1033
     *
1034
     * Note: Excel writes some relative links with the $dir_long string. We ignore
1035
     * these cases for the sake of simpler code.
1036
     *
1037
     * @see writeUrl()
1038
     *
1039
     * @param int $row1 Start row
1040
     * @param int $col1 Start column
1041
     * @param int $row2 End row
1042
     * @param int $col2 End column
1043
     * @param string $url URL string
1044
     *
1045
     * @return int
1046
     */
1047
    public function writeUrlExternal($row1, $col1, $row2, $col2, $url)
1048
    {
1049
        // Network drives are different. We will handle them separately
1050
        // MS/Novell network drives and shares start with \\
1051
        if (preg_match('[^external:\\\\]', $url)) {
1052
            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...
1053
        }
1054
1055
        $record = 0x01B8; // Record identifier
1056
        $length = 0x00000; // Bytes to follow
1057
1058
        // Strip URL type and change Unix dir separator to Dos style (if needed)
1059
        //
1060
        $url = preg_replace('/^external:/', '', $url);
1061
        $url = preg_replace('/\//', '\\', $url);
1062
1063
        // Determine if the link is relative or absolute:
1064
        //   relative if link contains no dir separator, "somefile.xls"
1065
        //   relative if link starts with up-dir, "..\..\somefile.xls"
1066
        //   otherwise, absolute
1067
1068
        $absolute = 0x00; // relative path
1069
        if (preg_match('/^[A-Z]:/', $url)) {
1070
            $absolute = 0x02; // absolute path on Windows, e.g. C:\...
1071
        }
1072
        $link_type = 0x01 | $absolute;
1073
1074
        // Determine if the link contains a sheet reference and change some of the
1075
        // parameters accordingly.
1076
        // Split the dir name and sheet name (if it exists)
1077
        $dir_long = $url;
1078
        if (preg_match("/\#/", $url)) {
1079
            $link_type |= 0x08;
1080
        }
1081
1082
        // Pack the link type
1083
        $link_type = pack('V', $link_type);
1084
1085
        // Calculate the up-level dir count e.g.. (..\..\..\ == 3)
1086
        $up_count = preg_match_all("/\.\.\\\/", $dir_long, $useless);
1087
        $up_count = pack('v', $up_count);
1088
1089
        // Store the short dos dir name (null terminated)
1090
        $dir_short = preg_replace("/\.\.\\\/", '', $dir_long) . "\0";
1091
1092
        // Store the long dir name as a wchar string (non-null terminated)
1093
        $dir_long = $dir_long . "\0";
1094
1095
        // Pack the lengths of the dir strings
1096
        $dir_short_len = pack('V', strlen($dir_short));
1097
        $dir_long_len = pack('V', strlen($dir_long));
1098
        $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...
1099
1100
        // Pack the undocumented parts of the hyperlink stream
1101
        $unknown1 = pack('H*', 'D0C9EA79F9BACE118C8200AA004BA90B02000000');
1102
        $unknown2 = pack('H*', '0303000000000000C000000000000046');
1103
        $unknown3 = pack('H*', 'FFFFADDE000000000000000000000000000000000000000');
1104
        $unknown4 = pack('v', 0x03);
1105
1106
        // Pack the main data stream
1107
        $data = pack('vvvv', $row1, $row2, $col1, $col2) .
1108
                            $unknown1 .
1109
                            $link_type .
1110
                            $unknown2 .
1111
                            $up_count .
1112
                            $dir_short_len .
1113
                            $dir_short .
1114
                            $unknown3 .
1115
                            $stream_len; /*.
1116
                          $dir_long_len .
1117
                          $unknown4     .
1118
                          $dir_long     .
1119
                          $sheet_len    .
1120
                          $sheet        ;*/
1121
1122
        // Pack the header data
1123
        $length = strlen($data);
1124
        $header = pack('vv', $record, $length);
1125
1126
        // Write the packed data
1127
        $this->append($header . $data);
1128
1129
        return 0;
1130
    }
1131
1132
    /**
1133
     * This method is used to set the height and format for a row.
1134
     *
1135
     * @param int $row The row to set
1136
     * @param int $height Height we are giving to the row.
1137
     *                        Use null to set XF without setting height
1138
     * @param int $xfIndex The optional cell style Xf index to apply to the columns
1139
     * @param bool $hidden The optional hidden attribute
1140
     * @param int $level The optional outline level for row, in range [0,7]
1141
     */
1142 38
    private function writeRow($row, $height, $xfIndex, $hidden = false, $level = 0)
1143
    {
1144 38
        $record = 0x0208; // Record identifier
1145 38
        $length = 0x0010; // Number of bytes to follow
1146
1147 38
        $colMic = 0x0000; // First defined column
1148 38
        $colMac = 0x0000; // Last defined column
1149 38
        $irwMac = 0x0000; // Used by Excel to optimise loading
1150 38
        $reserved = 0x0000; // Reserved
1151 38
        $grbit = 0x0000; // Option flags
1152 38
        $ixfe = $xfIndex;
1153
1154 38
        if ($height < 0) {
1155 37
            $height = null;
1156
        }
1157
1158
        // Use writeRow($row, null, $XF) to set XF format without setting height
1159 38
        if ($height != null) {
1160 6
            $miyRw = $height * 20; // row height
1161
        } else {
1162 37
            $miyRw = 0xff; // default row height is 256
1163
        }
1164
1165
        // Set the options flags. fUnsynced is used to show that the font and row
1166
        // heights are not compatible. This is usually the case for WriteExcel.
1167
        // The collapsed flag 0x10 doesn't seem to be used to indicate that a row
1168
        // is collapsed. Instead it is used to indicate that the previous row is
1169
        // collapsed. The zero height flag, 0x20, is used to collapse a row.
1170
1171 38
        $grbit |= $level;
1172 38
        if ($hidden) {
1173 2
            $grbit |= 0x0030;
1174
        }
1175 38
        if ($height !== null) {
1176 6
            $grbit |= 0x0040; // fUnsynced
1177
        }
1178 38
        if ($xfIndex !== 0xF) {
1179
            $grbit |= 0x0080;
1180
        }
1181 38
        $grbit |= 0x0100;
1182
1183 38
        $header = pack('vv', $record, $length);
1184 38
        $data = pack('vvvvvvvv', $row, $colMic, $colMac, $miyRw, $irwMac, $reserved, $grbit, $ixfe);
1185 38
        $this->append($header . $data);
1186 38
    }
1187
1188
    /**
1189
     * Writes Excel DIMENSIONS to define the area in which there is data.
1190
     */
1191 39
    private function writeDimensions()
1192
    {
1193 39
        $record = 0x0200; // Record identifier
1194
1195 39
        $length = 0x000E;
1196 39
        $data = pack('VVvvv', $this->firstRowIndex, $this->lastRowIndex + 1, $this->firstColumnIndex, $this->lastColumnIndex + 1, 0x0000); // reserved
1197
1198 39
        $header = pack('vv', $record, $length);
1199 39
        $this->append($header . $data);
1200 39
    }
1201
1202
    /**
1203
     * Write BIFF record Window2.
1204
     */
1205 39
    private function writeWindow2()
1206
    {
1207 39
        $record = 0x023E; // Record identifier
1208 39
        $length = 0x0012;
1209
1210 39
        $grbit = 0x00B6; // Option flags
1211 39
        $rwTop = 0x0000; // Top row visible in window
1212 39
        $colLeft = 0x0000; // Leftmost column visible in window
1213
1214
        // The options flags that comprise $grbit
1215 39
        $fDspFmla = 0; // 0 - bit
1216 39
        $fDspGrid = $this->phpSheet->getShowGridlines() ? 1 : 0; // 1
1217 39
        $fDspRwCol = $this->phpSheet->getShowRowColHeaders() ? 1 : 0; // 2
1218 39
        $fFrozen = $this->phpSheet->getFreezePane() ? 1 : 0; // 3
1219 39
        $fDspZeros = 1; // 4
1220 39
        $fDefaultHdr = 1; // 5
1221 39
        $fArabic = $this->phpSheet->getRightToLeft() ? 1 : 0; // 6
1222 39
        $fDspGuts = $this->outlineOn; // 7
1223 39
        $fFrozenNoSplit = 0; // 0 - bit
1224
        // no support in PhpSpreadsheet for selected sheet, therefore sheet is only selected if it is the active sheet
1225 39
        $fSelected = ($this->phpSheet === $this->phpSheet->getParent()->getActiveSheet()) ? 1 : 0;
1226 39
        $fPaged = 1; // 2
1227 39
        $fPageBreakPreview = $this->phpSheet->getSheetView()->getView() === SheetView::SHEETVIEW_PAGE_BREAK_PREVIEW;
1228
1229 39
        $grbit = $fDspFmla;
1230 39
        $grbit |= $fDspGrid << 1;
1231 39
        $grbit |= $fDspRwCol << 2;
1232 39
        $grbit |= $fFrozen << 3;
1233 39
        $grbit |= $fDspZeros << 4;
1234 39
        $grbit |= $fDefaultHdr << 5;
1235 39
        $grbit |= $fArabic << 6;
1236 39
        $grbit |= $fDspGuts << 7;
1237 39
        $grbit |= $fFrozenNoSplit << 8;
1238 39
        $grbit |= $fSelected << 9;
1239 39
        $grbit |= $fPaged << 10;
1240 39
        $grbit |= $fPageBreakPreview << 11;
1241
1242 39
        $header = pack('vv', $record, $length);
1243 39
        $data = pack('vvv', $grbit, $rwTop, $colLeft);
1244
1245
        // 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...
1246 39
        $rgbHdr = 0x0040; // Row/column heading and gridline color index
1247 39
        $zoom_factor_page_break = ($fPageBreakPreview ? $this->phpSheet->getSheetView()->getZoomScale() : 0x0000);
1248 39
        $zoom_factor_normal = $this->phpSheet->getSheetView()->getZoomScaleNormal();
1249
1250 39
        $data .= pack('vvvvV', $rgbHdr, 0x0000, $zoom_factor_page_break, $zoom_factor_normal, 0x00000000);
1251
1252 39
        $this->append($header . $data);
1253 39
    }
1254
1255
    /**
1256
     * Write BIFF record DEFAULTROWHEIGHT.
1257
     */
1258 39
    private function writeDefaultRowHeight()
1259
    {
1260 39
        $defaultRowHeight = $this->phpSheet->getDefaultRowDimension()->getRowHeight();
1261
1262 39
        if ($defaultRowHeight < 0) {
1263 36
            return;
1264
        }
1265
1266
        // convert to twips
1267 3
        $defaultRowHeight = (int) 20 * $defaultRowHeight;
1268
1269 3
        $record = 0x0225; // Record identifier
1270 3
        $length = 0x0004; // Number of bytes to follow
1271
1272 3
        $header = pack('vv', $record, $length);
1273 3
        $data = pack('vv', 1, $defaultRowHeight);
1274 3
        $this->append($header . $data);
1275 3
    }
1276
1277
    /**
1278
     * Write BIFF record DEFCOLWIDTH if COLINFO records are in use.
1279
     */
1280 39 View Code Duplication
    private function writeDefcol()
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...
1281
    {
1282 39
        $defaultColWidth = 8;
1283
1284 39
        $record = 0x0055; // Record identifier
1285 39
        $length = 0x0002; // Number of bytes to follow
1286
1287 39
        $header = pack('vv', $record, $length);
1288 39
        $data = pack('v', $defaultColWidth);
1289 39
        $this->append($header . $data);
1290 39
    }
1291
1292
    /**
1293
     * Write BIFF record COLINFO to define column widths.
1294
     *
1295
     * Note: The SDK says the record length is 0x0B but Excel writes a 0x0C
1296
     * length record.
1297
     *
1298
     * @param array $col_array This is the only parameter received and is composed of the following:
1299
     *                0 => First formatted column,
1300
     *                1 => Last formatted column,
1301
     *                2 => Col width (8.43 is Excel default),
1302
     *                3 => The optional XF format of the column,
1303
     *                4 => Option flags.
1304
     *                5 => Optional outline level
1305
     */
1306 39
    private function writeColinfo($col_array)
1307
    {
1308 39
        if (isset($col_array[0])) {
1309 39
            $colFirst = $col_array[0];
1310
        }
1311 39
        if (isset($col_array[1])) {
1312 39
            $colLast = $col_array[1];
1313
        }
1314 39
        if (isset($col_array[2])) {
1315 39
            $coldx = $col_array[2];
1316
        } else {
1317
            $coldx = 8.43;
1318
        }
1319 39
        if (isset($col_array[3])) {
1320 39
            $xfIndex = $col_array[3];
1321
        } else {
1322
            $xfIndex = 15;
1323
        }
1324 39
        if (isset($col_array[4])) {
1325 39
            $grbit = $col_array[4];
1326
        } else {
1327
            $grbit = 0;
1328
        }
1329 39
        if (isset($col_array[5])) {
1330 39
            $level = $col_array[5];
1331
        } else {
1332
            $level = 0;
1333
        }
1334 39
        $record = 0x007D; // Record identifier
1335 39
        $length = 0x000C; // Number of bytes to follow
1336
1337 39
        $coldx *= 256; // Convert to units of 1/256 of a char
1338
1339 39
        $ixfe = $xfIndex;
1340 39
        $reserved = 0x0000; // Reserved
1341
1342 39
        $level = max(0, min($level, 7));
1343 39
        $grbit |= $level << 8;
1344
1345 39
        $header = pack('vv', $record, $length);
1346 39
        $data = pack('vvvvvv', $colFirst, $colLast, $coldx, $ixfe, $grbit, $reserved);
1347 39
        $this->append($header . $data);
1348 39
    }
1349
1350
    /**
1351
     * Write BIFF record SELECTION.
1352
     */
1353 39
    private function writeSelection()
1354
    {
1355
        // look up the selected cell range
1356 39
        $selectedCells = Coordinate::splitRange($this->phpSheet->getSelectedCells());
1357 39
        $selectedCells = $selectedCells[0];
1358 39
        if (count($selectedCells) == 2) {
1359 13
            list($first, $last) = $selectedCells;
1360
        } else {
1361 32
            $first = $selectedCells[0];
1362 32
            $last = $selectedCells[0];
1363
        }
1364
1365 39
        list($colFirst, $rwFirst) = Coordinate::coordinateFromString($first);
1366 39
        $colFirst = Coordinate::columnIndexFromString($colFirst) - 1; // base 0 column index
1367 39
        --$rwFirst; // base 0 row index
1368
1369 39
        list($colLast, $rwLast) = Coordinate::coordinateFromString($last);
1370 39
        $colLast = Coordinate::columnIndexFromString($colLast) - 1; // base 0 column index
1371 39
        --$rwLast; // base 0 row index
1372
1373
        // make sure we are not out of bounds
1374 39
        $colFirst = min($colFirst, 255);
1375 39
        $colLast = min($colLast, 255);
1376
1377 39
        $rwFirst = min($rwFirst, 65535);
1378 39
        $rwLast = min($rwLast, 65535);
1379
1380 39
        $record = 0x001D; // Record identifier
1381 39
        $length = 0x000F; // Number of bytes to follow
1382
1383 39
        $pnn = $this->activePane; // Pane position
1384 39
        $rwAct = $rwFirst; // Active row
1385 39
        $colAct = $colFirst; // Active column
1386 39
        $irefAct = 0; // Active cell ref
1387 39
        $cref = 1; // Number of refs
1388
1389 39
        if (!isset($rwLast)) {
1390
            $rwLast = $rwFirst; // Last  row in reference
1391
        }
1392 39
        if (!isset($colLast)) {
1393
            $colLast = $colFirst; // Last  col in reference
1394
        }
1395
1396
        // Swap last row/col for first row/col as necessary
1397 39
        if ($rwFirst > $rwLast) {
1398
            list($rwFirst, $rwLast) = [$rwLast, $rwFirst];
1399
        }
1400
1401 39
        if ($colFirst > $colLast) {
1402
            list($colFirst, $colLast) = [$colLast, $colFirst];
1403
        }
1404
1405 39
        $header = pack('vv', $record, $length);
1406 39
        $data = pack('CvvvvvvCC', $pnn, $rwAct, $colAct, $irefAct, $cref, $rwFirst, $rwLast, $colFirst, $colLast);
1407 39
        $this->append($header . $data);
1408 39
    }
1409
1410
    /**
1411
     * Store the MERGEDCELLS records for all ranges of merged cells.
1412
     */
1413 39
    private function writeMergedCells()
1414
    {
1415 39
        $mergeCells = $this->phpSheet->getMergeCells();
1416 39
        $countMergeCells = count($mergeCells);
1417
1418 39
        if ($countMergeCells == 0) {
1419 38
            return;
1420
        }
1421
1422
        // maximum allowed number of merged cells per record
1423 10
        $maxCountMergeCellsPerRecord = 1027;
1424
1425
        // record identifier
1426 10
        $record = 0x00E5;
1427
1428
        // counter for total number of merged cells treated so far by the writer
1429 10
        $i = 0;
1430
1431
        // counter for number of merged cells written in record currently being written
1432 10
        $j = 0;
1433
1434
        // initialize record data
1435 10
        $recordData = '';
1436
1437
        // loop through the merged cells
1438 10
        foreach ($mergeCells as $mergeCell) {
1439 10
            ++$i;
1440 10
            ++$j;
1441
1442
            // extract the row and column indexes
1443 10
            $range = Coordinate::splitRange($mergeCell);
1444 10
            list($first, $last) = $range[0];
1445 10
            list($firstColumn, $firstRow) = Coordinate::coordinateFromString($first);
1446 10
            list($lastColumn, $lastRow) = Coordinate::coordinateFromString($last);
1447
1448 10
            $recordData .= pack('vvvv', $firstRow - 1, $lastRow - 1, Coordinate::columnIndexFromString($firstColumn) - 1, Coordinate::columnIndexFromString($lastColumn) - 1);
1449
1450
            // flush record if we have reached limit for number of merged cells, or reached final merged cell
1451 10
            if ($j == $maxCountMergeCellsPerRecord or $i == $countMergeCells) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

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

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

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

Let’s take a look at a few examples:

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

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


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

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

Logical Operators are used for Control-Flow

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

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

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

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

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

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

Loading history...
1452 10
                $recordData = pack('v', $j) . $recordData;
1453 10
                $length = strlen($recordData);
1454 10
                $header = pack('vv', $record, $length);
1455 10
                $this->append($header . $recordData);
1456
1457
                // initialize for next record, if any
1458 10
                $recordData = '';
1459 10
                $j = 0;
1460
            }
1461
        }
1462 10
    }
1463
1464
    /**
1465
     * Write SHEETLAYOUT record.
1466
     */
1467 39
    private function writeSheetLayout()
1468
    {
1469 39
        if (!$this->phpSheet->isTabColorSet()) {
1470 39
            return;
1471
        }
1472
1473 5
        $recordData = pack(
1474 5
            'vvVVVvv',
1475 5
            0x0862,
1476 5
            0x0000, // unused
1477 5
            0x00000000, // unused
1478 5
            0x00000000, // unused
1479 5
            0x00000014, // size of record data
1480 5
            $this->colors[$this->phpSheet->getTabColor()->getRGB()], // color index
1481 5
            0x0000        // unused
1482
        );
1483
1484 5
        $length = strlen($recordData);
1485
1486 5
        $record = 0x0862; // Record identifier
1487 5
        $header = pack('vv', $record, $length);
1488 5
        $this->append($header . $recordData);
1489 5
    }
1490
1491
    /**
1492
     * Write SHEETPROTECTION.
1493
     */
1494 39
    private function writeSheetProtection()
1495
    {
1496
        // record identifier
1497 39
        $record = 0x0867;
1498
1499
        // prepare options
1500 39
        $options = (int) !$this->phpSheet->getProtection()->getObjects()
1501 39
                    | (int) !$this->phpSheet->getProtection()->getScenarios() << 1
1502 39
                    | (int) !$this->phpSheet->getProtection()->getFormatCells() << 2
1503 39
                    | (int) !$this->phpSheet->getProtection()->getFormatColumns() << 3
1504 39
                    | (int) !$this->phpSheet->getProtection()->getFormatRows() << 4
1505 39
                    | (int) !$this->phpSheet->getProtection()->getInsertColumns() << 5
1506 39
                    | (int) !$this->phpSheet->getProtection()->getInsertRows() << 6
1507 39
                    | (int) !$this->phpSheet->getProtection()->getInsertHyperlinks() << 7
1508 39
                    | (int) !$this->phpSheet->getProtection()->getDeleteColumns() << 8
1509 39
                    | (int) !$this->phpSheet->getProtection()->getDeleteRows() << 9
1510 39
                    | (int) !$this->phpSheet->getProtection()->getSelectLockedCells() << 10
1511 39
                    | (int) !$this->phpSheet->getProtection()->getSort() << 11
1512 39
                    | (int) !$this->phpSheet->getProtection()->getAutoFilter() << 12
1513 39
                    | (int) !$this->phpSheet->getProtection()->getPivotTables() << 13
1514 39
                    | (int) !$this->phpSheet->getProtection()->getSelectUnlockedCells() << 14;
1515
1516
        // record data
1517 39
        $recordData = pack(
1518 39
            'vVVCVVvv',
1519 39
            0x0867, // repeated record identifier
1520 39
            0x0000, // not used
1521 39
            0x0000, // not used
1522 39
            0x00, // not used
1523 39
            0x01000200, // unknown data
1524 39
            0xFFFFFFFF, // unknown data
1525 39
            $options, // options
1526 39
            0x0000 // not used
1527
        );
1528
1529 39
        $length = strlen($recordData);
1530 39
        $header = pack('vv', $record, $length);
1531
1532 39
        $this->append($header . $recordData);
1533 39
    }
1534
1535
    /**
1536
     * Write BIFF record RANGEPROTECTION.
1537
     *
1538
     * Openoffice.org's Documentaion of the Microsoft Excel File Format uses term RANGEPROTECTION for these records
1539
     * Microsoft Office Excel 97-2007 Binary File Format Specification uses term FEAT for these records
1540
     */
1541 39
    private function writeRangeProtection()
1542
    {
1543 39
        foreach ($this->phpSheet->getProtectedCells() as $range => $password) {
1544
            // number of ranges, e.g. 'A1:B3 C20:D25'
1545 5
            $cellRanges = explode(' ', $range);
1546 5
            $cref = count($cellRanges);
1547
1548 5
            $recordData = pack(
1549 5
                'vvVVvCVvVv',
1550 5
                0x0868,
1551 5
                0x00,
1552 5
                0x0000,
1553 5
                0x0000,
1554 5
                0x02,
1555 5
                0x0,
1556 5
                0x0000,
1557 5
                $cref,
1558 5
                0x0000,
1559 5
                0x00
1560
            );
1561
1562 5
            foreach ($cellRanges as $cellRange) {
1563 5
                $recordData .= $this->writeBIFF8CellRangeAddressFixed($cellRange);
1564
            }
1565
1566
            // the rgbFeat structure
1567 5
            $recordData .= pack(
1568 5
                'VV',
1569 5
                0x0000,
1570 5
                hexdec($password)
1571
            );
1572
1573 5
            $recordData .= StringHelper::UTF8toBIFF8UnicodeLong('p' . md5($recordData));
1574
1575 5
            $length = strlen($recordData);
1576
1577 5
            $record = 0x0868; // Record identifier
1578 5
            $header = pack('vv', $record, $length);
1579 5
            $this->append($header . $recordData);
1580
        }
1581 39
    }
1582
1583
    /**
1584
     * Writes the Excel BIFF PANE record.
1585
     * The panes can either be frozen or thawed (unfrozen).
1586
     * Frozen panes are specified in terms of an integer number of rows and columns.
1587
     * Thawed panes are specified in terms of Excel's units for rows and columns.
1588
     */
1589 3
    private function writePanes()
1590
    {
1591 3
        $panes = [];
1592 3
        if ($this->phpSheet->getFreezePane()) {
1593 3
            list($column, $row) = Coordinate::coordinateFromString($this->phpSheet->getFreezePane());
1594 3
            $panes[0] = Coordinate::columnIndexFromString($column) - 1;
1595 3
            $panes[1] = $row - 1;
1596
1597 3
            list($leftMostColumn, $topRow) = Coordinate::coordinateFromString($this->phpSheet->getTopLeftCell());
1598
            //Coordinates are zero-based in xls files
1599 3
            $panes[2] = $topRow - 1;
1600 3
            $panes[3] = Coordinate::columnIndexFromString($leftMostColumn) - 1;
1601
        } else {
1602
            // thaw panes
1603
            return;
1604
        }
1605
1606 3
        $y = isset($panes[0]) ? $panes[0] : null;
1607 3
        $x = isset($panes[1]) ? $panes[1] : null;
1608 3
        $rwTop = isset($panes[2]) ? $panes[2] : null;
1609 3
        $colLeft = isset($panes[3]) ? $panes[3] : null;
1610 3
        if (count($panes) > 4) { // if Active pane was received
1611
            $pnnAct = $panes[4];
1612
        } else {
1613 3
            $pnnAct = null;
1614
        }
1615 3
        $record = 0x0041; // Record identifier
1616 3
        $length = 0x000A; // Number of bytes to follow
1617
1618
        // Code specific to frozen or thawed panes.
1619 3
        if ($this->phpSheet->getFreezePane()) {
1620
            // 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...
1621 3
            if (!isset($rwTop)) {
1622
                $rwTop = $y;
1623
            }
1624 3
            if (!isset($colLeft)) {
1625 3
                $colLeft = $x;
1626
            }
1627
        } else {
1628
            // 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...
1629
            if (!isset($rwTop)) {
1630
                $rwTop = 0;
1631
            }
1632
            if (!isset($colLeft)) {
1633
                $colLeft = 0;
1634
            }
1635
1636
            // Convert Excel's row and column units to the internal units.
1637
            // The default row height is 12.75
1638
            // The default column width is 8.43
1639
            // The following slope and intersection values were interpolated.
1640
            //
1641
            $y = 20 * $y + 255;
1642
            $x = 113.879 * $x + 390;
1643
        }
1644
1645
        // Determine which pane should be active. There is also the undocumented
1646
        // option to override this should it be necessary: may be removed later.
1647
        //
1648 3
        if (!isset($pnnAct)) {
1649 3
            if ($x != 0 && $y != 0) {
1650
                $pnnAct = 0; // Bottom right
1651
            }
1652 3
            if ($x != 0 && $y == 0) {
1653 3
                $pnnAct = 1; // Top right
1654
            }
1655 3
            if ($x == 0 && $y != 0) {
1656
                $pnnAct = 2; // Bottom left
1657
            }
1658 3
            if ($x == 0 && $y == 0) {
1659
                $pnnAct = 3; // Top left
1660
            }
1661
        }
1662
1663 3
        $this->activePane = $pnnAct; // Used in writeSelection
1664
1665 3
        $header = pack('vv', $record, $length);
1666 3
        $data = pack('vvvvv', $x, $y, $rwTop, $colLeft, $pnnAct);
1667 3
        $this->append($header . $data);
1668 3
    }
1669
1670
    /**
1671
     * Store the page setup SETUP BIFF record.
1672
     */
1673 39
    private function writeSetup()
1674
    {
1675 39
        $record = 0x00A1; // Record identifier
1676 39
        $length = 0x0022; // Number of bytes to follow
1677
1678 39
        $iPaperSize = $this->phpSheet->getPageSetup()->getPaperSize(); // Paper size
1679
1680 39
        $iScale = $this->phpSheet->getPageSetup()->getScale() ?
1681 39
            $this->phpSheet->getPageSetup()->getScale() : 100; // Print scaling factor
1682
1683 39
        $iPageStart = 0x01; // Starting page number
1684 39
        $iFitWidth = (int) $this->phpSheet->getPageSetup()->getFitToWidth(); // Fit to number of pages wide
1685 39
        $iFitHeight = (int) $this->phpSheet->getPageSetup()->getFitToHeight(); // Fit to number of pages high
1686 39
        $grbit = 0x00; // Option flags
1687 39
        $iRes = 0x0258; // Print resolution
1688 39
        $iVRes = 0x0258; // Vertical print resolution
1689
1690 39
        $numHdr = $this->phpSheet->getPageMargins()->getHeader(); // Header Margin
1691
1692 39
        $numFtr = $this->phpSheet->getPageMargins()->getFooter(); // Footer Margin
1693 39
        $iCopies = 0x01; // Number of copies
1694
1695 39
        $fLeftToRight = 0x0; // Print over then down
1696
1697
        // Page orientation
1698 39
        $fLandscape = ($this->phpSheet->getPageSetup()->getOrientation() == PageSetup::ORIENTATION_LANDSCAPE) ?
1699 39
            0x0 : 0x1;
1700
1701 39
        $fNoPls = 0x0; // Setup not read from printer
1702 39
        $fNoColor = 0x0; // Print black and white
1703 39
        $fDraft = 0x0; // Print draft quality
1704 39
        $fNotes = 0x0; // Print notes
1705 39
        $fNoOrient = 0x0; // Orientation not set
1706 39
        $fUsePage = 0x0; // Use custom starting page
1707
1708 39
        $grbit = $fLeftToRight;
1709 39
        $grbit |= $fLandscape << 1;
1710 39
        $grbit |= $fNoPls << 2;
1711 39
        $grbit |= $fNoColor << 3;
1712 39
        $grbit |= $fDraft << 4;
1713 39
        $grbit |= $fNotes << 5;
1714 39
        $grbit |= $fNoOrient << 6;
1715 39
        $grbit |= $fUsePage << 7;
1716
1717 39
        $numHdr = pack('d', $numHdr);
1718 39
        $numFtr = pack('d', $numFtr);
1719 39
        if (self::getByteOrder()) { // if it's Big Endian
1720
            $numHdr = strrev($numHdr);
1721
            $numFtr = strrev($numFtr);
1722
        }
1723
1724 39
        $header = pack('vv', $record, $length);
1725 39
        $data1 = pack('vvvvvvvv', $iPaperSize, $iScale, $iPageStart, $iFitWidth, $iFitHeight, $grbit, $iRes, $iVRes);
1726 39
        $data2 = $numHdr . $numFtr;
1727 39
        $data3 = pack('v', $iCopies);
1728 39
        $this->append($header . $data1 . $data2 . $data3);
1729 39
    }
1730
1731
    /**
1732
     * Store the header caption BIFF record.
1733
     */
1734 39 View Code Duplication
    private function writeHeader()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1735
    {
1736 39
        $record = 0x0014; // Record identifier
1737
1738
        /* 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...
1739
        // need to fix character count (multibyte!)
1740
        if (strlen($this->phpSheet->getHeaderFooter()->getOddHeader()) <= 255) {
1741
            $str      = $this->phpSheet->getHeaderFooter()->getOddHeader();       // header string
1742
        } else {
1743
            $str = '';
1744
        }
1745
        */
1746
1747 39
        $recordData = StringHelper::UTF8toBIFF8UnicodeLong($this->phpSheet->getHeaderFooter()->getOddHeader());
1748 39
        $length = strlen($recordData);
1749
1750 39
        $header = pack('vv', $record, $length);
1751
1752 39
        $this->append($header . $recordData);
1753 39
    }
1754
1755
    /**
1756
     * Store the footer caption BIFF record.
1757
     */
1758 39 View Code Duplication
    private function writeFooter()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1759
    {
1760 39
        $record = 0x0015; // Record identifier
1761
1762
        /* 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...
1763
        // need to fix character count (multibyte!)
1764
        if (strlen($this->phpSheet->getHeaderFooter()->getOddFooter()) <= 255) {
1765
            $str = $this->phpSheet->getHeaderFooter()->getOddFooter();
1766
        } else {
1767
            $str = '';
1768
        }
1769
        */
1770
1771 39
        $recordData = StringHelper::UTF8toBIFF8UnicodeLong($this->phpSheet->getHeaderFooter()->getOddFooter());
1772 39
        $length = strlen($recordData);
1773
1774 39
        $header = pack('vv', $record, $length);
1775
1776 39
        $this->append($header . $recordData);
1777 39
    }
1778
1779
    /**
1780
     * Store the horizontal centering HCENTER BIFF record.
1781
     */
1782 39 View Code Duplication
    private function writeHcenter()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1783
    {
1784 39
        $record = 0x0083; // Record identifier
1785 39
        $length = 0x0002; // Bytes to follow
1786
1787 39
        $fHCenter = $this->phpSheet->getPageSetup()->getHorizontalCentered() ? 1 : 0; // Horizontal centering
1788
1789 39
        $header = pack('vv', $record, $length);
1790 39
        $data = pack('v', $fHCenter);
1791
1792 39
        $this->append($header . $data);
1793 39
    }
1794
1795
    /**
1796
     * Store the vertical centering VCENTER BIFF record.
1797
     */
1798 39 View Code Duplication
    private function writeVcenter()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1799
    {
1800 39
        $record = 0x0084; // Record identifier
1801 39
        $length = 0x0002; // Bytes to follow
1802
1803 39
        $fVCenter = $this->phpSheet->getPageSetup()->getVerticalCentered() ? 1 : 0; // Horizontal centering
1804
1805 39
        $header = pack('vv', $record, $length);
1806 39
        $data = pack('v', $fVCenter);
1807 39
        $this->append($header . $data);
1808 39
    }
1809
1810
    /**
1811
     * Store the LEFTMARGIN BIFF record.
1812
     */
1813 39 View Code Duplication
    private function writeMarginLeft()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1814
    {
1815 39
        $record = 0x0026; // Record identifier
1816 39
        $length = 0x0008; // Bytes to follow
1817
1818 39
        $margin = $this->phpSheet->getPageMargins()->getLeft(); // Margin in inches
1819
1820 39
        $header = pack('vv', $record, $length);
1821 39
        $data = pack('d', $margin);
1822 39
        if (self::getByteOrder()) { // if it's Big Endian
1823
            $data = strrev($data);
1824
        }
1825
1826 39
        $this->append($header . $data);
1827 39
    }
1828
1829
    /**
1830
     * Store the RIGHTMARGIN BIFF record.
1831
     */
1832 39 View Code Duplication
    private function writeMarginRight()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1833
    {
1834 39
        $record = 0x0027; // Record identifier
1835 39
        $length = 0x0008; // Bytes to follow
1836
1837 39
        $margin = $this->phpSheet->getPageMargins()->getRight(); // Margin in inches
1838
1839 39
        $header = pack('vv', $record, $length);
1840 39
        $data = pack('d', $margin);
1841 39
        if (self::getByteOrder()) { // if it's Big Endian
1842
            $data = strrev($data);
1843
        }
1844
1845 39
        $this->append($header . $data);
1846 39
    }
1847
1848
    /**
1849
     * Store the TOPMARGIN BIFF record.
1850
     */
1851 39 View Code Duplication
    private function writeMarginTop()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1852
    {
1853 39
        $record = 0x0028; // Record identifier
1854 39
        $length = 0x0008; // Bytes to follow
1855
1856 39
        $margin = $this->phpSheet->getPageMargins()->getTop(); // Margin in inches
1857
1858 39
        $header = pack('vv', $record, $length);
1859 39
        $data = pack('d', $margin);
1860 39
        if (self::getByteOrder()) { // if it's Big Endian
1861
            $data = strrev($data);
1862
        }
1863
1864 39
        $this->append($header . $data);
1865 39
    }
1866
1867
    /**
1868
     * Store the BOTTOMMARGIN BIFF record.
1869
     */
1870 39 View Code Duplication
    private function writeMarginBottom()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1871
    {
1872 39
        $record = 0x0029; // Record identifier
1873 39
        $length = 0x0008; // Bytes to follow
1874
1875 39
        $margin = $this->phpSheet->getPageMargins()->getBottom(); // Margin in inches
1876
1877 39
        $header = pack('vv', $record, $length);
1878 39
        $data = pack('d', $margin);
1879 39
        if (self::getByteOrder()) { // if it's Big Endian
1880
            $data = strrev($data);
1881
        }
1882
1883 39
        $this->append($header . $data);
1884 39
    }
1885
1886
    /**
1887
     * Write the PRINTHEADERS BIFF record.
1888
     */
1889 39 View Code Duplication
    private function writePrintHeaders()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1890
    {
1891 39
        $record = 0x002a; // Record identifier
1892 39
        $length = 0x0002; // Bytes to follow
1893
1894 39
        $fPrintRwCol = $this->printHeaders; // Boolean flag
1895
1896 39
        $header = pack('vv', $record, $length);
1897 39
        $data = pack('v', $fPrintRwCol);
1898 39
        $this->append($header . $data);
1899 39
    }
1900
1901
    /**
1902
     * Write the PRINTGRIDLINES BIFF record. Must be used in conjunction with the
1903
     * GRIDSET record.
1904
     */
1905 39 View Code Duplication
    private function writePrintGridlines()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1906
    {
1907 39
        $record = 0x002b; // Record identifier
1908 39
        $length = 0x0002; // Bytes to follow
1909
1910 39
        $fPrintGrid = $this->phpSheet->getPrintGridlines() ? 1 : 0; // Boolean flag
1911
1912 39
        $header = pack('vv', $record, $length);
1913 39
        $data = pack('v', $fPrintGrid);
1914 39
        $this->append($header . $data);
1915 39
    }
1916
1917
    /**
1918
     * Write the GRIDSET BIFF record. Must be used in conjunction with the
1919
     * PRINTGRIDLINES record.
1920
     */
1921 39
    private function writeGridset()
1922
    {
1923 39
        $record = 0x0082; // Record identifier
1924 39
        $length = 0x0002; // Bytes to follow
1925
1926 39
        $fGridSet = !$this->phpSheet->getPrintGridlines(); // Boolean flag
1927
1928 39
        $header = pack('vv', $record, $length);
1929 39
        $data = pack('v', $fGridSet);
1930 39
        $this->append($header . $data);
1931 39
    }
1932
1933
    /**
1934
     * Write the AUTOFILTERINFO BIFF record. This is used to configure the number of autofilter select used in the sheet.
1935
     */
1936 3
    private function writeAutoFilterInfo()
1937
    {
1938 3
        $record = 0x009D; // Record identifier
1939 3
        $length = 0x0002; // Bytes to follow
1940
1941 3
        $rangeBounds = Coordinate::rangeBoundaries($this->phpSheet->getAutoFilter()->getRange());
1942 3
        $iNumFilters = 1 + $rangeBounds[1][0] - $rangeBounds[0][0];
1943
1944 3
        $header = pack('vv', $record, $length);
1945 3
        $data = pack('v', $iNumFilters);
1946 3
        $this->append($header . $data);
1947 3
    }
1948
1949
    /**
1950
     * Write the GUTS BIFF record. This is used to configure the gutter margins
1951
     * where Excel outline symbols are displayed. The visibility of the gutters is
1952
     * controlled by a flag in WSBOOL.
1953
     *
1954
     * @see writeWsbool()
1955
     */
1956 39
    private function writeGuts()
1957
    {
1958 39
        $record = 0x0080; // Record identifier
1959 39
        $length = 0x0008; // Bytes to follow
1960
1961 39
        $dxRwGut = 0x0000; // Size of row gutter
1962 39
        $dxColGut = 0x0000; // Size of col gutter
1963
1964
        // determine maximum row outline level
1965 39
        $maxRowOutlineLevel = 0;
1966 39
        foreach ($this->phpSheet->getRowDimensions() as $rowDimension) {
1967 38
            $maxRowOutlineLevel = max($maxRowOutlineLevel, $rowDimension->getOutlineLevel());
1968
        }
1969
1970 39
        $col_level = 0;
1971
1972
        // Calculate the maximum column outline level. The equivalent calculation
1973
        // for the row outline level is carried out in writeRow().
1974 39
        $colcount = count($this->columnInfo);
1975 39
        for ($i = 0; $i < $colcount; ++$i) {
1976 39
            $col_level = max($this->columnInfo[$i][5], $col_level);
1977
        }
1978
1979
        // Set the limits for the outline levels (0 <= x <= 7).
1980 39
        $col_level = max(0, min($col_level, 7));
1981
1982
        // The displayed level is one greater than the max outline levels
1983 39
        if ($maxRowOutlineLevel) {
1984
            ++$maxRowOutlineLevel;
1985
        }
1986 39
        if ($col_level) {
1987 1
            ++$col_level;
1988
        }
1989
1990 39
        $header = pack('vv', $record, $length);
1991 39
        $data = pack('vvvv', $dxRwGut, $dxColGut, $maxRowOutlineLevel, $col_level);
1992
1993 39
        $this->append($header . $data);
1994 39
    }
1995
1996
    /**
1997
     * Write the WSBOOL BIFF record, mainly for fit-to-page. Used in conjunction
1998
     * with the SETUP record.
1999
     */
2000 39
    private function writeWsbool()
2001
    {
2002 39
        $record = 0x0081; // Record identifier
2003 39
        $length = 0x0002; // Bytes to follow
2004 39
        $grbit = 0x0000;
2005
2006
        // The only option that is of interest is the flag for fit to page. So we
2007
        // set all the options in one go.
2008
        //
2009
        // Set the option flags
2010 39
        $grbit |= 0x0001; // Auto page breaks visible
2011 39
        if ($this->outlineStyle) {
2012
            $grbit |= 0x0020; // Auto outline styles
2013
        }
2014 39
        if ($this->phpSheet->getShowSummaryBelow()) {
2015 39
            $grbit |= 0x0040; // Outline summary below
2016
        }
2017 39
        if ($this->phpSheet->getShowSummaryRight()) {
2018 39
            $grbit |= 0x0080; // Outline summary right
2019
        }
2020 39
        if ($this->phpSheet->getPageSetup()->getFitToPage()) {
2021
            $grbit |= 0x0100; // Page setup fit to page
2022
        }
2023 39
        if ($this->outlineOn) {
2024 39
            $grbit |= 0x0400; // Outline symbols displayed
2025
        }
2026
2027 39
        $header = pack('vv', $record, $length);
2028 39
        $data = pack('v', $grbit);
2029 39
        $this->append($header . $data);
2030 39
    }
2031
2032
    /**
2033
     * Write the HORIZONTALPAGEBREAKS and VERTICALPAGEBREAKS BIFF records.
2034
     */
2035 39
    private function writeBreaks()
2036
    {
2037
        // initialize
2038 39
        $vbreaks = [];
2039 39
        $hbreaks = [];
2040
2041 39
        foreach ($this->phpSheet->getBreaks() as $cell => $breakType) {
2042
            // Fetch coordinates
2043 1
            $coordinates = Coordinate::coordinateFromString($cell);
2044
2045
            // Decide what to do by the type of break
2046
            switch ($breakType) {
2047 1
                case \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet::BREAK_COLUMN:
2048
                    // Add to list of vertical breaks
2049
                    $vbreaks[] = Coordinate::columnIndexFromString($coordinates[0]) - 1;
2050
2051
                    break;
2052 1
                case \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet::BREAK_ROW:
2053
                    // Add to list of horizontal breaks
2054 1
                    $hbreaks[] = $coordinates[1];
2055
2056 1
                    break;
2057
                case \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet::BREAK_NONE:
2058
                default:
2059
                    // Nothing to do
2060 1
                    break;
2061
            }
2062
        }
2063
2064
        //horizontal page breaks
2065 39
        if (!empty($hbreaks)) {
2066
            // Sort and filter array of page breaks
2067 1
            sort($hbreaks, SORT_NUMERIC);
2068 1
            if ($hbreaks[0] == 0) { // don't use first break if it's 0
2069
                array_shift($hbreaks);
2070
            }
2071
2072 1
            $record = 0x001b; // Record identifier
2073 1
            $cbrk = count($hbreaks); // Number of page breaks
2074 1
            $length = 2 + 6 * $cbrk; // Bytes to follow
2075
2076 1
            $header = pack('vv', $record, $length);
2077 1
            $data = pack('v', $cbrk);
2078
2079
            // Append each page break
2080 1
            foreach ($hbreaks as $hbreak) {
2081 1
                $data .= pack('vvv', $hbreak, 0x0000, 0x00ff);
2082
            }
2083
2084 1
            $this->append($header . $data);
2085
        }
2086
2087
        // vertical page breaks
2088 39
        if (!empty($vbreaks)) {
2089
            // 1000 vertical pagebreaks appears to be an internal Excel 5 limit.
2090
            // It is slightly higher in Excel 97/200, approx. 1026
2091
            $vbreaks = array_slice($vbreaks, 0, 1000);
2092
2093
            // Sort and filter array of page breaks
2094
            sort($vbreaks, SORT_NUMERIC);
2095
            if ($vbreaks[0] == 0) { // don't use first break if it's 0
2096
                array_shift($vbreaks);
2097
            }
2098
2099
            $record = 0x001a; // Record identifier
2100
            $cbrk = count($vbreaks); // Number of page breaks
2101
            $length = 2 + 6 * $cbrk; // Bytes to follow
2102
2103
            $header = pack('vv', $record, $length);
2104
            $data = pack('v', $cbrk);
2105
2106
            // Append each page break
2107
            foreach ($vbreaks as $vbreak) {
2108
                $data .= pack('vvv', $vbreak, 0x0000, 0xffff);
2109
            }
2110
2111
            $this->append($header . $data);
2112
        }
2113 39
    }
2114
2115
    /**
2116
     * Set the Biff PROTECT record to indicate that the worksheet is protected.
2117
     */
2118 39 View Code Duplication
    private function writeProtect()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2119
    {
2120
        // Exit unless sheet protection has been specified
2121 39
        if (!$this->phpSheet->getProtection()->getSheet()) {
2122 37
            return;
2123
        }
2124
2125 7
        $record = 0x0012; // Record identifier
2126 7
        $length = 0x0002; // Bytes to follow
2127
2128 7
        $fLock = 1; // Worksheet is protected
2129
2130 7
        $header = pack('vv', $record, $length);
2131 7
        $data = pack('v', $fLock);
2132
2133 7
        $this->append($header . $data);
2134 7
    }
2135
2136
    /**
2137
     * Write SCENPROTECT.
2138
     */
2139 39 View Code Duplication
    private function writeScenProtect()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2140
    {
2141
        // Exit if sheet protection is not active
2142 39
        if (!$this->phpSheet->getProtection()->getSheet()) {
2143 37
            return;
2144
        }
2145
2146
        // Exit if scenarios are not protected
2147 7
        if (!$this->phpSheet->getProtection()->getScenarios()) {
2148 7
            return;
2149
        }
2150
2151
        $record = 0x00DD; // Record identifier
2152
        $length = 0x0002; // Bytes to follow
2153
2154
        $header = pack('vv', $record, $length);
2155
        $data = pack('v', 1);
2156
2157
        $this->append($header . $data);
2158
    }
2159
2160
    /**
2161
     * Write OBJECTPROTECT.
2162
     */
2163 39 View Code Duplication
    private function writeObjectProtect()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2164
    {
2165
        // Exit if sheet protection is not active
2166 39
        if (!$this->phpSheet->getProtection()->getSheet()) {
2167 37
            return;
2168
        }
2169
2170
        // Exit if objects are not protected
2171 7
        if (!$this->phpSheet->getProtection()->getObjects()) {
2172 7
            return;
2173
        }
2174
2175
        $record = 0x0063; // Record identifier
2176
        $length = 0x0002; // Bytes to follow
2177
2178
        $header = pack('vv', $record, $length);
2179
        $data = pack('v', 1);
2180
2181
        $this->append($header . $data);
2182
    }
2183
2184
    /**
2185
     * Write the worksheet PASSWORD record.
2186
     */
2187 39
    private function writePassword()
2188
    {
2189
        // Exit unless sheet protection and password have been specified
2190 39
        if (!$this->phpSheet->getProtection()->getSheet() || !$this->phpSheet->getProtection()->getPassword()) {
2191 38
            return;
2192
        }
2193
2194 1
        $record = 0x0013; // Record identifier
2195 1
        $length = 0x0002; // Bytes to follow
2196
2197 1
        $wPassword = hexdec($this->phpSheet->getProtection()->getPassword()); // Encoded password
2198
2199 1
        $header = pack('vv', $record, $length);
2200 1
        $data = pack('v', $wPassword);
2201
2202 1
        $this->append($header . $data);
2203 1
    }
2204
2205
    /**
2206
     * Insert a 24bit bitmap image in a worksheet.
2207
     *
2208
     * @param int $row The row we are going to insert the bitmap into
2209
     * @param int $col The column we are going to insert the bitmap into
2210
     * @param mixed $bitmap The bitmap filename or GD-image resource
2211
     * @param int $x the horizontal position (offset) of the image inside the cell
2212
     * @param int $y the vertical position (offset) of the image inside the cell
2213
     * @param float $scale_x The horizontal scale
2214
     * @param float $scale_y The vertical scale
2215
     */
2216
    public function insertBitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1)
2217
    {
2218
        $bitmap_array = (is_resource($bitmap) ? $this->processBitmapGd($bitmap) : $this->processBitmap($bitmap));
2219
        list($width, $height, $size, $data) = $bitmap_array;
2220
2221
        // Scale the frame of the image.
2222
        $width *= $scale_x;
2223
        $height *= $scale_y;
2224
2225
        // Calculate the vertices of the image and write the OBJ record
2226
        $this->positionImage($col, $row, $x, $y, $width, $height);
2227
2228
        // Write the IMDATA record to store the bitmap data
2229
        $record = 0x007f;
2230
        $length = 8 + $size;
2231
        $cf = 0x09;
2232
        $env = 0x01;
2233
        $lcb = $size;
2234
2235
        $header = pack('vvvvV', $record, $length, $cf, $env, $lcb);
2236
        $this->append($header . $data);
2237
    }
2238
2239
    /**
2240
     * Calculate the vertices that define the position of the image as required by
2241
     * the OBJ record.
2242
     *
2243
     *         +------------+------------+
2244
     *         |     A      |      B     |
2245
     *   +-----+------------+------------+
2246
     *   |     |(x1,y1)     |            |
2247
     *   |  1  |(A1)._______|______      |
2248
     *   |     |    |              |     |
2249
     *   |     |    |              |     |
2250
     *   +-----+----|    BITMAP    |-----+
2251
     *   |     |    |              |     |
2252
     *   |  2  |    |______________.     |
2253
     *   |     |            |        (B2)|
2254
     *   |     |            |     (x2,y2)|
2255
     *   +---- +------------+------------+
2256
     *
2257
     * Example of a bitmap that covers some of the area from cell A1 to cell B2.
2258
     *
2259
     * Based on the width and height of the bitmap we need to calculate 8 vars:
2260
     *     $col_start, $row_start, $col_end, $row_end, $x1, $y1, $x2, $y2.
2261
     * The width and height of the cells are also variable and have to be taken into
2262
     * account.
2263
     * The values of $col_start and $row_start are passed in from the calling
2264
     * function. The values of $col_end and $row_end are calculated by subtracting
2265
     * the width and height of the bitmap from the width and height of the
2266
     * underlying cells.
2267
     * The vertices are expressed as a percentage of the underlying cell width as
2268
     * follows (rhs values are in pixels):
2269
     *
2270
     *       x1 = X / W *1024
2271
     *       y1 = Y / H *256
2272
     *       x2 = (X-1) / W *1024
2273
     *       y2 = (Y-1) / H *256
2274
     *
2275
     *       Where:  X is distance from the left side of the underlying cell
2276
     *               Y is distance from the top of the underlying cell
2277
     *               W is the width of the cell
2278
     *               H is the height of the cell
2279
     * The SDK incorrectly states that the height should be expressed as a
2280
     *        percentage of 1024.
2281
     *
2282
     * @param int $col_start Col containing upper left corner of object
2283
     * @param int $row_start Row containing top left corner of object
2284
     * @param int $x1 Distance to left side of object
2285
     * @param int $y1 Distance to top of object
2286
     * @param int $width Width of image frame
2287
     * @param int $height Height of image frame
2288
     */
2289
    public function positionImage($col_start, $row_start, $x1, $y1, $width, $height)
2290
    {
2291
        // Initialise end cell to the same as the start cell
2292
        $col_end = $col_start; // Col containing lower right corner of object
2293
        $row_end = $row_start; // Row containing bottom right corner of object
2294
2295
        // Zero the specified offset if greater than the cell dimensions
2296
        if ($x1 >= Xls::sizeCol($this->phpSheet, Coordinate::stringFromColumnIndex($col_start + 1))) {
2297
            $x1 = 0;
2298
        }
2299
        if ($y1 >= Xls::sizeRow($this->phpSheet, $row_start + 1)) {
2300
            $y1 = 0;
2301
        }
2302
2303
        $width = $width + $x1 - 1;
2304
        $height = $height + $y1 - 1;
2305
2306
        // Subtract the underlying cell widths to find the end cell of the image
2307
        while ($width >= Xls::sizeCol($this->phpSheet, Coordinate::stringFromColumnIndex($col_end + 1))) {
2308
            $width -= Xls::sizeCol($this->phpSheet, Coordinate::stringFromColumnIndex($col_end + 1));
2309
            ++$col_end;
2310
        }
2311
2312
        // Subtract the underlying cell heights to find the end cell of the image
2313
        while ($height >= Xls::sizeRow($this->phpSheet, $row_end + 1)) {
2314
            $height -= Xls::sizeRow($this->phpSheet, $row_end + 1);
2315
            ++$row_end;
2316
        }
2317
2318
        // Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell
2319
        // with zero eight or width.
2320
        //
2321
        if (Xls::sizeCol($this->phpSheet, Coordinate::stringFromColumnIndex($col_start + 1)) == 0) {
2322
            return;
2323
        }
2324
        if (Xls::sizeCol($this->phpSheet, Coordinate::stringFromColumnIndex($col_end + 1)) == 0) {
2325
            return;
2326
        }
2327
        if (Xls::sizeRow($this->phpSheet, $row_start + 1) == 0) {
2328
            return;
2329
        }
2330
        if (Xls::sizeRow($this->phpSheet, $row_end + 1) == 0) {
2331
            return;
2332
        }
2333
2334
        // Convert the pixel values to the percentage value expected by Excel
2335
        $x1 = $x1 / Xls::sizeCol($this->phpSheet, Coordinate::stringFromColumnIndex($col_start + 1)) * 1024;
2336
        $y1 = $y1 / Xls::sizeRow($this->phpSheet, $row_start + 1) * 256;
2337
        $x2 = $width / Xls::sizeCol($this->phpSheet, Coordinate::stringFromColumnIndex($col_end + 1)) * 1024; // Distance to right side of object
2338
        $y2 = $height / Xls::sizeRow($this->phpSheet, $row_end + 1) * 256; // Distance to bottom of object
2339
2340
        $this->writeObjPicture($col_start, $x1, $row_start, $y1, $col_end, $x2, $row_end, $y2);
2341
    }
2342
2343
    /**
2344
     * Store the OBJ record that precedes an IMDATA record. This could be generalise
2345
     * to support other Excel objects.
2346
     *
2347
     * @param int $colL Column containing upper left corner of object
2348
     * @param int $dxL Distance from left side of cell
2349
     * @param int $rwT Row containing top left corner of object
2350
     * @param int $dyT Distance from top of cell
2351
     * @param int $colR Column containing lower right corner of object
2352
     * @param int $dxR Distance from right of cell
2353
     * @param int $rwB Row containing bottom right corner of object
2354
     * @param int $dyB Distance from bottom of cell
2355
     */
2356
    private function writeObjPicture($colL, $dxL, $rwT, $dyT, $colR, $dxR, $rwB, $dyB)
2357
    {
2358
        $record = 0x005d; // Record identifier
2359
        $length = 0x003c; // Bytes to follow
2360
2361
        $cObj = 0x0001; // Count of objects in file (set to 1)
2362
        $OT = 0x0008; // Object type. 8 = Picture
2363
        $id = 0x0001; // Object ID
2364
        $grbit = 0x0614; // Option flags
2365
2366
        $cbMacro = 0x0000; // Length of FMLA structure
2367
        $Reserved1 = 0x0000; // Reserved
2368
        $Reserved2 = 0x0000; // Reserved
2369
2370
        $icvBack = 0x09; // Background colour
2371
        $icvFore = 0x09; // Foreground colour
2372
        $fls = 0x00; // Fill pattern
2373
        $fAuto = 0x00; // Automatic fill
2374
        $icv = 0x08; // Line colour
2375
        $lns = 0xff; // Line style
2376
        $lnw = 0x01; // Line weight
2377
        $fAutoB = 0x00; // Automatic border
2378
        $frs = 0x0000; // Frame style
2379
        $cf = 0x0009; // Image format, 9 = bitmap
2380
        $Reserved3 = 0x0000; // Reserved
2381
        $cbPictFmla = 0x0000; // Length of FMLA structure
2382
        $Reserved4 = 0x0000; // Reserved
2383
        $grbit2 = 0x0001; // Option flags
2384
        $Reserved5 = 0x0000; // Reserved
2385
2386
        $header = pack('vv', $record, $length);
2387
        $data = pack('V', $cObj);
2388
        $data .= pack('v', $OT);
2389
        $data .= pack('v', $id);
2390
        $data .= pack('v', $grbit);
2391
        $data .= pack('v', $colL);
2392
        $data .= pack('v', $dxL);
2393
        $data .= pack('v', $rwT);
2394
        $data .= pack('v', $dyT);
2395
        $data .= pack('v', $colR);
2396
        $data .= pack('v', $dxR);
2397
        $data .= pack('v', $rwB);
2398
        $data .= pack('v', $dyB);
2399
        $data .= pack('v', $cbMacro);
2400
        $data .= pack('V', $Reserved1);
2401
        $data .= pack('v', $Reserved2);
2402
        $data .= pack('C', $icvBack);
2403
        $data .= pack('C', $icvFore);
2404
        $data .= pack('C', $fls);
2405
        $data .= pack('C', $fAuto);
2406
        $data .= pack('C', $icv);
2407
        $data .= pack('C', $lns);
2408
        $data .= pack('C', $lnw);
2409
        $data .= pack('C', $fAutoB);
2410
        $data .= pack('v', $frs);
2411
        $data .= pack('V', $cf);
2412
        $data .= pack('v', $Reserved3);
2413
        $data .= pack('v', $cbPictFmla);
2414
        $data .= pack('v', $Reserved4);
2415
        $data .= pack('v', $grbit2);
2416
        $data .= pack('V', $Reserved5);
2417
2418
        $this->append($header . $data);
2419
    }
2420
2421
    /**
2422
     * Convert a GD-image into the internal format.
2423
     *
2424
     * @param resource $image The image to process
2425
     *
2426
     * @return array Array with data and properties of the bitmap
2427
     */
2428
    public function processBitmapGd($image)
2429
    {
2430
        $width = imagesx($image);
2431
        $height = imagesy($image);
2432
2433
        $data = pack('Vvvvv', 0x000c, $width, $height, 0x01, 0x18);
2434
        for ($j = $height; --$j;) {
2435
            for ($i = 0; $i < $width; ++$i) {
2436
                $color = imagecolorsforindex($image, imagecolorat($image, $i, $j));
2437
                foreach (['red', 'green', 'blue'] as $key) {
2438
                    $color[$key] = $color[$key] + round((255 - $color[$key]) * $color['alpha'] / 127);
2439
                }
2440
                $data .= chr($color['blue']) . chr($color['green']) . chr($color['red']);
2441
            }
2442
            if (3 * $width % 4) {
2443
                $data .= str_repeat("\x00", 4 - 3 * $width % 4);
2444
            }
2445
        }
2446
2447
        return [$width, $height, strlen($data), $data];
2448
    }
2449
2450
    /**
2451
     * Convert a 24 bit bitmap into the modified internal format used by Windows.
2452
     * This is described in BITMAPCOREHEADER and BITMAPCOREINFO structures in the
2453
     * MSDN library.
2454
     *
2455
     * @param string $bitmap The bitmap to process
2456
     *
2457
     * @return array Array with data and properties of the bitmap
2458
     */
2459
    public function processBitmap($bitmap)
2460
    {
2461
        // Open file.
2462
        $bmp_fd = @fopen($bitmap, 'rb');
2463
        if (!$bmp_fd) {
2464
            throw new WriterException("Couldn't import $bitmap");
2465
        }
2466
2467
        // Slurp the file into a string.
2468
        $data = fread($bmp_fd, filesize($bitmap));
2469
2470
        // Check that the file is big enough to be a bitmap.
2471
        if (strlen($data) <= 0x36) {
2472
            throw new WriterException("$bitmap doesn't contain enough data.\n");
2473
        }
2474
2475
        // The first 2 bytes are used to identify the bitmap.
2476
        $identity = unpack('A2ident', $data);
2477
        if ($identity['ident'] != 'BM') {
2478
            throw new WriterException("$bitmap doesn't appear to be a valid bitmap image.\n");
2479
        }
2480
2481
        // Remove bitmap data: ID.
2482
        $data = substr($data, 2);
2483
2484
        // Read and remove the bitmap size. This is more reliable than reading
2485
        // the data size at offset 0x22.
2486
        //
2487
        $size_array = unpack('Vsa', substr($data, 0, 4));
2488
        $size = $size_array['sa'];
2489
        $data = substr($data, 4);
2490
        $size -= 0x36; // Subtract size of bitmap header.
2491
        $size += 0x0C; // Add size of BIFF header.
2492
2493
        // Remove bitmap data: reserved, offset, header length.
2494
        $data = substr($data, 12);
2495
2496
        // Read and remove the bitmap width and height. Verify the sizes.
2497
        $width_and_height = unpack('V2', substr($data, 0, 8));
2498
        $width = $width_and_height[1];
2499
        $height = $width_and_height[2];
2500
        $data = substr($data, 8);
2501
        if ($width > 0xFFFF) {
2502
            throw new WriterException("$bitmap: largest image width supported is 65k.\n");
2503
        }
2504
        if ($height > 0xFFFF) {
2505
            throw new WriterException("$bitmap: largest image height supported is 65k.\n");
2506
        }
2507
2508
        // Read and remove the bitmap planes and bpp data. Verify them.
2509
        $planes_and_bitcount = unpack('v2', substr($data, 0, 4));
2510
        $data = substr($data, 4);
2511
        if ($planes_and_bitcount[2] != 24) { // Bitcount
2512
            throw new WriterException("$bitmap isn't a 24bit true color bitmap.\n");
2513
        }
2514
        if ($planes_and_bitcount[1] != 1) {
2515
            throw new WriterException("$bitmap: only 1 plane supported in bitmap image.\n");
2516
        }
2517
2518
        // Read and remove the bitmap compression. Verify compression.
2519
        $compression = unpack('Vcomp', substr($data, 0, 4));
2520
        $data = substr($data, 4);
2521
2522
        if ($compression['comp'] != 0) {
2523
            throw new WriterException("$bitmap: compression not supported in bitmap image.\n");
2524
        }
2525
2526
        // Remove bitmap data: data size, hres, vres, colours, imp. colours.
2527
        $data = substr($data, 20);
2528
2529
        // Add the BITMAPCOREHEADER data
2530
        $header = pack('Vvvvv', 0x000c, $width, $height, 0x01, 0x18);
2531
        $data = $header . $data;
2532
2533
        return [$width, $height, $size, $data];
2534
    }
2535
2536
    /**
2537
     * Store the window zoom factor. This should be a reduced fraction but for
2538
     * simplicity we will store all fractions with a numerator of 100.
2539
     */
2540 39 View Code Duplication
    private function writeZoom()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2541
    {
2542
        // If scale is 100 we don't need to write a record
2543 39
        if ($this->phpSheet->getSheetView()->getZoomScale() == 100) {
2544 39
            return;
2545
        }
2546
2547
        $record = 0x00A0; // Record identifier
2548
        $length = 0x0004; // Bytes to follow
2549
2550
        $header = pack('vv', $record, $length);
2551
        $data = pack('vv', $this->phpSheet->getSheetView()->getZoomScale(), 100);
2552
        $this->append($header . $data);
2553
    }
2554
2555
    /**
2556
     * Get Escher object.
2557
     *
2558
     * @return \PhpOffice\PhpSpreadsheet\Shared\Escher
2559
     */
2560
    public function getEscher()
2561
    {
2562
        return $this->escher;
2563
    }
2564
2565
    /**
2566
     * Set Escher object.
2567
     *
2568
     * @param \PhpOffice\PhpSpreadsheet\Shared\Escher $pValue
2569
     */
2570 10
    public function setEscher(\PhpOffice\PhpSpreadsheet\Shared\Escher $pValue = null)
2571
    {
2572 10
        $this->escher = $pValue;
2573 10
    }
2574
2575
    /**
2576
     * Write MSODRAWING record.
2577
     */
2578 39
    private function writeMsoDrawing()
2579
    {
2580
        // write the Escher stream if necessary
2581 39
        if (isset($this->escher)) {
2582 10
            $writer = new Escher($this->escher);
2583 10
            $data = $writer->close();
2584 10
            $spOffsets = $writer->getSpOffsets();
2585 10
            $spTypes = $writer->getSpTypes();
2586
            // write the neccesary MSODRAWING, OBJ records
2587
2588
            // split the Escher stream
2589 10
            $spOffsets[0] = 0;
2590 10
            $nm = count($spOffsets) - 1; // number of shapes excluding first shape
2591 10
            for ($i = 1; $i <= $nm; ++$i) {
2592
                // MSODRAWING record
2593 10
                $record = 0x00EC; // Record identifier
2594
2595
                // chunk of Escher stream for one shape
2596 10
                $dataChunk = substr($data, $spOffsets[$i - 1], $spOffsets[$i] - $spOffsets[$i - 1]);
2597
2598 10
                $length = strlen($dataChunk);
2599 10
                $header = pack('vv', $record, $length);
2600
2601 10
                $this->append($header . $dataChunk);
2602
2603
                // OBJ record
2604 10
                $record = 0x005D; // record identifier
2605 10
                $objData = '';
2606
2607
                // ftCmo
2608 10
                if ($spTypes[$i] == 0x00C9) {
2609
                    // Add ftCmo (common object data) subobject
2610
                    $objData .=
2611 3
                        pack(
2612 3
                            'vvvvvVVV',
2613 3
                            0x0015, // 0x0015 = ftCmo
2614 3
                            0x0012, // length of ftCmo data
2615 3
                            0x0014, // object type, 0x0014 = filter
2616 3
                            $i, // object id number, Excel seems to use 1-based index, local for the sheet
2617 3
                            0x2101, // option flags, 0x2001 is what OpenOffice.org uses
2618 3
                            0, // reserved
2619 3
                            0, // reserved
2620 3
                            0  // reserved
2621
                        );
2622
2623
                    // Add ftSbs Scroll bar subobject
2624 3
                    $objData .= pack('vv', 0x00C, 0x0014);
2625 3
                    $objData .= pack('H*', '0000000000000000640001000A00000010000100');
2626
                    // Add ftLbsData (List box data) subobject
2627 3
                    $objData .= pack('vv', 0x0013, 0x1FEE);
2628 3
                    $objData .= pack('H*', '00000000010001030000020008005700');
2629
                } else {
2630
                    // Add ftCmo (common object data) subobject
2631
                    $objData .=
2632 7
                        pack(
2633 7
                            'vvvvvVVV',
2634 7
                            0x0015, // 0x0015 = ftCmo
2635 7
                            0x0012, // length of ftCmo data
2636 7
                            0x0008, // object type, 0x0008 = picture
2637 7
                            $i, // object id number, Excel seems to use 1-based index, local for the sheet
2638 7
                            0x6011, // option flags, 0x6011 is what OpenOffice.org uses
2639 7
                            0, // reserved
2640 7
                            0, // reserved
2641 7
                            0  // reserved
2642
                        );
2643
                }
2644
2645
                // ftEnd
2646
                $objData .=
2647 10
                    pack(
2648 10
                        'vv',
2649 10
                        0x0000, // 0x0000 = ftEnd
2650 10
                        0x0000  // length of ftEnd data
2651
                    );
2652
2653 10
                $length = strlen($objData);
2654 10
                $header = pack('vv', $record, $length);
2655 10
                $this->append($header . $objData);
2656
            }
2657
        }
2658 39
    }
2659
2660
    /**
2661
     * Store the DATAVALIDATIONS and DATAVALIDATION records.
2662
     *
2663
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
2664
     */
2665 39
    private function writeDataValidity()
2666
    {
2667
        // Datavalidation collection
2668 39
        $dataValidationCollection = $this->phpSheet->getDataValidationCollection();
2669
2670
        // Write data validations?
2671 39
        if (!empty($dataValidationCollection)) {
2672
            // DATAVALIDATIONS record
2673 2
            $record = 0x01B2; // Record identifier
2674 2
            $length = 0x0012; // Bytes to follow
2675
2676 2
            $grbit = 0x0000; // Prompt box at cell, no cached validity data at DV records
2677 2
            $horPos = 0x00000000; // Horizontal position of prompt box, if fixed position
2678 2
            $verPos = 0x00000000; // Vertical position of prompt box, if fixed position
2679 2
            $objId = 0xFFFFFFFF; // Object identifier of drop down arrow object, or -1 if not visible
2680
2681 2
            $header = pack('vv', $record, $length);
2682 2
            $data = pack('vVVVV', $grbit, $horPos, $verPos, $objId, count($dataValidationCollection));
2683 2
            $this->append($header . $data);
2684
2685
            // DATAVALIDATION records
2686 2
            $record = 0x01BE; // Record identifier
2687
2688 2
            foreach ($dataValidationCollection as $cellCoordinate => $dataValidation) {
2689
                // initialize record data
2690 2
                $data = '';
2691
2692
                // options
2693 2
                $options = 0x00000000;
2694
2695
                // data type
2696 2
                $type = 0x00;
2697 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...
2698 2
                    case DataValidation::TYPE_NONE:
2699
                        $type = 0x00;
2700
2701
                        break;
2702 2
                    case DataValidation::TYPE_WHOLE:
2703 1
                        $type = 0x01;
2704
2705 1
                        break;
2706 2
                    case DataValidation::TYPE_DECIMAL:
2707
                        $type = 0x02;
2708
2709
                        break;
2710 2
                    case DataValidation::TYPE_LIST:
2711 2
                        $type = 0x03;
2712
2713 2
                        break;
2714
                    case DataValidation::TYPE_DATE:
2715
                        $type = 0x04;
2716
2717
                        break;
2718
                    case DataValidation::TYPE_TIME:
2719
                        $type = 0x05;
2720
2721
                        break;
2722
                    case DataValidation::TYPE_TEXTLENGTH:
2723
                        $type = 0x06;
2724
2725
                        break;
2726
                    case DataValidation::TYPE_CUSTOM:
2727
                        $type = 0x07;
2728
2729
                        break;
2730
                }
2731
2732 2
                $options |= $type << 0;
2733
2734
                // error style
2735 2
                $errorStyle = 0x00;
2736 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...
2737 2
                    case DataValidation::STYLE_STOP:
2738 1
                        $errorStyle = 0x00;
2739
2740 1
                        break;
2741 2
                    case DataValidation::STYLE_WARNING:
2742
                        $errorStyle = 0x01;
2743
2744
                        break;
2745 2
                    case DataValidation::STYLE_INFORMATION:
2746 2
                        $errorStyle = 0x02;
2747
2748 2
                        break;
2749
                }
2750
2751 2
                $options |= $errorStyle << 4;
2752
2753
                // explicit formula?
2754 2
                if ($type == 0x03 && preg_match('/^\".*\"$/', $dataValidation->getFormula1())) {
2755 1
                    $options |= 0x01 << 7;
2756
                }
2757
2758
                // empty cells allowed
2759 2
                $options |= $dataValidation->getAllowBlank() << 8;
2760
2761
                // show drop down
2762 2
                $options |= (!$dataValidation->getShowDropDown()) << 9;
2763
2764
                // show input message
2765 2
                $options |= $dataValidation->getShowInputMessage() << 18;
2766
2767
                // show error message
2768 2
                $options |= $dataValidation->getShowErrorMessage() << 19;
2769
2770
                // condition operator
2771 2
                $operator = 0x00;
2772 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...
2773 2
                    case DataValidation::OPERATOR_BETWEEN:
2774 2
                        $operator = 0x00;
2775
2776 2
                        break;
2777
                    case DataValidation::OPERATOR_NOTBETWEEN:
2778
                        $operator = 0x01;
2779
2780
                        break;
2781
                    case DataValidation::OPERATOR_EQUAL:
2782
                        $operator = 0x02;
2783
2784
                        break;
2785
                    case DataValidation::OPERATOR_NOTEQUAL:
2786
                        $operator = 0x03;
2787
2788
                        break;
2789
                    case DataValidation::OPERATOR_GREATERTHAN:
2790
                        $operator = 0x04;
2791
2792
                        break;
2793
                    case DataValidation::OPERATOR_LESSTHAN:
2794
                        $operator = 0x05;
2795
2796
                        break;
2797
                    case DataValidation::OPERATOR_GREATERTHANOREQUAL:
2798
                        $operator = 0x06;
2799
2800
                        break;
2801
                    case DataValidation::OPERATOR_LESSTHANOREQUAL:
2802
                        $operator = 0x07;
2803
2804
                        break;
2805
                }
2806
2807 2
                $options |= $operator << 20;
2808
2809 2
                $data = pack('V', $options);
2810
2811
                // prompt title
2812 2
                $promptTitle = $dataValidation->getPromptTitle() !== '' ?
2813 2
                    $dataValidation->getPromptTitle() : chr(0);
2814 2
                $data .= StringHelper::UTF8toBIFF8UnicodeLong($promptTitle);
2815
2816
                // error title
2817 2
                $errorTitle = $dataValidation->getErrorTitle() !== '' ?
2818 2
                    $dataValidation->getErrorTitle() : chr(0);
2819 2
                $data .= StringHelper::UTF8toBIFF8UnicodeLong($errorTitle);
2820
2821
                // prompt text
2822 2
                $prompt = $dataValidation->getPrompt() !== '' ?
2823 2
                    $dataValidation->getPrompt() : chr(0);
2824 2
                $data .= StringHelper::UTF8toBIFF8UnicodeLong($prompt);
2825
2826
                // error text
2827 2
                $error = $dataValidation->getError() !== '' ?
2828 2
                    $dataValidation->getError() : chr(0);
2829 2
                $data .= StringHelper::UTF8toBIFF8UnicodeLong($error);
2830
2831
                // formula 1
2832
                try {
2833 2
                    $formula1 = $dataValidation->getFormula1();
2834 2
                    if ($type == 0x03) { // list type
2835 2
                        $formula1 = str_replace(',', chr(0), $formula1);
2836
                    }
2837 2
                    $this->parser->parse($formula1);
2838 1
                    $formula1 = $this->parser->toReversePolish();
2839 1
                    $sz1 = strlen($formula1);
2840 2
                } catch (PhpSpreadsheetException $e) {
2841 2
                    $sz1 = 0;
2842 2
                    $formula1 = '';
2843
                }
2844 2
                $data .= pack('vv', $sz1, 0x0000);
2845 2
                $data .= $formula1;
2846
2847
                // formula 2
2848
                try {
2849 2
                    $formula2 = $dataValidation->getFormula2();
2850 2
                    if ($formula2 === '') {
2851 2
                        throw new WriterException('No formula2');
2852
                    }
2853 1
                    $this->parser->parse($formula2);
2854
                    $formula2 = $this->parser->toReversePolish();
2855
                    $sz2 = strlen($formula2);
2856 2
                } catch (PhpSpreadsheetException $e) {
2857 2
                    $sz2 = 0;
2858 2
                    $formula2 = '';
2859
                }
2860 2
                $data .= pack('vv', $sz2, 0x0000);
2861 2
                $data .= $formula2;
2862
2863
                // cell range address list
2864 2
                $data .= pack('v', 0x0001);
2865 2
                $data .= $this->writeBIFF8CellRangeAddressFixed($cellCoordinate);
2866
2867 2
                $length = strlen($data);
2868 2
                $header = pack('vv', $record, $length);
2869
2870 2
                $this->append($header . $data);
2871
            }
2872
        }
2873 39
    }
2874
2875
    /**
2876
     * Map Error code.
2877
     *
2878
     * @param string $errorCode
2879
     *
2880
     * @return int
2881
     */
2882 4
    private static function mapErrorCode($errorCode)
2883
    {
2884
        switch ($errorCode) {
2885 4
            case '#NULL!':
2886
                return 0x00;
2887 4
            case '#DIV/0!':
2888 3
                return 0x07;
2889 2
            case '#VALUE!':
2890 1
                return 0x0F;
2891 1
            case '#REF!':
2892
                return 0x17;
2893 1
            case '#NAME?':
2894
                return 0x1D;
2895 1
            case '#NUM!':
2896
                return 0x24;
2897 1
            case '#N/A':
2898 1
                return 0x2A;
2899
        }
2900
2901
        return 0;
2902
    }
2903
2904
    /**
2905
     * Write PLV Record.
2906
     */
2907 39
    private function writePageLayoutView()
2908
    {
2909 39
        $record = 0x088B; // Record identifier
2910 39
        $length = 0x0010; // Bytes to follow
2911
2912 39
        $rt = 0x088B; // 2
2913 39
        $grbitFrt = 0x0000; // 2
2914 39
        $reserved = 0x0000000000000000; // 8
2915 39
        $wScalvePLV = $this->phpSheet->getSheetView()->getZoomScale(); // 2
2916
2917
        // The options flags that comprise $grbit
2918 39
        if ($this->phpSheet->getSheetView()->getView() == SheetView::SHEETVIEW_PAGE_LAYOUT) {
2919 1
            $fPageLayoutView = 1;
2920
        } else {
2921 38
            $fPageLayoutView = 0;
2922
        }
2923 39
        $fRulerVisible = 0;
2924 39
        $fWhitespaceHidden = 0;
2925
2926 39
        $grbit = $fPageLayoutView; // 2
2927 39
        $grbit |= $fRulerVisible << 1;
2928 39
        $grbit |= $fWhitespaceHidden << 3;
2929
2930 39
        $header = pack('vv', $record, $length);
2931 39
        $data = pack('vvVVvv', $rt, $grbitFrt, 0x00000000, 0x00000000, $wScalvePLV, $grbit);
2932 39
        $this->append($header . $data);
2933 39
    }
2934
2935
    /**
2936
     * Write CFRule Record.
2937
     *
2938
     * @param Conditional $conditional
2939
     */
2940 2
    private function writeCFRule(Conditional $conditional)
2941
    {
2942 2
        $record = 0x01B1; // Record identifier
2943
2944
        // $type : Type of the CF
2945
        // $operatorType : Comparison operator
2946 2
        if ($conditional->getConditionType() == Conditional::CONDITION_EXPRESSION) {
2947
            $type = 0x02;
2948
            $operatorType = 0x00;
2949 2
        } elseif ($conditional->getConditionType() == Conditional::CONDITION_CELLIS) {
2950 2
            $type = 0x01;
2951
2952 2
            switch ($conditional->getOperatorType()) {
2953 2
                case Conditional::OPERATOR_NONE:
2954
                    $operatorType = 0x00;
2955
2956
                    break;
2957 2
                case Conditional::OPERATOR_EQUAL:
2958
                    $operatorType = 0x03;
2959
2960
                    break;
2961 2
                case Conditional::OPERATOR_GREATERTHAN:
2962
                    $operatorType = 0x05;
2963
2964
                    break;
2965 2
                case Conditional::OPERATOR_GREATERTHANOREQUAL:
2966 2
                    $operatorType = 0x07;
2967
2968 2
                    break;
2969 2
                case Conditional::OPERATOR_LESSTHAN:
2970 2
                    $operatorType = 0x06;
2971
2972 2
                    break;
2973 1
                case Conditional::OPERATOR_LESSTHANOREQUAL:
2974
                    $operatorType = 0x08;
2975
2976
                    break;
2977 1
                case Conditional::OPERATOR_NOTEQUAL:
2978
                    $operatorType = 0x04;
2979
2980
                    break;
2981 1
                case Conditional::OPERATOR_BETWEEN:
2982 1
                    $operatorType = 0x01;
2983
2984 1
                    break;
2985
                    // not OPERATOR_NOTBETWEEN 0x02
2986
            }
2987
        }
2988
2989
        // $szValue1 : size of the formula data for first value or formula
2990
        // $szValue2 : size of the formula data for second value or formula
2991 2
        $arrConditions = $conditional->getConditions();
2992 2
        $numConditions = count($arrConditions);
2993 2
        if ($numConditions == 1) {
2994 2
            $szValue1 = ($arrConditions[0] <= 65535 ? 3 : 0x0000);
2995 2
            $szValue2 = 0x0000;
2996 2
            $operand1 = pack('Cv', 0x1E, $arrConditions[0]);
2997 2
            $operand2 = null;
2998 1
        } elseif ($numConditions == 2 && ($conditional->getOperatorType() == Conditional::OPERATOR_BETWEEN)) {
2999 1
            $szValue1 = ($arrConditions[0] <= 65535 ? 3 : 0x0000);
3000 1
            $szValue2 = ($arrConditions[1] <= 65535 ? 3 : 0x0000);
3001 1
            $operand1 = pack('Cv', 0x1E, $arrConditions[0]);
3002 1
            $operand2 = pack('Cv', 0x1E, $arrConditions[1]);
3003
        } else {
3004
            $szValue1 = 0x0000;
3005
            $szValue2 = 0x0000;
3006
            $operand1 = null;
3007
            $operand2 = null;
3008
        }
3009
3010
        // $flags : Option flags
3011
        // Alignment
3012 2
        $bAlignHz = ($conditional->getStyle()->getAlignment()->getHorizontal() == null ? 1 : 0);
3013 2
        $bAlignVt = ($conditional->getStyle()->getAlignment()->getVertical() == null ? 1 : 0);
3014 2
        $bAlignWrapTx = ($conditional->getStyle()->getAlignment()->getWrapText() == false ? 1 : 0);
3015 2
        $bTxRotation = ($conditional->getStyle()->getAlignment()->getTextRotation() == null ? 1 : 0);
3016 2
        $bIndent = ($conditional->getStyle()->getAlignment()->getIndent() == 0 ? 1 : 0);
3017 2
        $bShrinkToFit = ($conditional->getStyle()->getAlignment()->getShrinkToFit() == false ? 1 : 0);
3018 2
        if ($bAlignHz == 0 || $bAlignVt == 0 || $bAlignWrapTx == 0 || $bTxRotation == 0 || $bIndent == 0 || $bShrinkToFit == 0) {
3019
            $bFormatAlign = 1;
3020
        } else {
3021 2
            $bFormatAlign = 0;
3022
        }
3023
        // Protection
3024 2
        $bProtLocked = ($conditional->getStyle()->getProtection()->getLocked() == null ? 1 : 0);
3025 2
        $bProtHidden = ($conditional->getStyle()->getProtection()->getHidden() == null ? 1 : 0);
3026 2
        if ($bProtLocked == 0 || $bProtHidden == 0) {
3027
            $bFormatProt = 1;
3028
        } else {
3029 2
            $bFormatProt = 0;
3030
        }
3031
        // Border
3032 2
        $bBorderLeft = ($conditional->getStyle()->getBorders()->getLeft()->getColor()->getARGB() == Color::COLOR_BLACK
3033 2
                        && $conditional->getStyle()->getBorders()->getLeft()->getBorderStyle() == Border::BORDER_NONE ? 1 : 0);
3034 2
        $bBorderRight = ($conditional->getStyle()->getBorders()->getRight()->getColor()->getARGB() == Color::COLOR_BLACK
3035 2
                        && $conditional->getStyle()->getBorders()->getRight()->getBorderStyle() == Border::BORDER_NONE ? 1 : 0);
3036 2
        $bBorderTop = ($conditional->getStyle()->getBorders()->getTop()->getColor()->getARGB() == Color::COLOR_BLACK
3037 2
                        && $conditional->getStyle()->getBorders()->getTop()->getBorderStyle() == Border::BORDER_NONE ? 1 : 0);
3038 2
        $bBorderBottom = ($conditional->getStyle()->getBorders()->getBottom()->getColor()->getARGB() == Color::COLOR_BLACK
3039 2
                        && $conditional->getStyle()->getBorders()->getBottom()->getBorderStyle() == Border::BORDER_NONE ? 1 : 0);
3040 2
        if ($bBorderLeft == 0 || $bBorderRight == 0 || $bBorderTop == 0 || $bBorderBottom == 0) {
3041
            $bFormatBorder = 1;
3042
        } else {
3043 2
            $bFormatBorder = 0;
3044
        }
3045
        // Pattern
3046 2
        $bFillStyle = ($conditional->getStyle()->getFill()->getFillType() == null ? 0 : 1);
3047 2
        $bFillColor = ($conditional->getStyle()->getFill()->getStartColor()->getARGB() == null ? 0 : 1);
3048 2
        $bFillColorBg = ($conditional->getStyle()->getFill()->getEndColor()->getARGB() == null ? 0 : 1);
3049 2
        if ($bFillStyle == 0 || $bFillColor == 0 || $bFillColorBg == 0) {
3050 2
            $bFormatFill = 1;
3051
        } else {
3052
            $bFormatFill = 0;
3053
        }
3054
        // Font
3055 2
        if ($conditional->getStyle()->getFont()->getName() != null
3056 2
            || $conditional->getStyle()->getFont()->getSize() != null
3057 2
            || $conditional->getStyle()->getFont()->getBold() != null
3058 2
            || $conditional->getStyle()->getFont()->getItalic() != null
3059 1
            || $conditional->getStyle()->getFont()->getSuperscript() != null
3060 1
            || $conditional->getStyle()->getFont()->getSubscript() != null
3061 1
            || $conditional->getStyle()->getFont()->getUnderline() != null
3062 1
            || $conditional->getStyle()->getFont()->getStrikethrough() != null
3063 2
            || $conditional->getStyle()->getFont()->getColor()->getARGB() != null) {
3064 2
            $bFormatFont = 1;
3065
        } else {
3066
            $bFormatFont = 0;
3067
        }
3068
        // Alignment
3069 2
        $flags = 0;
3070 2
        $flags |= (1 == $bAlignHz ? 0x00000001 : 0);
3071 2
        $flags |= (1 == $bAlignVt ? 0x00000002 : 0);
3072 2
        $flags |= (1 == $bAlignWrapTx ? 0x00000004 : 0);
3073 2
        $flags |= (1 == $bTxRotation ? 0x00000008 : 0);
3074
        // Justify last line flag
3075 2
        $flags |= (1 == 1 ? 0x00000010 : 0);
3076 2
        $flags |= (1 == $bIndent ? 0x00000020 : 0);
3077 2
        $flags |= (1 == $bShrinkToFit ? 0x00000040 : 0);
3078
        // Default
3079 2
        $flags |= (1 == 1 ? 0x00000080 : 0);
3080
        // Protection
3081 2
        $flags |= (1 == $bProtLocked ? 0x00000100 : 0);
3082 2
        $flags |= (1 == $bProtHidden ? 0x00000200 : 0);
3083
        // Border
3084 2
        $flags |= (1 == $bBorderLeft ? 0x00000400 : 0);
3085 2
        $flags |= (1 == $bBorderRight ? 0x00000800 : 0);
3086 2
        $flags |= (1 == $bBorderTop ? 0x00001000 : 0);
3087 2
        $flags |= (1 == $bBorderBottom ? 0x00002000 : 0);
3088 2
        $flags |= (1 == 1 ? 0x00004000 : 0); // Top left to Bottom right border
3089 2
        $flags |= (1 == 1 ? 0x00008000 : 0); // Bottom left to Top right border
3090
        // Pattern
3091 2
        $flags |= (1 == $bFillStyle ? 0x00010000 : 0);
3092 2
        $flags |= (1 == $bFillColor ? 0x00020000 : 0);
3093 2
        $flags |= (1 == $bFillColorBg ? 0x00040000 : 0);
3094 2
        $flags |= (1 == 1 ? 0x00380000 : 0);
3095
        // Font
3096 2
        $flags |= (1 == $bFormatFont ? 0x04000000 : 0);
3097
        // Alignment:
3098 2
        $flags |= (1 == $bFormatAlign ? 0x08000000 : 0);
3099
        // Border
3100 2
        $flags |= (1 == $bFormatBorder ? 0x10000000 : 0);
3101
        // Pattern
3102 2
        $flags |= (1 == $bFormatFill ? 0x20000000 : 0);
3103
        // Protection
3104 2
        $flags |= (1 == $bFormatProt ? 0x40000000 : 0);
3105
        // Text direction
3106 2
        $flags |= (1 == 0 ? 0x80000000 : 0);
3107
3108
        // Data Blocks
3109 2
        if ($bFormatFont == 1) {
3110
            // Font Name
3111 2
            if ($conditional->getStyle()->getFont()->getName() == null) {
3112 2
                $dataBlockFont = pack('VVVVVVVV', 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
3113 2
                $dataBlockFont .= pack('VVVVVVVV', 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
3114
            } else {
3115
                $dataBlockFont = StringHelper::UTF8toBIFF8UnicodeLong($conditional->getStyle()->getFont()->getName());
3116
            }
3117
            // Font Size
3118 2
            if ($conditional->getStyle()->getFont()->getSize() == null) {
3119 2
                $dataBlockFont .= pack('V', 20 * 11);
3120
            } else {
3121
                $dataBlockFont .= pack('V', 20 * $conditional->getStyle()->getFont()->getSize());
3122
            }
3123
            // Font Options
3124 2
            $dataBlockFont .= pack('V', 0);
3125
            // Font weight
3126 2
            if ($conditional->getStyle()->getFont()->getBold() == true) {
3127 1
                $dataBlockFont .= pack('v', 0x02BC);
3128
            } else {
3129 2
                $dataBlockFont .= pack('v', 0x0190);
3130
            }
3131
            // Escapement type
3132 2
            if ($conditional->getStyle()->getFont()->getSubscript() == true) {
3133
                $dataBlockFont .= pack('v', 0x02);
3134
                $fontEscapement = 0;
3135 2
            } elseif ($conditional->getStyle()->getFont()->getSuperscript() == true) {
3136
                $dataBlockFont .= pack('v', 0x01);
3137
                $fontEscapement = 0;
3138
            } else {
3139 2
                $dataBlockFont .= pack('v', 0x00);
3140 2
                $fontEscapement = 1;
3141
            }
3142
            // Underline type
3143 2
            switch ($conditional->getStyle()->getFont()->getUnderline()) {
3144 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_NONE:
3145
                    $dataBlockFont .= pack('C', 0x00);
3146
                    $fontUnderline = 0;
3147
3148
                    break;
3149 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_DOUBLE:
3150
                    $dataBlockFont .= pack('C', 0x02);
3151
                    $fontUnderline = 0;
3152
3153
                    break;
3154 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_DOUBLEACCOUNTING:
3155
                    $dataBlockFont .= pack('C', 0x22);
3156
                    $fontUnderline = 0;
3157
3158
                    break;
3159 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_SINGLE:
3160
                    $dataBlockFont .= pack('C', 0x01);
3161
                    $fontUnderline = 0;
3162
3163
                    break;
3164 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_SINGLEACCOUNTING:
3165
                    $dataBlockFont .= pack('C', 0x21);
3166
                    $fontUnderline = 0;
3167
3168
                    break;
3169
                default:
3170 2
                    $dataBlockFont .= pack('C', 0x00);
3171 2
                    $fontUnderline = 1;
3172
3173 2
                    break;
3174
            }
3175
            // 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...
3176 2
            $dataBlockFont .= pack('vC', 0x0000, 0x00);
3177
            // Font color index
3178 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...
3179 2
                case '000000':
3180
                    $colorIdx = 0x08;
3181
3182
                    break;
3183 2
                case 'FFFFFF':
3184
                    $colorIdx = 0x09;
3185
3186
                    break;
3187 2
                case 'FF0000':
3188 2
                    $colorIdx = 0x0A;
3189
3190 2
                    break;
3191 2
                case '00FF00':
3192 2
                    $colorIdx = 0x0B;
3193
3194 2
                    break;
3195 1
                case '0000FF':
3196
                    $colorIdx = 0x0C;
3197
3198
                    break;
3199 1
                case 'FFFF00':
3200 1
                    $colorIdx = 0x0D;
3201
3202 1
                    break;
3203
                case 'FF00FF':
3204
                    $colorIdx = 0x0E;
3205
3206
                    break;
3207
                case '00FFFF':
3208
                    $colorIdx = 0x0F;
3209
3210
                    break;
3211
                case '800000':
3212
                    $colorIdx = 0x10;
3213
3214
                    break;
3215
                case '008000':
3216
                    $colorIdx = 0x11;
3217
3218
                    break;
3219
                case '000080':
3220
                    $colorIdx = 0x12;
3221
3222
                    break;
3223
                case '808000':
3224
                    $colorIdx = 0x13;
3225
3226
                    break;
3227
                case '800080':
3228
                    $colorIdx = 0x14;
3229
3230
                    break;
3231
                case '008080':
3232
                    $colorIdx = 0x15;
3233
3234
                    break;
3235
                case 'C0C0C0':
3236
                    $colorIdx = 0x16;
3237
3238
                    break;
3239
                case '808080':
3240
                    $colorIdx = 0x17;
3241
3242
                    break;
3243
                case '9999FF':
3244
                    $colorIdx = 0x18;
3245
3246
                    break;
3247
                case '993366':
3248
                    $colorIdx = 0x19;
3249
3250
                    break;
3251
                case 'FFFFCC':
3252
                    $colorIdx = 0x1A;
3253
3254
                    break;
3255
                case 'CCFFFF':
3256
                    $colorIdx = 0x1B;
3257
3258
                    break;
3259
                case '660066':
3260
                    $colorIdx = 0x1C;
3261
3262
                    break;
3263
                case 'FF8080':
3264
                    $colorIdx = 0x1D;
3265
3266
                    break;
3267
                case '0066CC':
3268
                    $colorIdx = 0x1E;
3269
3270
                    break;
3271
                case 'CCCCFF':
3272
                    $colorIdx = 0x1F;
3273
3274
                    break;
3275
                case '000080':
3276
                    $colorIdx = 0x20;
3277
3278
                    break;
3279
                case 'FF00FF':
3280
                    $colorIdx = 0x21;
3281
3282
                    break;
3283
                case 'FFFF00':
3284
                    $colorIdx = 0x22;
3285
3286
                    break;
3287
                case '00FFFF':
3288
                    $colorIdx = 0x23;
3289
3290
                    break;
3291
                case '800080':
3292
                    $colorIdx = 0x24;
3293
3294
                    break;
3295
                case '800000':
3296
                    $colorIdx = 0x25;
3297
3298
                    break;
3299
                case '008080':
3300
                    $colorIdx = 0x26;
3301
3302
                    break;
3303
                case '0000FF':
3304
                    $colorIdx = 0x27;
3305
3306
                    break;
3307
                case '00CCFF':
3308
                    $colorIdx = 0x28;
3309
3310
                    break;
3311
                case 'CCFFFF':
3312
                    $colorIdx = 0x29;
3313
3314
                    break;
3315
                case 'CCFFCC':
3316
                    $colorIdx = 0x2A;
3317
3318
                    break;
3319
                case 'FFFF99':
3320
                    $colorIdx = 0x2B;
3321
3322
                    break;
3323
                case '99CCFF':
3324
                    $colorIdx = 0x2C;
3325
3326
                    break;
3327
                case 'FF99CC':
3328
                    $colorIdx = 0x2D;
3329
3330
                    break;
3331
                case 'CC99FF':
3332
                    $colorIdx = 0x2E;
3333
3334
                    break;
3335
                case 'FFCC99':
3336
                    $colorIdx = 0x2F;
3337
3338
                    break;
3339
                case '3366FF':
3340
                    $colorIdx = 0x30;
3341
3342
                    break;
3343
                case '33CCCC':
3344
                    $colorIdx = 0x31;
3345
3346
                    break;
3347
                case '99CC00':
3348
                    $colorIdx = 0x32;
3349
3350
                    break;
3351
                case 'FFCC00':
3352
                    $colorIdx = 0x33;
3353
3354
                    break;
3355
                case 'FF9900':
3356
                    $colorIdx = 0x34;
3357
3358
                    break;
3359
                case 'FF6600':
3360
                    $colorIdx = 0x35;
3361
3362
                    break;
3363
                case '666699':
3364
                    $colorIdx = 0x36;
3365
3366
                    break;
3367
                case '969696':
3368
                    $colorIdx = 0x37;
3369
3370
                    break;
3371
                case '003366':
3372
                    $colorIdx = 0x38;
3373
3374
                    break;
3375
                case '339966':
3376
                    $colorIdx = 0x39;
3377
3378
                    break;
3379
                case '003300':
3380
                    $colorIdx = 0x3A;
3381
3382
                    break;
3383
                case '333300':
3384
                    $colorIdx = 0x3B;
3385
3386
                    break;
3387
                case '993300':
3388
                    $colorIdx = 0x3C;
3389
3390
                    break;
3391
                case '993366':
3392
                    $colorIdx = 0x3D;
3393
3394
                    break;
3395
                case '333399':
3396
                    $colorIdx = 0x3E;
3397
3398
                    break;
3399
                case '333333':
3400
                    $colorIdx = 0x3F;
3401
3402
                    break;
3403
                default:
3404
                    $colorIdx = 0x00;
3405
3406
                    break;
3407
            }
3408 2
            $dataBlockFont .= pack('V', $colorIdx);
3409
            // 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...
3410 2
            $dataBlockFont .= pack('V', 0x00000000);
3411
            // Options flags for modified font attributes
3412 2
            $optionsFlags = 0;
3413 2
            $optionsFlagsBold = ($conditional->getStyle()->getFont()->getBold() == null ? 1 : 0);
3414 2
            $optionsFlags |= (1 == $optionsFlagsBold ? 0x00000002 : 0);
3415 2
            $optionsFlags |= (1 == 1 ? 0x00000008 : 0);
3416 2
            $optionsFlags |= (1 == 1 ? 0x00000010 : 0);
3417 2
            $optionsFlags |= (1 == 0 ? 0x00000020 : 0);
3418 2
            $optionsFlags |= (1 == 1 ? 0x00000080 : 0);
3419 2
            $dataBlockFont .= pack('V', $optionsFlags);
3420
            // Escapement type
3421 2
            $dataBlockFont .= pack('V', $fontEscapement);
3422
            // Underline type
3423 2
            $dataBlockFont .= pack('V', $fontUnderline);
3424
            // Always
3425 2
            $dataBlockFont .= pack('V', 0x00000000);
3426
            // Always
3427 2
            $dataBlockFont .= pack('V', 0x00000000);
3428
            // 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...
3429 2
            $dataBlockFont .= pack('VV', 0x00000000, 0x00000000);
3430
            // Always
3431 2
            $dataBlockFont .= pack('v', 0x0001);
3432
        }
3433 2
        if ($bFormatAlign == 1) {
3434
            $blockAlign = 0;
3435
            // Alignment and text break
3436
            switch ($conditional->getStyle()->getAlignment()->getHorizontal()) {
3437
                case Alignment::HORIZONTAL_GENERAL:
3438
                    $blockAlign = 0;
3439
3440
                    break;
3441
                case Alignment::HORIZONTAL_LEFT:
3442
                    $blockAlign = 1;
3443
3444
                    break;
3445
                case Alignment::HORIZONTAL_RIGHT:
3446
                    $blockAlign = 3;
3447
3448
                    break;
3449
                case Alignment::HORIZONTAL_CENTER:
3450
                    $blockAlign = 2;
3451
3452
                    break;
3453
                case Alignment::HORIZONTAL_CENTER_CONTINUOUS:
3454
                    $blockAlign = 6;
3455
3456
                    break;
3457
                case Alignment::HORIZONTAL_JUSTIFY:
3458
                    $blockAlign = 5;
3459
3460
                    break;
3461
            }
3462
            if ($conditional->getStyle()->getAlignment()->getWrapText() == true) {
3463
                $blockAlign |= 1 << 3;
3464
            } else {
3465
                $blockAlign |= 0 << 3;
3466
            }
3467
            switch ($conditional->getStyle()->getAlignment()->getVertical()) {
3468
                case Alignment::VERTICAL_BOTTOM:
3469
                    $blockAlign = 2 << 4;
3470
3471
                    break;
3472
                case Alignment::VERTICAL_TOP:
3473
                    $blockAlign = 0 << 4;
3474
3475
                    break;
3476
                case Alignment::VERTICAL_CENTER:
3477
                    $blockAlign = 1 << 4;
3478
3479
                    break;
3480
                case Alignment::VERTICAL_JUSTIFY:
3481
                    $blockAlign = 3 << 4;
3482
3483
                    break;
3484
            }
3485
            $blockAlign |= 0 << 7;
3486
3487
            // Text rotation angle
3488
            $blockRotation = $conditional->getStyle()->getAlignment()->getTextRotation();
3489
3490
            // Indentation
3491
            $blockIndent = $conditional->getStyle()->getAlignment()->getIndent();
3492
            if ($conditional->getStyle()->getAlignment()->getShrinkToFit() == true) {
3493
                $blockIndent |= 1 << 4;
3494
            } else {
3495
                $blockIndent |= 0 << 4;
3496
            }
3497
            $blockIndent |= 0 << 6;
3498
3499
            // Relative indentation
3500
            $blockIndentRelative = 255;
3501
3502
            $dataBlockAlign = pack('CCvvv', $blockAlign, $blockRotation, $blockIndent, $blockIndentRelative, 0x0000);
3503
        }
3504 2
        if ($bFormatBorder == 1) {
3505
            $blockLineStyle = 0;
3506
            switch ($conditional->getStyle()->getBorders()->getLeft()->getBorderStyle()) {
3507
                case Border::BORDER_NONE:
3508
                    $blockLineStyle |= 0x00;
3509
3510
                    break;
3511
                case Border::BORDER_THIN:
3512
                    $blockLineStyle |= 0x01;
3513
3514
                    break;
3515
                case Border::BORDER_MEDIUM:
3516
                    $blockLineStyle |= 0x02;
3517
3518
                    break;
3519
                case Border::BORDER_DASHED:
3520
                    $blockLineStyle |= 0x03;
3521
3522
                    break;
3523
                case Border::BORDER_DOTTED:
3524
                    $blockLineStyle |= 0x04;
3525
3526
                    break;
3527
                case Border::BORDER_THICK:
3528
                    $blockLineStyle |= 0x05;
3529
3530
                    break;
3531
                case Border::BORDER_DOUBLE:
3532
                    $blockLineStyle |= 0x06;
3533
3534
                    break;
3535
                case Border::BORDER_HAIR:
3536
                    $blockLineStyle |= 0x07;
3537
3538
                    break;
3539
                case Border::BORDER_MEDIUMDASHED:
3540
                    $blockLineStyle |= 0x08;
3541
3542
                    break;
3543
                case Border::BORDER_DASHDOT:
3544
                    $blockLineStyle |= 0x09;
3545
3546
                    break;
3547
                case Border::BORDER_MEDIUMDASHDOT:
3548
                    $blockLineStyle |= 0x0A;
3549
3550
                    break;
3551
                case Border::BORDER_DASHDOTDOT:
3552
                    $blockLineStyle |= 0x0B;
3553
3554
                    break;
3555
                case Border::BORDER_MEDIUMDASHDOTDOT:
3556
                    $blockLineStyle |= 0x0C;
3557
3558
                    break;
3559
                case Border::BORDER_SLANTDASHDOT:
3560
                    $blockLineStyle |= 0x0D;
3561
3562
                    break;
3563
            }
3564 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...
3565
                case Border::BORDER_NONE:
3566
                    $blockLineStyle |= 0x00 << 4;
3567
3568
                    break;
3569
                case Border::BORDER_THIN:
3570
                    $blockLineStyle |= 0x01 << 4;
3571
3572
                    break;
3573
                case Border::BORDER_MEDIUM:
3574
                    $blockLineStyle |= 0x02 << 4;
3575
3576
                    break;
3577
                case Border::BORDER_DASHED:
3578
                    $blockLineStyle |= 0x03 << 4;
3579
3580
                    break;
3581
                case Border::BORDER_DOTTED:
3582
                    $blockLineStyle |= 0x04 << 4;
3583
3584
                    break;
3585
                case Border::BORDER_THICK:
3586
                    $blockLineStyle |= 0x05 << 4;
3587
3588
                    break;
3589
                case Border::BORDER_DOUBLE:
3590
                    $blockLineStyle |= 0x06 << 4;
3591
3592
                    break;
3593
                case Border::BORDER_HAIR:
3594
                    $blockLineStyle |= 0x07 << 4;
3595
3596
                    break;
3597
                case Border::BORDER_MEDIUMDASHED:
3598
                    $blockLineStyle |= 0x08 << 4;
3599
3600
                    break;
3601
                case Border::BORDER_DASHDOT:
3602
                    $blockLineStyle |= 0x09 << 4;
3603
3604
                    break;
3605
                case Border::BORDER_MEDIUMDASHDOT:
3606
                    $blockLineStyle |= 0x0A << 4;
3607
3608
                    break;
3609
                case Border::BORDER_DASHDOTDOT:
3610
                    $blockLineStyle |= 0x0B << 4;
3611
3612
                    break;
3613
                case Border::BORDER_MEDIUMDASHDOTDOT:
3614
                    $blockLineStyle |= 0x0C << 4;
3615
3616
                    break;
3617
                case Border::BORDER_SLANTDASHDOT:
3618
                    $blockLineStyle |= 0x0D << 4;
3619
3620
                    break;
3621
            }
3622 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...
3623
                case Border::BORDER_NONE:
3624
                    $blockLineStyle |= 0x00 << 8;
3625
3626
                    break;
3627
                case Border::BORDER_THIN:
3628
                    $blockLineStyle |= 0x01 << 8;
3629
3630
                    break;
3631
                case Border::BORDER_MEDIUM:
3632
                    $blockLineStyle |= 0x02 << 8;
3633
3634
                    break;
3635
                case Border::BORDER_DASHED:
3636
                    $blockLineStyle |= 0x03 << 8;
3637
3638
                    break;
3639
                case Border::BORDER_DOTTED:
3640
                    $blockLineStyle |= 0x04 << 8;
3641
3642
                    break;
3643
                case Border::BORDER_THICK:
3644
                    $blockLineStyle |= 0x05 << 8;
3645
3646
                    break;
3647
                case Border::BORDER_DOUBLE:
3648
                    $blockLineStyle |= 0x06 << 8;
3649
3650
                    break;
3651
                case Border::BORDER_HAIR:
3652
                    $blockLineStyle |= 0x07 << 8;
3653
3654
                    break;
3655
                case Border::BORDER_MEDIUMDASHED:
3656
                    $blockLineStyle |= 0x08 << 8;
3657
3658
                    break;
3659
                case Border::BORDER_DASHDOT:
3660
                    $blockLineStyle |= 0x09 << 8;
3661
3662
                    break;
3663
                case Border::BORDER_MEDIUMDASHDOT:
3664
                    $blockLineStyle |= 0x0A << 8;
3665
3666
                    break;
3667
                case Border::BORDER_DASHDOTDOT:
3668
                    $blockLineStyle |= 0x0B << 8;
3669
3670
                    break;
3671
                case Border::BORDER_MEDIUMDASHDOTDOT:
3672
                    $blockLineStyle |= 0x0C << 8;
3673
3674
                    break;
3675
                case Border::BORDER_SLANTDASHDOT:
3676
                    $blockLineStyle |= 0x0D << 8;
3677
3678
                    break;
3679
            }
3680 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...
3681
                case Border::BORDER_NONE:
3682
                    $blockLineStyle |= 0x00 << 12;
3683
3684
                    break;
3685
                case Border::BORDER_THIN:
3686
                    $blockLineStyle |= 0x01 << 12;
3687
3688
                    break;
3689
                case Border::BORDER_MEDIUM:
3690
                    $blockLineStyle |= 0x02 << 12;
3691
3692
                    break;
3693
                case Border::BORDER_DASHED:
3694
                    $blockLineStyle |= 0x03 << 12;
3695
3696
                    break;
3697
                case Border::BORDER_DOTTED:
3698
                    $blockLineStyle |= 0x04 << 12;
3699
3700
                    break;
3701
                case Border::BORDER_THICK:
3702
                    $blockLineStyle |= 0x05 << 12;
3703
3704
                    break;
3705
                case Border::BORDER_DOUBLE:
3706
                    $blockLineStyle |= 0x06 << 12;
3707
3708
                    break;
3709
                case Border::BORDER_HAIR:
3710
                    $blockLineStyle |= 0x07 << 12;
3711
3712
                    break;
3713
                case Border::BORDER_MEDIUMDASHED:
3714
                    $blockLineStyle |= 0x08 << 12;
3715
3716
                    break;
3717
                case Border::BORDER_DASHDOT:
3718
                    $blockLineStyle |= 0x09 << 12;
3719
3720
                    break;
3721
                case Border::BORDER_MEDIUMDASHDOT:
3722
                    $blockLineStyle |= 0x0A << 12;
3723
3724
                    break;
3725
                case Border::BORDER_DASHDOTDOT:
3726
                    $blockLineStyle |= 0x0B << 12;
3727
3728
                    break;
3729
                case Border::BORDER_MEDIUMDASHDOTDOT:
3730
                    $blockLineStyle |= 0x0C << 12;
3731
3732
                    break;
3733
                case Border::BORDER_SLANTDASHDOT:
3734
                    $blockLineStyle |= 0x0D << 12;
3735
3736
                    break;
3737
            }
3738
            //@todo writeCFRule() => $blockLineStyle => Index Color for left line
3739
            //@todo writeCFRule() => $blockLineStyle => Index Color for right line
3740
            //@todo writeCFRule() => $blockLineStyle => Top-left to bottom-right on/off
3741
            //@todo writeCFRule() => $blockLineStyle => Bottom-left to top-right on/off
3742
            $blockColor = 0;
3743
            //@todo writeCFRule() => $blockColor => Index Color for top line
3744
            //@todo writeCFRule() => $blockColor => Index Color for bottom line
3745
            //@todo writeCFRule() => $blockColor => Index Color for diagonal line
3746 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...
3747
                case Border::BORDER_NONE:
3748
                    $blockColor |= 0x00 << 21;
3749
3750
                    break;
3751
                case Border::BORDER_THIN:
3752
                    $blockColor |= 0x01 << 21;
3753
3754
                    break;
3755
                case Border::BORDER_MEDIUM:
3756
                    $blockColor |= 0x02 << 21;
3757
3758
                    break;
3759
                case Border::BORDER_DASHED:
3760
                    $blockColor |= 0x03 << 21;
3761
3762
                    break;
3763
                case Border::BORDER_DOTTED:
3764
                    $blockColor |= 0x04 << 21;
3765
3766
                    break;
3767
                case Border::BORDER_THICK:
3768
                    $blockColor |= 0x05 << 21;
3769
3770
                    break;
3771
                case Border::BORDER_DOUBLE:
3772
                    $blockColor |= 0x06 << 21;
3773
3774
                    break;
3775
                case Border::BORDER_HAIR:
3776
                    $blockColor |= 0x07 << 21;
3777
3778
                    break;
3779
                case Border::BORDER_MEDIUMDASHED:
3780
                    $blockColor |= 0x08 << 21;
3781
3782
                    break;
3783
                case Border::BORDER_DASHDOT:
3784
                    $blockColor |= 0x09 << 21;
3785
3786
                    break;
3787
                case Border::BORDER_MEDIUMDASHDOT:
3788
                    $blockColor |= 0x0A << 21;
3789
3790
                    break;
3791
                case Border::BORDER_DASHDOTDOT:
3792
                    $blockColor |= 0x0B << 21;
3793
3794
                    break;
3795
                case Border::BORDER_MEDIUMDASHDOTDOT:
3796
                    $blockColor |= 0x0C << 21;
3797
3798
                    break;
3799
                case Border::BORDER_SLANTDASHDOT:
3800
                    $blockColor |= 0x0D << 21;
3801
3802
                    break;
3803
            }
3804
            $dataBlockBorder = pack('vv', $blockLineStyle, $blockColor);
3805
        }
3806 2
        if ($bFormatFill == 1) {
3807
            // Fill Patern Style
3808 2
            $blockFillPatternStyle = 0;
3809 2
            switch ($conditional->getStyle()->getFill()->getFillType()) {
3810 2
                case Fill::FILL_NONE:
3811
                    $blockFillPatternStyle = 0x00;
3812
3813
                    break;
3814 2
                case Fill::FILL_SOLID:
3815
                    $blockFillPatternStyle = 0x01;
3816
3817
                    break;
3818 2
                case Fill::FILL_PATTERN_MEDIUMGRAY:
3819
                    $blockFillPatternStyle = 0x02;
3820
3821
                    break;
3822 2
                case Fill::FILL_PATTERN_DARKGRAY:
3823
                    $blockFillPatternStyle = 0x03;
3824
3825
                    break;
3826 2
                case Fill::FILL_PATTERN_LIGHTGRAY:
3827
                    $blockFillPatternStyle = 0x04;
3828
3829
                    break;
3830 2
                case Fill::FILL_PATTERN_DARKHORIZONTAL:
3831
                    $blockFillPatternStyle = 0x05;
3832
3833
                    break;
3834 2
                case Fill::FILL_PATTERN_DARKVERTICAL:
3835
                    $blockFillPatternStyle = 0x06;
3836
3837
                    break;
3838 2
                case Fill::FILL_PATTERN_DARKDOWN:
3839
                    $blockFillPatternStyle = 0x07;
3840
3841
                    break;
3842 2
                case Fill::FILL_PATTERN_DARKUP:
3843
                    $blockFillPatternStyle = 0x08;
3844
3845
                    break;
3846 2
                case Fill::FILL_PATTERN_DARKGRID:
3847
                    $blockFillPatternStyle = 0x09;
3848
3849
                    break;
3850 2
                case Fill::FILL_PATTERN_DARKTRELLIS:
3851
                    $blockFillPatternStyle = 0x0A;
3852
3853
                    break;
3854 2
                case Fill::FILL_PATTERN_LIGHTHORIZONTAL:
3855
                    $blockFillPatternStyle = 0x0B;
3856
3857
                    break;
3858 2
                case Fill::FILL_PATTERN_LIGHTVERTICAL:
3859
                    $blockFillPatternStyle = 0x0C;
3860
3861
                    break;
3862 2
                case Fill::FILL_PATTERN_LIGHTDOWN:
3863
                    $blockFillPatternStyle = 0x0D;
3864
3865
                    break;
3866 2
                case Fill::FILL_PATTERN_LIGHTUP:
3867
                    $blockFillPatternStyle = 0x0E;
3868
3869
                    break;
3870 2
                case Fill::FILL_PATTERN_LIGHTGRID:
3871
                    $blockFillPatternStyle = 0x0F;
3872
3873
                    break;
3874 2
                case Fill::FILL_PATTERN_LIGHTTRELLIS:
3875
                    $blockFillPatternStyle = 0x10;
3876
3877
                    break;
3878 2
                case Fill::FILL_PATTERN_GRAY125:
3879
                    $blockFillPatternStyle = 0x11;
3880
3881
                    break;
3882 2
                case Fill::FILL_PATTERN_GRAY0625:
3883
                    $blockFillPatternStyle = 0x12;
3884
3885
                    break;
3886 2
                case Fill::FILL_GRADIENT_LINEAR:
3887
                    $blockFillPatternStyle = 0x00;
3888
3889
                    break; // does not exist in BIFF8
3890 2
                case Fill::FILL_GRADIENT_PATH:
3891
                    $blockFillPatternStyle = 0x00;
3892
3893
                    break; // does not exist in BIFF8
3894
                default:
3895 2
                    $blockFillPatternStyle = 0x00;
3896
3897 2
                    break;
3898
            }
3899
            // Color
3900 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...
3901 2
                case '000000':
3902
                    $colorIdxBg = 0x08;
3903
3904
                    break;
3905 2
                case 'FFFFFF':
3906
                    $colorIdxBg = 0x09;
3907
3908
                    break;
3909 2
                case 'FF0000':
3910
                    $colorIdxBg = 0x0A;
3911
3912
                    break;
3913 2
                case '00FF00':
3914
                    $colorIdxBg = 0x0B;
3915
3916
                    break;
3917 2
                case '0000FF':
3918
                    $colorIdxBg = 0x0C;
3919
3920
                    break;
3921 2
                case 'FFFF00':
3922
                    $colorIdxBg = 0x0D;
3923
3924
                    break;
3925 2
                case 'FF00FF':
3926
                    $colorIdxBg = 0x0E;
3927
3928
                    break;
3929 2
                case '00FFFF':
3930
                    $colorIdxBg = 0x0F;
3931
3932
                    break;
3933 2
                case '800000':
3934
                    $colorIdxBg = 0x10;
3935
3936
                    break;
3937 2
                case '008000':
3938
                    $colorIdxBg = 0x11;
3939
3940
                    break;
3941 2
                case '000080':
3942
                    $colorIdxBg = 0x12;
3943
3944
                    break;
3945 2
                case '808000':
3946
                    $colorIdxBg = 0x13;
3947
3948
                    break;
3949 2
                case '800080':
3950
                    $colorIdxBg = 0x14;
3951
3952
                    break;
3953 2
                case '008080':
3954
                    $colorIdxBg = 0x15;
3955
3956
                    break;
3957 2
                case 'C0C0C0':
3958
                    $colorIdxBg = 0x16;
3959
3960
                    break;
3961 2
                case '808080':
3962
                    $colorIdxBg = 0x17;
3963
3964
                    break;
3965 2
                case '9999FF':
3966
                    $colorIdxBg = 0x18;
3967
3968
                    break;
3969 2
                case '993366':
3970
                    $colorIdxBg = 0x19;
3971
3972
                    break;
3973 2
                case 'FFFFCC':
3974
                    $colorIdxBg = 0x1A;
3975
3976
                    break;
3977 2
                case 'CCFFFF':
3978
                    $colorIdxBg = 0x1B;
3979
3980
                    break;
3981 2
                case '660066':
3982
                    $colorIdxBg = 0x1C;
3983
3984
                    break;
3985 2
                case 'FF8080':
3986
                    $colorIdxBg = 0x1D;
3987
3988
                    break;
3989 2
                case '0066CC':
3990
                    $colorIdxBg = 0x1E;
3991
3992
                    break;
3993 2
                case 'CCCCFF':
3994
                    $colorIdxBg = 0x1F;
3995
3996
                    break;
3997 2
                case '000080':
3998
                    $colorIdxBg = 0x20;
3999
4000
                    break;
4001 2
                case 'FF00FF':
4002
                    $colorIdxBg = 0x21;
4003
4004
                    break;
4005 2
                case 'FFFF00':
4006
                    $colorIdxBg = 0x22;
4007
4008
                    break;
4009 2
                case '00FFFF':
4010
                    $colorIdxBg = 0x23;
4011
4012
                    break;
4013 2
                case '800080':
4014
                    $colorIdxBg = 0x24;
4015
4016
                    break;
4017 2
                case '800000':
4018
                    $colorIdxBg = 0x25;
4019
4020
                    break;
4021 2
                case '008080':
4022
                    $colorIdxBg = 0x26;
4023
4024
                    break;
4025 2
                case '0000FF':
4026
                    $colorIdxBg = 0x27;
4027
4028
                    break;
4029 2
                case '00CCFF':
4030
                    $colorIdxBg = 0x28;
4031
4032
                    break;
4033 2
                case 'CCFFFF':
4034
                    $colorIdxBg = 0x29;
4035
4036
                    break;
4037 2
                case 'CCFFCC':
4038
                    $colorIdxBg = 0x2A;
4039
4040
                    break;
4041 2
                case 'FFFF99':
4042
                    $colorIdxBg = 0x2B;
4043
4044
                    break;
4045 2
                case '99CCFF':
4046
                    $colorIdxBg = 0x2C;
4047
4048
                    break;
4049 2
                case 'FF99CC':
4050
                    $colorIdxBg = 0x2D;
4051
4052
                    break;
4053 2
                case 'CC99FF':
4054
                    $colorIdxBg = 0x2E;
4055
4056
                    break;
4057 2
                case 'FFCC99':
4058
                    $colorIdxBg = 0x2F;
4059
4060
                    break;
4061 2
                case '3366FF':
4062
                    $colorIdxBg = 0x30;
4063
4064
                    break;
4065 2
                case '33CCCC':
4066
                    $colorIdxBg = 0x31;
4067
4068
                    break;
4069 2
                case '99CC00':
4070
                    $colorIdxBg = 0x32;
4071
4072
                    break;
4073 2
                case 'FFCC00':
4074
                    $colorIdxBg = 0x33;
4075
4076
                    break;
4077 2
                case 'FF9900':
4078
                    $colorIdxBg = 0x34;
4079
4080
                    break;
4081 2
                case 'FF6600':
4082
                    $colorIdxBg = 0x35;
4083
4084
                    break;
4085 2
                case '666699':
4086
                    $colorIdxBg = 0x36;
4087
4088
                    break;
4089 2
                case '969696':
4090
                    $colorIdxBg = 0x37;
4091
4092
                    break;
4093 2
                case '003366':
4094
                    $colorIdxBg = 0x38;
4095
4096
                    break;
4097 2
                case '339966':
4098
                    $colorIdxBg = 0x39;
4099
4100
                    break;
4101 2
                case '003300':
4102
                    $colorIdxBg = 0x3A;
4103
4104
                    break;
4105 2
                case '333300':
4106
                    $colorIdxBg = 0x3B;
4107
4108
                    break;
4109 2
                case '993300':
4110
                    $colorIdxBg = 0x3C;
4111
4112
                    break;
4113 2
                case '993366':
4114
                    $colorIdxBg = 0x3D;
4115
4116
                    break;
4117 2
                case '333399':
4118
                    $colorIdxBg = 0x3E;
4119
4120
                    break;
4121 2
                case '333333':
4122
                    $colorIdxBg = 0x3F;
4123
4124
                    break;
4125
                default:
4126 2
                          $colorIdxBg = 0x41;
4127
4128 2
                    break;
4129
            }
4130
            // Fg Color
4131 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...
4132 2
                case '000000':
4133
                    $colorIdxFg = 0x08;
4134
4135
                    break;
4136 2
                case 'FFFFFF':
4137
                    $colorIdxFg = 0x09;
4138
4139
                    break;
4140 2
                case 'FF0000':
4141
                    $colorIdxFg = 0x0A;
4142
4143
                    break;
4144 2
                case '00FF00':
4145
                    $colorIdxFg = 0x0B;
4146
4147
                    break;
4148 2
                case '0000FF':
4149
                    $colorIdxFg = 0x0C;
4150
4151
                    break;
4152 2
                case 'FFFF00':
4153
                    $colorIdxFg = 0x0D;
4154
4155
                    break;
4156 2
                case 'FF00FF':
4157
                    $colorIdxFg = 0x0E;
4158
4159
                    break;
4160 2
                case '00FFFF':
4161
                    $colorIdxFg = 0x0F;
4162
4163
                    break;
4164 2
                case '800000':
4165
                    $colorIdxFg = 0x10;
4166
4167
                    break;
4168 2
                case '008000':
4169
                    $colorIdxFg = 0x11;
4170
4171
                    break;
4172 2
                case '000080':
4173
                    $colorIdxFg = 0x12;
4174
4175
                    break;
4176 2
                case '808000':
4177
                    $colorIdxFg = 0x13;
4178
4179
                    break;
4180 2
                case '800080':
4181
                    $colorIdxFg = 0x14;
4182
4183
                    break;
4184 2
                case '008080':
4185
                    $colorIdxFg = 0x15;
4186
4187
                    break;
4188 2
                case 'C0C0C0':
4189
                    $colorIdxFg = 0x16;
4190
4191
                    break;
4192 2
                case '808080':
4193
                    $colorIdxFg = 0x17;
4194
4195
                    break;
4196 2
                case '9999FF':
4197
                    $colorIdxFg = 0x18;
4198
4199
                    break;
4200 2
                case '993366':
4201
                    $colorIdxFg = 0x19;
4202
4203
                    break;
4204 2
                case 'FFFFCC':
4205
                    $colorIdxFg = 0x1A;
4206
4207
                    break;
4208 2
                case 'CCFFFF':
4209
                    $colorIdxFg = 0x1B;
4210
4211
                    break;
4212 2
                case '660066':
4213
                    $colorIdxFg = 0x1C;
4214
4215
                    break;
4216 2
                case 'FF8080':
4217
                    $colorIdxFg = 0x1D;
4218
4219
                    break;
4220 2
                case '0066CC':
4221
                    $colorIdxFg = 0x1E;
4222
4223
                    break;
4224 2
                case 'CCCCFF':
4225
                    $colorIdxFg = 0x1F;
4226
4227
                    break;
4228 2
                case '000080':
4229
                    $colorIdxFg = 0x20;
4230
4231
                    break;
4232 2
                case 'FF00FF':
4233
                    $colorIdxFg = 0x21;
4234
4235
                    break;
4236 2
                case 'FFFF00':
4237
                    $colorIdxFg = 0x22;
4238
4239
                    break;
4240 2
                case '00FFFF':
4241
                    $colorIdxFg = 0x23;
4242
4243
                    break;
4244 2
                case '800080':
4245
                    $colorIdxFg = 0x24;
4246
4247
                    break;
4248 2
                case '800000':
4249
                    $colorIdxFg = 0x25;
4250
4251
                    break;
4252 2
                case '008080':
4253
                    $colorIdxFg = 0x26;
4254
4255
                    break;
4256 2
                case '0000FF':
4257
                    $colorIdxFg = 0x27;
4258
4259
                    break;
4260 2
                case '00CCFF':
4261
                    $colorIdxFg = 0x28;
4262
4263
                    break;
4264 2
                case 'CCFFFF':
4265
                    $colorIdxFg = 0x29;
4266
4267
                    break;
4268 2
                case 'CCFFCC':
4269
                    $colorIdxFg = 0x2A;
4270
4271
                    break;
4272 2
                case 'FFFF99':
4273
                    $colorIdxFg = 0x2B;
4274
4275
                    break;
4276 2
                case '99CCFF':
4277
                    $colorIdxFg = 0x2C;
4278
4279
                    break;
4280 2
                case 'FF99CC':
4281
                    $colorIdxFg = 0x2D;
4282
4283
                    break;
4284 2
                case 'CC99FF':
4285
                    $colorIdxFg = 0x2E;
4286
4287
                    break;
4288 2
                case 'FFCC99':
4289
                    $colorIdxFg = 0x2F;
4290
4291
                    break;
4292 2
                case '3366FF':
4293
                    $colorIdxFg = 0x30;
4294
4295
                    break;
4296 2
                case '33CCCC':
4297
                    $colorIdxFg = 0x31;
4298
4299
                    break;
4300 2
                case '99CC00':
4301
                    $colorIdxFg = 0x32;
4302
4303
                    break;
4304 2
                case 'FFCC00':
4305
                    $colorIdxFg = 0x33;
4306
4307
                    break;
4308 2
                case 'FF9900':
4309
                    $colorIdxFg = 0x34;
4310
4311
                    break;
4312 2
                case 'FF6600':
4313
                    $colorIdxFg = 0x35;
4314
4315
                    break;
4316 2
                case '666699':
4317
                    $colorIdxFg = 0x36;
4318
4319
                    break;
4320 2
                case '969696':
4321
                    $colorIdxFg = 0x37;
4322
4323
                    break;
4324 2
                case '003366':
4325
                    $colorIdxFg = 0x38;
4326
4327
                    break;
4328 2
                case '339966':
4329
                    $colorIdxFg = 0x39;
4330
4331
                    break;
4332 2
                case '003300':
4333
                    $colorIdxFg = 0x3A;
4334
4335
                    break;
4336 2
                case '333300':
4337
                    $colorIdxFg = 0x3B;
4338
4339
                    break;
4340 2
                case '993300':
4341
                    $colorIdxFg = 0x3C;
4342
4343
                    break;
4344 2
                case '993366':
4345
                    $colorIdxFg = 0x3D;
4346
4347
                    break;
4348 2
                case '333399':
4349
                    $colorIdxFg = 0x3E;
4350
4351
                    break;
4352 2
                case '333333':
4353
                    $colorIdxFg = 0x3F;
4354
4355
                    break;
4356
                default:
4357 2
                          $colorIdxFg = 0x40;
4358
4359 2
                    break;
4360
            }
4361 2
            $dataBlockFill = pack('v', $blockFillPatternStyle);
4362 2
            $dataBlockFill .= pack('v', $colorIdxFg | ($colorIdxBg << 7));
4363
        }
4364 2
        if ($bFormatProt == 1) {
4365
            $dataBlockProtection = 0;
4366
            if ($conditional->getStyle()->getProtection()->getLocked() == Protection::PROTECTION_PROTECTED) {
4367
                $dataBlockProtection = 1;
4368
            }
4369
            if ($conditional->getStyle()->getProtection()->getHidden() == Protection::PROTECTION_PROTECTED) {
4370
                $dataBlockProtection = 1 << 1;
4371
            }
4372
        }
4373
4374 2
        $data = pack('CCvvVv', $type, $operatorType, $szValue1, $szValue2, $flags, 0x0000);
4375 2
        if ($bFormatFont == 1) { // Block Formatting : OK
4376 2
            $data .= $dataBlockFont;
4377
        }
4378 2
        if ($bFormatAlign == 1) {
4379
            $data .= $dataBlockAlign;
4380
        }
4381 2
        if ($bFormatBorder == 1) {
4382
            $data .= $dataBlockBorder;
4383
        }
4384 2
        if ($bFormatFill == 1) { // Block Formatting : OK
4385 2
            $data .= $dataBlockFill;
4386
        }
4387 2
        if ($bFormatProt == 1) {
4388
            $data .= $dataBlockProtection;
4389
        }
4390 2
        if ($operand1 !== null) {
4391 2
            $data .= $operand1;
4392
        }
4393 2
        if ($operand2 !== null) {
4394 1
            $data .= $operand2;
4395
        }
4396 2
        $header = pack('vv', $record, strlen($data));
4397 2
        $this->append($header . $data);
4398 2
    }
4399
4400
    /**
4401
     * Write CFHeader record.
4402
     */
4403 2
    private function writeCFHeader()
4404
    {
4405 2
        $record = 0x01B0; // Record identifier
4406 2
        $length = 0x0016; // Bytes to follow
4407
4408 2
        $numColumnMin = null;
4409 2
        $numColumnMax = null;
4410 2
        $numRowMin = null;
4411 2
        $numRowMax = null;
4412 2
        $arrConditional = [];
4413 2
        foreach ($this->phpSheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) {
4414 2
            foreach ($conditionalStyles as $conditional) {
4415 2
                if ($conditional->getConditionType() == Conditional::CONDITION_EXPRESSION
4416 2
                        || $conditional->getConditionType() == Conditional::CONDITION_CELLIS) {
4417 2
                    if (!in_array($conditional->getHashCode(), $arrConditional)) {
4418 2
                        $arrConditional[] = $conditional->getHashCode();
4419
                    }
4420
                    // Cells
4421 2
                    $arrCoord = Coordinate::coordinateFromString($cellCoordinate);
4422 2
                    if (!is_numeric($arrCoord[0])) {
4423 2
                        $arrCoord[0] = Coordinate::columnIndexFromString($arrCoord[0]);
4424
                    }
4425 2
                    if ($numColumnMin === null || ($numColumnMin > $arrCoord[0])) {
4426 2
                        $numColumnMin = $arrCoord[0];
4427
                    }
4428 2
                    if ($numColumnMax === null || ($numColumnMax < $arrCoord[0])) {
4429 2
                        $numColumnMax = $arrCoord[0];
4430
                    }
4431 2
                    if ($numRowMin === null || ($numRowMin > $arrCoord[1])) {
4432 2
                        $numRowMin = $arrCoord[1];
4433
                    }
4434 2
                    if ($numRowMax === null || ($numRowMax < $arrCoord[1])) {
4435 2
                        $numRowMax = $arrCoord[1];
4436
                    }
4437
                }
4438
            }
4439
        }
4440 2
        $needRedraw = 1;
4441 2
        $cellRange = pack('vvvv', $numRowMin - 1, $numRowMax - 1, $numColumnMin - 1, $numColumnMax - 1);
4442
4443 2
        $header = pack('vv', $record, $length);
4444 2
        $data = pack('vv', count($arrConditional), $needRedraw);
4445 2
        $data .= $cellRange;
4446 2
        $data .= pack('v', 0x0001);
4447 2
        $data .= $cellRange;
4448 2
        $this->append($header . $data);
4449 2
    }
4450
}
4451