Completed
Push — develop ( 04a8dd...eb5856 )
by Adrien
32:33
created

Worksheet::writeHcenter()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 11
Ratio 100 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 0
dl 11
loc 11
ccs 7
cts 7
cp 1
crap 2
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 ($freezePane = $this->phpSheet->getFreezePane()) {
1593 3
            list($column, $row) = Coordinate::coordinateFromString($freezePane);
1594 3
            $panes[0] = $row - 1;
1595 3
            $panes[1] = Coordinate::columnIndexFromString($column) - 1;
1596
        } else {
1597
            // thaw panes
1598
            return;
1599
        }
1600
1601 3
        $y = isset($panes[0]) ? $panes[0] : null;
1602 3
        $x = isset($panes[1]) ? $panes[1] : null;
1603 3
        $rwTop = isset($panes[2]) ? $panes[2] : null;
1604 3
        $colLeft = isset($panes[3]) ? $panes[3] : null;
1605 3
        if (count($panes) > 4) { // if Active pane was received
1606
            $pnnAct = $panes[4];
1607
        } else {
1608 3
            $pnnAct = null;
1609
        }
1610 3
        $record = 0x0041; // Record identifier
1611 3
        $length = 0x000A; // Number of bytes to follow
1612
1613
        // Code specific to frozen or thawed panes.
1614 3
        if ($this->phpSheet->getFreezePane()) {
1615
            // 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...
1616 3
            if (!isset($rwTop)) {
1617 3
                $rwTop = $y;
1618
            }
1619 3
            if (!isset($colLeft)) {
1620 3
                $colLeft = $x;
1621
            }
1622
        } else {
1623
            // 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...
1624
            if (!isset($rwTop)) {
1625
                $rwTop = 0;
1626
            }
1627
            if (!isset($colLeft)) {
1628
                $colLeft = 0;
1629
            }
1630
1631
            // Convert Excel's row and column units to the internal units.
1632
            // The default row height is 12.75
1633
            // The default column width is 8.43
1634
            // The following slope and intersection values were interpolated.
1635
            //
1636
            $y = 20 * $y + 255;
1637
            $x = 113.879 * $x + 390;
1638
        }
1639
1640
        // Determine which pane should be active. There is also the undocumented
1641
        // option to override this should it be necessary: may be removed later.
1642
        //
1643 3
        if (!isset($pnnAct)) {
1644 3
            if ($x != 0 && $y != 0) {
1645
                $pnnAct = 0; // Bottom right
1646
            }
1647 3
            if ($x != 0 && $y == 0) {
1648
                $pnnAct = 1; // Top right
1649
            }
1650 3
            if ($x == 0 && $y != 0) {
1651 3
                $pnnAct = 2; // Bottom left
1652
            }
1653 3
            if ($x == 0 && $y == 0) {
1654
                $pnnAct = 3; // Top left
1655
            }
1656
        }
1657
1658 3
        $this->activePane = $pnnAct; // Used in writeSelection
1659
1660 3
        $header = pack('vv', $record, $length);
1661 3
        $data = pack('vvvvv', $x, $y, $rwTop, $colLeft, $pnnAct);
1662 3
        $this->append($header . $data);
1663 3
    }
1664
1665
    /**
1666
     * Store the page setup SETUP BIFF record.
1667
     */
1668 39
    private function writeSetup()
1669
    {
1670 39
        $record = 0x00A1; // Record identifier
1671 39
        $length = 0x0022; // Number of bytes to follow
1672
1673 39
        $iPaperSize = $this->phpSheet->getPageSetup()->getPaperSize(); // Paper size
1674
1675 39
        $iScale = $this->phpSheet->getPageSetup()->getScale() ?
1676 39
            $this->phpSheet->getPageSetup()->getScale() : 100; // Print scaling factor
1677
1678 39
        $iPageStart = 0x01; // Starting page number
1679 39
        $iFitWidth = (int) $this->phpSheet->getPageSetup()->getFitToWidth(); // Fit to number of pages wide
1680 39
        $iFitHeight = (int) $this->phpSheet->getPageSetup()->getFitToHeight(); // Fit to number of pages high
1681 39
        $grbit = 0x00; // Option flags
1682 39
        $iRes = 0x0258; // Print resolution
1683 39
        $iVRes = 0x0258; // Vertical print resolution
1684
1685 39
        $numHdr = $this->phpSheet->getPageMargins()->getHeader(); // Header Margin
1686
1687 39
        $numFtr = $this->phpSheet->getPageMargins()->getFooter(); // Footer Margin
1688 39
        $iCopies = 0x01; // Number of copies
1689
1690 39
        $fLeftToRight = 0x0; // Print over then down
1691
1692
        // Page orientation
1693 39
        $fLandscape = ($this->phpSheet->getPageSetup()->getOrientation() == PageSetup::ORIENTATION_LANDSCAPE) ?
1694 39
            0x0 : 0x1;
1695
1696 39
        $fNoPls = 0x0; // Setup not read from printer
1697 39
        $fNoColor = 0x0; // Print black and white
1698 39
        $fDraft = 0x0; // Print draft quality
1699 39
        $fNotes = 0x0; // Print notes
1700 39
        $fNoOrient = 0x0; // Orientation not set
1701 39
        $fUsePage = 0x0; // Use custom starting page
1702
1703 39
        $grbit = $fLeftToRight;
1704 39
        $grbit |= $fLandscape << 1;
1705 39
        $grbit |= $fNoPls << 2;
1706 39
        $grbit |= $fNoColor << 3;
1707 39
        $grbit |= $fDraft << 4;
1708 39
        $grbit |= $fNotes << 5;
1709 39
        $grbit |= $fNoOrient << 6;
1710 39
        $grbit |= $fUsePage << 7;
1711
1712 39
        $numHdr = pack('d', $numHdr);
1713 39
        $numFtr = pack('d', $numFtr);
1714 39
        if (self::getByteOrder()) { // if it's Big Endian
1715
            $numHdr = strrev($numHdr);
1716
            $numFtr = strrev($numFtr);
1717
        }
1718
1719 39
        $header = pack('vv', $record, $length);
1720 39
        $data1 = pack('vvvvvvvv', $iPaperSize, $iScale, $iPageStart, $iFitWidth, $iFitHeight, $grbit, $iRes, $iVRes);
1721 39
        $data2 = $numHdr . $numFtr;
1722 39
        $data3 = pack('v', $iCopies);
1723 39
        $this->append($header . $data1 . $data2 . $data3);
1724 39
    }
1725
1726
    /**
1727
     * Store the header caption BIFF record.
1728
     */
1729 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...
1730
    {
1731 39
        $record = 0x0014; // Record identifier
1732
1733
        /* 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...
1734
        // need to fix character count (multibyte!)
1735
        if (strlen($this->phpSheet->getHeaderFooter()->getOddHeader()) <= 255) {
1736
            $str      = $this->phpSheet->getHeaderFooter()->getOddHeader();       // header string
1737
        } else {
1738
            $str = '';
1739
        }
1740
        */
1741
1742 39
        $recordData = StringHelper::UTF8toBIFF8UnicodeLong($this->phpSheet->getHeaderFooter()->getOddHeader());
1743 39
        $length = strlen($recordData);
1744
1745 39
        $header = pack('vv', $record, $length);
1746
1747 39
        $this->append($header . $recordData);
1748 39
    }
1749
1750
    /**
1751
     * Store the footer caption BIFF record.
1752
     */
1753 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...
1754
    {
1755 39
        $record = 0x0015; // Record identifier
1756
1757
        /* 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...
1758
        // need to fix character count (multibyte!)
1759
        if (strlen($this->phpSheet->getHeaderFooter()->getOddFooter()) <= 255) {
1760
            $str = $this->phpSheet->getHeaderFooter()->getOddFooter();
1761
        } else {
1762
            $str = '';
1763
        }
1764
        */
1765
1766 39
        $recordData = StringHelper::UTF8toBIFF8UnicodeLong($this->phpSheet->getHeaderFooter()->getOddFooter());
1767 39
        $length = strlen($recordData);
1768
1769 39
        $header = pack('vv', $record, $length);
1770
1771 39
        $this->append($header . $recordData);
1772 39
    }
1773
1774
    /**
1775
     * Store the horizontal centering HCENTER BIFF record.
1776
     */
1777 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...
1778
    {
1779 39
        $record = 0x0083; // Record identifier
1780 39
        $length = 0x0002; // Bytes to follow
1781
1782 39
        $fHCenter = $this->phpSheet->getPageSetup()->getHorizontalCentered() ? 1 : 0; // Horizontal centering
1783
1784 39
        $header = pack('vv', $record, $length);
1785 39
        $data = pack('v', $fHCenter);
1786
1787 39
        $this->append($header . $data);
1788 39
    }
1789
1790
    /**
1791
     * Store the vertical centering VCENTER BIFF record.
1792
     */
1793 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...
1794
    {
1795 39
        $record = 0x0084; // Record identifier
1796 39
        $length = 0x0002; // Bytes to follow
1797
1798 39
        $fVCenter = $this->phpSheet->getPageSetup()->getVerticalCentered() ? 1 : 0; // Horizontal centering
1799
1800 39
        $header = pack('vv', $record, $length);
1801 39
        $data = pack('v', $fVCenter);
1802 39
        $this->append($header . $data);
1803 39
    }
1804
1805
    /**
1806
     * Store the LEFTMARGIN BIFF record.
1807
     */
1808 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...
1809
    {
1810 39
        $record = 0x0026; // Record identifier
1811 39
        $length = 0x0008; // Bytes to follow
1812
1813 39
        $margin = $this->phpSheet->getPageMargins()->getLeft(); // Margin in inches
1814
1815 39
        $header = pack('vv', $record, $length);
1816 39
        $data = pack('d', $margin);
1817 39
        if (self::getByteOrder()) { // if it's Big Endian
1818
            $data = strrev($data);
1819
        }
1820
1821 39
        $this->append($header . $data);
1822 39
    }
1823
1824
    /**
1825
     * Store the RIGHTMARGIN BIFF record.
1826
     */
1827 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...
1828
    {
1829 39
        $record = 0x0027; // Record identifier
1830 39
        $length = 0x0008; // Bytes to follow
1831
1832 39
        $margin = $this->phpSheet->getPageMargins()->getRight(); // Margin in inches
1833
1834 39
        $header = pack('vv', $record, $length);
1835 39
        $data = pack('d', $margin);
1836 39
        if (self::getByteOrder()) { // if it's Big Endian
1837
            $data = strrev($data);
1838
        }
1839
1840 39
        $this->append($header . $data);
1841 39
    }
1842
1843
    /**
1844
     * Store the TOPMARGIN BIFF record.
1845
     */
1846 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...
1847
    {
1848 39
        $record = 0x0028; // Record identifier
1849 39
        $length = 0x0008; // Bytes to follow
1850
1851 39
        $margin = $this->phpSheet->getPageMargins()->getTop(); // Margin in inches
1852
1853 39
        $header = pack('vv', $record, $length);
1854 39
        $data = pack('d', $margin);
1855 39
        if (self::getByteOrder()) { // if it's Big Endian
1856
            $data = strrev($data);
1857
        }
1858
1859 39
        $this->append($header . $data);
1860 39
    }
1861
1862
    /**
1863
     * Store the BOTTOMMARGIN BIFF record.
1864
     */
1865 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...
1866
    {
1867 39
        $record = 0x0029; // Record identifier
1868 39
        $length = 0x0008; // Bytes to follow
1869
1870 39
        $margin = $this->phpSheet->getPageMargins()->getBottom(); // Margin in inches
1871
1872 39
        $header = pack('vv', $record, $length);
1873 39
        $data = pack('d', $margin);
1874 39
        if (self::getByteOrder()) { // if it's Big Endian
1875
            $data = strrev($data);
1876
        }
1877
1878 39
        $this->append($header . $data);
1879 39
    }
1880
1881
    /**
1882
     * Write the PRINTHEADERS BIFF record.
1883
     */
1884 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...
1885
    {
1886 39
        $record = 0x002a; // Record identifier
1887 39
        $length = 0x0002; // Bytes to follow
1888
1889 39
        $fPrintRwCol = $this->printHeaders; // Boolean flag
1890
1891 39
        $header = pack('vv', $record, $length);
1892 39
        $data = pack('v', $fPrintRwCol);
1893 39
        $this->append($header . $data);
1894 39
    }
1895
1896
    /**
1897
     * Write the PRINTGRIDLINES BIFF record. Must be used in conjunction with the
1898
     * GRIDSET record.
1899
     */
1900 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...
1901
    {
1902 39
        $record = 0x002b; // Record identifier
1903 39
        $length = 0x0002; // Bytes to follow
1904
1905 39
        $fPrintGrid = $this->phpSheet->getPrintGridlines() ? 1 : 0; // Boolean flag
1906
1907 39
        $header = pack('vv', $record, $length);
1908 39
        $data = pack('v', $fPrintGrid);
1909 39
        $this->append($header . $data);
1910 39
    }
1911
1912
    /**
1913
     * Write the GRIDSET BIFF record. Must be used in conjunction with the
1914
     * PRINTGRIDLINES record.
1915
     */
1916 39
    private function writeGridset()
1917
    {
1918 39
        $record = 0x0082; // Record identifier
1919 39
        $length = 0x0002; // Bytes to follow
1920
1921 39
        $fGridSet = !$this->phpSheet->getPrintGridlines(); // Boolean flag
1922
1923 39
        $header = pack('vv', $record, $length);
1924 39
        $data = pack('v', $fGridSet);
1925 39
        $this->append($header . $data);
1926 39
    }
1927
1928
    /**
1929
     * Write the AUTOFILTERINFO BIFF record. This is used to configure the number of autofilter select used in the sheet.
1930
     */
1931 3
    private function writeAutoFilterInfo()
1932
    {
1933 3
        $record = 0x009D; // Record identifier
1934 3
        $length = 0x0002; // Bytes to follow
1935
1936 3
        $rangeBounds = Coordinate::rangeBoundaries($this->phpSheet->getAutoFilter()->getRange());
1937 3
        $iNumFilters = 1 + $rangeBounds[1][0] - $rangeBounds[0][0];
1938
1939 3
        $header = pack('vv', $record, $length);
1940 3
        $data = pack('v', $iNumFilters);
1941 3
        $this->append($header . $data);
1942 3
    }
1943
1944
    /**
1945
     * Write the GUTS BIFF record. This is used to configure the gutter margins
1946
     * where Excel outline symbols are displayed. The visibility of the gutters is
1947
     * controlled by a flag in WSBOOL.
1948
     *
1949
     * @see writeWsbool()
1950
     */
1951 39
    private function writeGuts()
1952
    {
1953 39
        $record = 0x0080; // Record identifier
1954 39
        $length = 0x0008; // Bytes to follow
1955
1956 39
        $dxRwGut = 0x0000; // Size of row gutter
1957 39
        $dxColGut = 0x0000; // Size of col gutter
1958
1959
        // determine maximum row outline level
1960 39
        $maxRowOutlineLevel = 0;
1961 39
        foreach ($this->phpSheet->getRowDimensions() as $rowDimension) {
1962 38
            $maxRowOutlineLevel = max($maxRowOutlineLevel, $rowDimension->getOutlineLevel());
1963
        }
1964
1965 39
        $col_level = 0;
1966
1967
        // Calculate the maximum column outline level. The equivalent calculation
1968
        // for the row outline level is carried out in writeRow().
1969 39
        $colcount = count($this->columnInfo);
1970 39
        for ($i = 0; $i < $colcount; ++$i) {
1971 39
            $col_level = max($this->columnInfo[$i][5], $col_level);
1972
        }
1973
1974
        // Set the limits for the outline levels (0 <= x <= 7).
1975 39
        $col_level = max(0, min($col_level, 7));
1976
1977
        // The displayed level is one greater than the max outline levels
1978 39
        if ($maxRowOutlineLevel) {
1979
            ++$maxRowOutlineLevel;
1980
        }
1981 39
        if ($col_level) {
1982 1
            ++$col_level;
1983
        }
1984
1985 39
        $header = pack('vv', $record, $length);
1986 39
        $data = pack('vvvv', $dxRwGut, $dxColGut, $maxRowOutlineLevel, $col_level);
1987
1988 39
        $this->append($header . $data);
1989 39
    }
1990
1991
    /**
1992
     * Write the WSBOOL BIFF record, mainly for fit-to-page. Used in conjunction
1993
     * with the SETUP record.
1994
     */
1995 39
    private function writeWsbool()
1996
    {
1997 39
        $record = 0x0081; // Record identifier
1998 39
        $length = 0x0002; // Bytes to follow
1999 39
        $grbit = 0x0000;
2000
2001
        // The only option that is of interest is the flag for fit to page. So we
2002
        // set all the options in one go.
2003
        //
2004
        // Set the option flags
2005 39
        $grbit |= 0x0001; // Auto page breaks visible
2006 39
        if ($this->outlineStyle) {
2007
            $grbit |= 0x0020; // Auto outline styles
2008
        }
2009 39
        if ($this->phpSheet->getShowSummaryBelow()) {
2010 39
            $grbit |= 0x0040; // Outline summary below
2011
        }
2012 39
        if ($this->phpSheet->getShowSummaryRight()) {
2013 39
            $grbit |= 0x0080; // Outline summary right
2014
        }
2015 39
        if ($this->phpSheet->getPageSetup()->getFitToPage()) {
2016
            $grbit |= 0x0100; // Page setup fit to page
2017
        }
2018 39
        if ($this->outlineOn) {
2019 39
            $grbit |= 0x0400; // Outline symbols displayed
2020
        }
2021
2022 39
        $header = pack('vv', $record, $length);
2023 39
        $data = pack('v', $grbit);
2024 39
        $this->append($header . $data);
2025 39
    }
2026
2027
    /**
2028
     * Write the HORIZONTALPAGEBREAKS and VERTICALPAGEBREAKS BIFF records.
2029
     */
2030 39
    private function writeBreaks()
2031
    {
2032
        // initialize
2033 39
        $vbreaks = [];
2034 39
        $hbreaks = [];
2035
2036 39
        foreach ($this->phpSheet->getBreaks() as $cell => $breakType) {
2037
            // Fetch coordinates
2038 1
            $coordinates = Coordinate::coordinateFromString($cell);
2039
2040
            // Decide what to do by the type of break
2041
            switch ($breakType) {
2042 1
                case \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet::BREAK_COLUMN:
2043
                    // Add to list of vertical breaks
2044
                    $vbreaks[] = Coordinate::columnIndexFromString($coordinates[0]) - 1;
2045
2046
                    break;
2047 1
                case \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet::BREAK_ROW:
2048
                    // Add to list of horizontal breaks
2049 1
                    $hbreaks[] = $coordinates[1];
2050
2051 1
                    break;
2052
                case \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet::BREAK_NONE:
2053
                default:
2054
                    // Nothing to do
2055 1
                    break;
2056
            }
2057
        }
2058
2059
        //horizontal page breaks
2060 39
        if (!empty($hbreaks)) {
2061
            // Sort and filter array of page breaks
2062 1
            sort($hbreaks, SORT_NUMERIC);
2063 1
            if ($hbreaks[0] == 0) { // don't use first break if it's 0
2064
                array_shift($hbreaks);
2065
            }
2066
2067 1
            $record = 0x001b; // Record identifier
2068 1
            $cbrk = count($hbreaks); // Number of page breaks
2069 1
            $length = 2 + 6 * $cbrk; // Bytes to follow
2070
2071 1
            $header = pack('vv', $record, $length);
2072 1
            $data = pack('v', $cbrk);
2073
2074
            // Append each page break
2075 1
            foreach ($hbreaks as $hbreak) {
2076 1
                $data .= pack('vvv', $hbreak, 0x0000, 0x00ff);
2077
            }
2078
2079 1
            $this->append($header . $data);
2080
        }
2081
2082
        // vertical page breaks
2083 39
        if (!empty($vbreaks)) {
2084
            // 1000 vertical pagebreaks appears to be an internal Excel 5 limit.
2085
            // It is slightly higher in Excel 97/200, approx. 1026
2086
            $vbreaks = array_slice($vbreaks, 0, 1000);
2087
2088
            // Sort and filter array of page breaks
2089
            sort($vbreaks, SORT_NUMERIC);
2090
            if ($vbreaks[0] == 0) { // don't use first break if it's 0
2091
                array_shift($vbreaks);
2092
            }
2093
2094
            $record = 0x001a; // Record identifier
2095
            $cbrk = count($vbreaks); // Number of page breaks
2096
            $length = 2 + 6 * $cbrk; // Bytes to follow
2097
2098
            $header = pack('vv', $record, $length);
2099
            $data = pack('v', $cbrk);
2100
2101
            // Append each page break
2102
            foreach ($vbreaks as $vbreak) {
2103
                $data .= pack('vvv', $vbreak, 0x0000, 0xffff);
2104
            }
2105
2106
            $this->append($header . $data);
2107
        }
2108 39
    }
2109
2110
    /**
2111
     * Set the Biff PROTECT record to indicate that the worksheet is protected.
2112
     */
2113 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...
2114
    {
2115
        // Exit unless sheet protection has been specified
2116 39
        if (!$this->phpSheet->getProtection()->getSheet()) {
2117 37
            return;
2118
        }
2119
2120 7
        $record = 0x0012; // Record identifier
2121 7
        $length = 0x0002; // Bytes to follow
2122
2123 7
        $fLock = 1; // Worksheet is protected
2124
2125 7
        $header = pack('vv', $record, $length);
2126 7
        $data = pack('v', $fLock);
2127
2128 7
        $this->append($header . $data);
2129 7
    }
2130
2131
    /**
2132
     * Write SCENPROTECT.
2133
     */
2134 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...
2135
    {
2136
        // Exit if sheet protection is not active
2137 39
        if (!$this->phpSheet->getProtection()->getSheet()) {
2138 37
            return;
2139
        }
2140
2141
        // Exit if scenarios are not protected
2142 7
        if (!$this->phpSheet->getProtection()->getScenarios()) {
2143 7
            return;
2144
        }
2145
2146
        $record = 0x00DD; // Record identifier
2147
        $length = 0x0002; // Bytes to follow
2148
2149
        $header = pack('vv', $record, $length);
2150
        $data = pack('v', 1);
2151
2152
        $this->append($header . $data);
2153
    }
2154
2155
    /**
2156
     * Write OBJECTPROTECT.
2157
     */
2158 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...
2159
    {
2160
        // Exit if sheet protection is not active
2161 39
        if (!$this->phpSheet->getProtection()->getSheet()) {
2162 37
            return;
2163
        }
2164
2165
        // Exit if objects are not protected
2166 7
        if (!$this->phpSheet->getProtection()->getObjects()) {
2167 7
            return;
2168
        }
2169
2170
        $record = 0x0063; // Record identifier
2171
        $length = 0x0002; // Bytes to follow
2172
2173
        $header = pack('vv', $record, $length);
2174
        $data = pack('v', 1);
2175
2176
        $this->append($header . $data);
2177
    }
2178
2179
    /**
2180
     * Write the worksheet PASSWORD record.
2181
     */
2182 39
    private function writePassword()
2183
    {
2184
        // Exit unless sheet protection and password have been specified
2185 39
        if (!$this->phpSheet->getProtection()->getSheet() || !$this->phpSheet->getProtection()->getPassword()) {
2186 38
            return;
2187
        }
2188
2189 1
        $record = 0x0013; // Record identifier
2190 1
        $length = 0x0002; // Bytes to follow
2191
2192 1
        $wPassword = hexdec($this->phpSheet->getProtection()->getPassword()); // Encoded password
2193
2194 1
        $header = pack('vv', $record, $length);
2195 1
        $data = pack('v', $wPassword);
2196
2197 1
        $this->append($header . $data);
2198 1
    }
2199
2200
    /**
2201
     * Insert a 24bit bitmap image in a worksheet.
2202
     *
2203
     * @param int $row The row we are going to insert the bitmap into
2204
     * @param int $col The column we are going to insert the bitmap into
2205
     * @param mixed $bitmap The bitmap filename or GD-image resource
2206
     * @param int $x the horizontal position (offset) of the image inside the cell
2207
     * @param int $y the vertical position (offset) of the image inside the cell
2208
     * @param float $scale_x The horizontal scale
2209
     * @param float $scale_y The vertical scale
2210
     */
2211
    public function insertBitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1)
2212
    {
2213
        $bitmap_array = (is_resource($bitmap) ? $this->processBitmapGd($bitmap) : $this->processBitmap($bitmap));
2214
        list($width, $height, $size, $data) = $bitmap_array;
2215
2216
        // Scale the frame of the image.
2217
        $width *= $scale_x;
2218
        $height *= $scale_y;
2219
2220
        // Calculate the vertices of the image and write the OBJ record
2221
        $this->positionImage($col, $row, $x, $y, $width, $height);
2222
2223
        // Write the IMDATA record to store the bitmap data
2224
        $record = 0x007f;
2225
        $length = 8 + $size;
2226
        $cf = 0x09;
2227
        $env = 0x01;
2228
        $lcb = $size;
2229
2230
        $header = pack('vvvvV', $record, $length, $cf, $env, $lcb);
2231
        $this->append($header . $data);
2232
    }
2233
2234
    /**
2235
     * Calculate the vertices that define the position of the image as required by
2236
     * the OBJ record.
2237
     *
2238
     *         +------------+------------+
2239
     *         |     A      |      B     |
2240
     *   +-----+------------+------------+
2241
     *   |     |(x1,y1)     |            |
2242
     *   |  1  |(A1)._______|______      |
2243
     *   |     |    |              |     |
2244
     *   |     |    |              |     |
2245
     *   +-----+----|    BITMAP    |-----+
2246
     *   |     |    |              |     |
2247
     *   |  2  |    |______________.     |
2248
     *   |     |            |        (B2)|
2249
     *   |     |            |     (x2,y2)|
2250
     *   +---- +------------+------------+
2251
     *
2252
     * Example of a bitmap that covers some of the area from cell A1 to cell B2.
2253
     *
2254
     * Based on the width and height of the bitmap we need to calculate 8 vars:
2255
     *     $col_start, $row_start, $col_end, $row_end, $x1, $y1, $x2, $y2.
2256
     * The width and height of the cells are also variable and have to be taken into
2257
     * account.
2258
     * The values of $col_start and $row_start are passed in from the calling
2259
     * function. The values of $col_end and $row_end are calculated by subtracting
2260
     * the width and height of the bitmap from the width and height of the
2261
     * underlying cells.
2262
     * The vertices are expressed as a percentage of the underlying cell width as
2263
     * follows (rhs values are in pixels):
2264
     *
2265
     *       x1 = X / W *1024
2266
     *       y1 = Y / H *256
2267
     *       x2 = (X-1) / W *1024
2268
     *       y2 = (Y-1) / H *256
2269
     *
2270
     *       Where:  X is distance from the left side of the underlying cell
2271
     *               Y is distance from the top of the underlying cell
2272
     *               W is the width of the cell
2273
     *               H is the height of the cell
2274
     * The SDK incorrectly states that the height should be expressed as a
2275
     *        percentage of 1024.
2276
     *
2277
     * @param int $col_start Col containing upper left corner of object
2278
     * @param int $row_start Row containing top left corner of object
2279
     * @param int $x1 Distance to left side of object
2280
     * @param int $y1 Distance to top of object
2281
     * @param int $width Width of image frame
2282
     * @param int $height Height of image frame
2283
     */
2284
    public function positionImage($col_start, $row_start, $x1, $y1, $width, $height)
2285
    {
2286
        // Initialise end cell to the same as the start cell
2287
        $col_end = $col_start; // Col containing lower right corner of object
2288
        $row_end = $row_start; // Row containing bottom right corner of object
2289
2290
        // Zero the specified offset if greater than the cell dimensions
2291
        if ($x1 >= Xls::sizeCol($this->phpSheet, Coordinate::stringFromColumnIndex($col_start + 1))) {
2292
            $x1 = 0;
2293
        }
2294
        if ($y1 >= Xls::sizeRow($this->phpSheet, $row_start + 1)) {
2295
            $y1 = 0;
2296
        }
2297
2298
        $width = $width + $x1 - 1;
2299
        $height = $height + $y1 - 1;
2300
2301
        // Subtract the underlying cell widths to find the end cell of the image
2302
        while ($width >= Xls::sizeCol($this->phpSheet, Coordinate::stringFromColumnIndex($col_end + 1))) {
2303
            $width -= Xls::sizeCol($this->phpSheet, Coordinate::stringFromColumnIndex($col_end + 1));
2304
            ++$col_end;
2305
        }
2306
2307
        // Subtract the underlying cell heights to find the end cell of the image
2308
        while ($height >= Xls::sizeRow($this->phpSheet, $row_end + 1)) {
2309
            $height -= Xls::sizeRow($this->phpSheet, $row_end + 1);
2310
            ++$row_end;
2311
        }
2312
2313
        // Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell
2314
        // with zero eight or width.
2315
        //
2316
        if (Xls::sizeCol($this->phpSheet, Coordinate::stringFromColumnIndex($col_start + 1)) == 0) {
2317
            return;
2318
        }
2319
        if (Xls::sizeCol($this->phpSheet, Coordinate::stringFromColumnIndex($col_end + 1)) == 0) {
2320
            return;
2321
        }
2322
        if (Xls::sizeRow($this->phpSheet, $row_start + 1) == 0) {
2323
            return;
2324
        }
2325
        if (Xls::sizeRow($this->phpSheet, $row_end + 1) == 0) {
2326
            return;
2327
        }
2328
2329
        // Convert the pixel values to the percentage value expected by Excel
2330
        $x1 = $x1 / Xls::sizeCol($this->phpSheet, Coordinate::stringFromColumnIndex($col_start + 1)) * 1024;
2331
        $y1 = $y1 / Xls::sizeRow($this->phpSheet, $row_start + 1) * 256;
2332
        $x2 = $width / Xls::sizeCol($this->phpSheet, Coordinate::stringFromColumnIndex($col_end + 1)) * 1024; // Distance to right side of object
2333
        $y2 = $height / Xls::sizeRow($this->phpSheet, $row_end + 1) * 256; // Distance to bottom of object
2334
2335
        $this->writeObjPicture($col_start, $x1, $row_start, $y1, $col_end, $x2, $row_end, $y2);
2336
    }
2337
2338
    /**
2339
     * Store the OBJ record that precedes an IMDATA record. This could be generalise
2340
     * to support other Excel objects.
2341
     *
2342
     * @param int $colL Column containing upper left corner of object
2343
     * @param int $dxL Distance from left side of cell
2344
     * @param int $rwT Row containing top left corner of object
2345
     * @param int $dyT Distance from top of cell
2346
     * @param int $colR Column containing lower right corner of object
2347
     * @param int $dxR Distance from right of cell
2348
     * @param int $rwB Row containing bottom right corner of object
2349
     * @param int $dyB Distance from bottom of cell
2350
     */
2351
    private function writeObjPicture($colL, $dxL, $rwT, $dyT, $colR, $dxR, $rwB, $dyB)
2352
    {
2353
        $record = 0x005d; // Record identifier
2354
        $length = 0x003c; // Bytes to follow
2355
2356
        $cObj = 0x0001; // Count of objects in file (set to 1)
2357
        $OT = 0x0008; // Object type. 8 = Picture
2358
        $id = 0x0001; // Object ID
2359
        $grbit = 0x0614; // Option flags
2360
2361
        $cbMacro = 0x0000; // Length of FMLA structure
2362
        $Reserved1 = 0x0000; // Reserved
2363
        $Reserved2 = 0x0000; // Reserved
2364
2365
        $icvBack = 0x09; // Background colour
2366
        $icvFore = 0x09; // Foreground colour
2367
        $fls = 0x00; // Fill pattern
2368
        $fAuto = 0x00; // Automatic fill
2369
        $icv = 0x08; // Line colour
2370
        $lns = 0xff; // Line style
2371
        $lnw = 0x01; // Line weight
2372
        $fAutoB = 0x00; // Automatic border
2373
        $frs = 0x0000; // Frame style
2374
        $cf = 0x0009; // Image format, 9 = bitmap
2375
        $Reserved3 = 0x0000; // Reserved
2376
        $cbPictFmla = 0x0000; // Length of FMLA structure
2377
        $Reserved4 = 0x0000; // Reserved
2378
        $grbit2 = 0x0001; // Option flags
2379
        $Reserved5 = 0x0000; // Reserved
2380
2381
        $header = pack('vv', $record, $length);
2382
        $data = pack('V', $cObj);
2383
        $data .= pack('v', $OT);
2384
        $data .= pack('v', $id);
2385
        $data .= pack('v', $grbit);
2386
        $data .= pack('v', $colL);
2387
        $data .= pack('v', $dxL);
2388
        $data .= pack('v', $rwT);
2389
        $data .= pack('v', $dyT);
2390
        $data .= pack('v', $colR);
2391
        $data .= pack('v', $dxR);
2392
        $data .= pack('v', $rwB);
2393
        $data .= pack('v', $dyB);
2394
        $data .= pack('v', $cbMacro);
2395
        $data .= pack('V', $Reserved1);
2396
        $data .= pack('v', $Reserved2);
2397
        $data .= pack('C', $icvBack);
2398
        $data .= pack('C', $icvFore);
2399
        $data .= pack('C', $fls);
2400
        $data .= pack('C', $fAuto);
2401
        $data .= pack('C', $icv);
2402
        $data .= pack('C', $lns);
2403
        $data .= pack('C', $lnw);
2404
        $data .= pack('C', $fAutoB);
2405
        $data .= pack('v', $frs);
2406
        $data .= pack('V', $cf);
2407
        $data .= pack('v', $Reserved3);
2408
        $data .= pack('v', $cbPictFmla);
2409
        $data .= pack('v', $Reserved4);
2410
        $data .= pack('v', $grbit2);
2411
        $data .= pack('V', $Reserved5);
2412
2413
        $this->append($header . $data);
2414
    }
2415
2416
    /**
2417
     * Convert a GD-image into the internal format.
2418
     *
2419
     * @param resource $image The image to process
2420
     *
2421
     * @return array Array with data and properties of the bitmap
2422
     */
2423
    public function processBitmapGd($image)
2424
    {
2425
        $width = imagesx($image);
2426
        $height = imagesy($image);
2427
2428
        $data = pack('Vvvvv', 0x000c, $width, $height, 0x01, 0x18);
2429
        for ($j = $height; --$j;) {
2430
            for ($i = 0; $i < $width; ++$i) {
2431
                $color = imagecolorsforindex($image, imagecolorat($image, $i, $j));
2432
                foreach (['red', 'green', 'blue'] as $key) {
2433
                    $color[$key] = $color[$key] + round((255 - $color[$key]) * $color['alpha'] / 127);
2434
                }
2435
                $data .= chr($color['blue']) . chr($color['green']) . chr($color['red']);
2436
            }
2437
            if (3 * $width % 4) {
2438
                $data .= str_repeat("\x00", 4 - 3 * $width % 4);
2439
            }
2440
        }
2441
2442
        return [$width, $height, strlen($data), $data];
2443
    }
2444
2445
    /**
2446
     * Convert a 24 bit bitmap into the modified internal format used by Windows.
2447
     * This is described in BITMAPCOREHEADER and BITMAPCOREINFO structures in the
2448
     * MSDN library.
2449
     *
2450
     * @param string $bitmap The bitmap to process
2451
     *
2452
     * @return array Array with data and properties of the bitmap
2453
     */
2454
    public function processBitmap($bitmap)
2455
    {
2456
        // Open file.
2457
        $bmp_fd = @fopen($bitmap, 'rb');
2458
        if (!$bmp_fd) {
2459
            throw new WriterException("Couldn't import $bitmap");
2460
        }
2461
2462
        // Slurp the file into a string.
2463
        $data = fread($bmp_fd, filesize($bitmap));
2464
2465
        // Check that the file is big enough to be a bitmap.
2466
        if (strlen($data) <= 0x36) {
2467
            throw new WriterException("$bitmap doesn't contain enough data.\n");
2468
        }
2469
2470
        // The first 2 bytes are used to identify the bitmap.
2471
        $identity = unpack('A2ident', $data);
2472
        if ($identity['ident'] != 'BM') {
2473
            throw new WriterException("$bitmap doesn't appear to be a valid bitmap image.\n");
2474
        }
2475
2476
        // Remove bitmap data: ID.
2477
        $data = substr($data, 2);
2478
2479
        // Read and remove the bitmap size. This is more reliable than reading
2480
        // the data size at offset 0x22.
2481
        //
2482
        $size_array = unpack('Vsa', substr($data, 0, 4));
2483
        $size = $size_array['sa'];
2484
        $data = substr($data, 4);
2485
        $size -= 0x36; // Subtract size of bitmap header.
2486
        $size += 0x0C; // Add size of BIFF header.
2487
2488
        // Remove bitmap data: reserved, offset, header length.
2489
        $data = substr($data, 12);
2490
2491
        // Read and remove the bitmap width and height. Verify the sizes.
2492
        $width_and_height = unpack('V2', substr($data, 0, 8));
2493
        $width = $width_and_height[1];
2494
        $height = $width_and_height[2];
2495
        $data = substr($data, 8);
2496
        if ($width > 0xFFFF) {
2497
            throw new WriterException("$bitmap: largest image width supported is 65k.\n");
2498
        }
2499
        if ($height > 0xFFFF) {
2500
            throw new WriterException("$bitmap: largest image height supported is 65k.\n");
2501
        }
2502
2503
        // Read and remove the bitmap planes and bpp data. Verify them.
2504
        $planes_and_bitcount = unpack('v2', substr($data, 0, 4));
2505
        $data = substr($data, 4);
2506
        if ($planes_and_bitcount[2] != 24) { // Bitcount
2507
            throw new WriterException("$bitmap isn't a 24bit true color bitmap.\n");
2508
        }
2509
        if ($planes_and_bitcount[1] != 1) {
2510
            throw new WriterException("$bitmap: only 1 plane supported in bitmap image.\n");
2511
        }
2512
2513
        // Read and remove the bitmap compression. Verify compression.
2514
        $compression = unpack('Vcomp', substr($data, 0, 4));
2515
        $data = substr($data, 4);
2516
2517
        if ($compression['comp'] != 0) {
2518
            throw new WriterException("$bitmap: compression not supported in bitmap image.\n");
2519
        }
2520
2521
        // Remove bitmap data: data size, hres, vres, colours, imp. colours.
2522
        $data = substr($data, 20);
2523
2524
        // Add the BITMAPCOREHEADER data
2525
        $header = pack('Vvvvv', 0x000c, $width, $height, 0x01, 0x18);
2526
        $data = $header . $data;
2527
2528
        return [$width, $height, $size, $data];
2529
    }
2530
2531
    /**
2532
     * Store the window zoom factor. This should be a reduced fraction but for
2533
     * simplicity we will store all fractions with a numerator of 100.
2534
     */
2535 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...
2536
    {
2537
        // If scale is 100 we don't need to write a record
2538 39
        if ($this->phpSheet->getSheetView()->getZoomScale() == 100) {
2539 39
            return;
2540
        }
2541
2542
        $record = 0x00A0; // Record identifier
2543
        $length = 0x0004; // Bytes to follow
2544
2545
        $header = pack('vv', $record, $length);
2546
        $data = pack('vv', $this->phpSheet->getSheetView()->getZoomScale(), 100);
2547
        $this->append($header . $data);
2548
    }
2549
2550
    /**
2551
     * Get Escher object.
2552
     *
2553
     * @return \PhpOffice\PhpSpreadsheet\Shared\Escher
2554
     */
2555
    public function getEscher()
2556
    {
2557
        return $this->escher;
2558
    }
2559
2560
    /**
2561
     * Set Escher object.
2562
     *
2563
     * @param \PhpOffice\PhpSpreadsheet\Shared\Escher $pValue
2564
     */
2565 10
    public function setEscher(\PhpOffice\PhpSpreadsheet\Shared\Escher $pValue = null)
2566
    {
2567 10
        $this->escher = $pValue;
2568 10
    }
2569
2570
    /**
2571
     * Write MSODRAWING record.
2572
     */
2573 39
    private function writeMsoDrawing()
2574
    {
2575
        // write the Escher stream if necessary
2576 39
        if (isset($this->escher)) {
2577 10
            $writer = new Escher($this->escher);
2578 10
            $data = $writer->close();
2579 10
            $spOffsets = $writer->getSpOffsets();
2580 10
            $spTypes = $writer->getSpTypes();
2581
            // write the neccesary MSODRAWING, OBJ records
2582
2583
            // split the Escher stream
2584 10
            $spOffsets[0] = 0;
2585 10
            $nm = count($spOffsets) - 1; // number of shapes excluding first shape
2586 10
            for ($i = 1; $i <= $nm; ++$i) {
2587
                // MSODRAWING record
2588 10
                $record = 0x00EC; // Record identifier
2589
2590
                // chunk of Escher stream for one shape
2591 10
                $dataChunk = substr($data, $spOffsets[$i - 1], $spOffsets[$i] - $spOffsets[$i - 1]);
2592
2593 10
                $length = strlen($dataChunk);
2594 10
                $header = pack('vv', $record, $length);
2595
2596 10
                $this->append($header . $dataChunk);
2597
2598
                // OBJ record
2599 10
                $record = 0x005D; // record identifier
2600 10
                $objData = '';
2601
2602
                // ftCmo
2603 10
                if ($spTypes[$i] == 0x00C9) {
2604
                    // Add ftCmo (common object data) subobject
2605
                    $objData .=
2606 3
                        pack(
2607 3
                            'vvvvvVVV',
2608 3
                            0x0015, // 0x0015 = ftCmo
2609 3
                            0x0012, // length of ftCmo data
2610 3
                            0x0014, // object type, 0x0014 = filter
2611 3
                            $i, // object id number, Excel seems to use 1-based index, local for the sheet
2612 3
                            0x2101, // option flags, 0x2001 is what OpenOffice.org uses
2613 3
                            0, // reserved
2614 3
                            0, // reserved
2615 3
                            0  // reserved
2616
                        );
2617
2618
                    // Add ftSbs Scroll bar subobject
2619 3
                    $objData .= pack('vv', 0x00C, 0x0014);
2620 3
                    $objData .= pack('H*', '0000000000000000640001000A00000010000100');
2621
                    // Add ftLbsData (List box data) subobject
2622 3
                    $objData .= pack('vv', 0x0013, 0x1FEE);
2623 3
                    $objData .= pack('H*', '00000000010001030000020008005700');
2624
                } else {
2625
                    // Add ftCmo (common object data) subobject
2626
                    $objData .=
2627 7
                        pack(
2628 7
                            'vvvvvVVV',
2629 7
                            0x0015, // 0x0015 = ftCmo
2630 7
                            0x0012, // length of ftCmo data
2631 7
                            0x0008, // object type, 0x0008 = picture
2632 7
                            $i, // object id number, Excel seems to use 1-based index, local for the sheet
2633 7
                            0x6011, // option flags, 0x6011 is what OpenOffice.org uses
2634 7
                            0, // reserved
2635 7
                            0, // reserved
2636 7
                            0  // reserved
2637
                        );
2638
                }
2639
2640
                // ftEnd
2641
                $objData .=
2642 10
                    pack(
2643 10
                        'vv',
2644 10
                        0x0000, // 0x0000 = ftEnd
2645 10
                        0x0000  // length of ftEnd data
2646
                    );
2647
2648 10
                $length = strlen($objData);
2649 10
                $header = pack('vv', $record, $length);
2650 10
                $this->append($header . $objData);
2651
            }
2652
        }
2653 39
    }
2654
2655
    /**
2656
     * Store the DATAVALIDATIONS and DATAVALIDATION records.
2657
     *
2658
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
2659
     */
2660 39
    private function writeDataValidity()
2661
    {
2662
        // Datavalidation collection
2663 39
        $dataValidationCollection = $this->phpSheet->getDataValidationCollection();
2664
2665
        // Write data validations?
2666 39
        if (!empty($dataValidationCollection)) {
2667
            // DATAVALIDATIONS record
2668 2
            $record = 0x01B2; // Record identifier
2669 2
            $length = 0x0012; // Bytes to follow
2670
2671 2
            $grbit = 0x0000; // Prompt box at cell, no cached validity data at DV records
2672 2
            $horPos = 0x00000000; // Horizontal position of prompt box, if fixed position
2673 2
            $verPos = 0x00000000; // Vertical position of prompt box, if fixed position
2674 2
            $objId = 0xFFFFFFFF; // Object identifier of drop down arrow object, or -1 if not visible
2675
2676 2
            $header = pack('vv', $record, $length);
2677 2
            $data = pack('vVVVV', $grbit, $horPos, $verPos, $objId, count($dataValidationCollection));
2678 2
            $this->append($header . $data);
2679
2680
            // DATAVALIDATION records
2681 2
            $record = 0x01BE; // Record identifier
2682
2683 2
            foreach ($dataValidationCollection as $cellCoordinate => $dataValidation) {
2684
                // initialize record data
2685 2
                $data = '';
2686
2687
                // options
2688 2
                $options = 0x00000000;
2689
2690
                // data type
2691 2
                $type = 0x00;
2692 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...
2693 2
                    case DataValidation::TYPE_NONE:
2694
                        $type = 0x00;
2695
2696
                        break;
2697 2
                    case DataValidation::TYPE_WHOLE:
2698 1
                        $type = 0x01;
2699
2700 1
                        break;
2701 2
                    case DataValidation::TYPE_DECIMAL:
2702
                        $type = 0x02;
2703
2704
                        break;
2705 2
                    case DataValidation::TYPE_LIST:
2706 2
                        $type = 0x03;
2707
2708 2
                        break;
2709
                    case DataValidation::TYPE_DATE:
2710
                        $type = 0x04;
2711
2712
                        break;
2713
                    case DataValidation::TYPE_TIME:
2714
                        $type = 0x05;
2715
2716
                        break;
2717
                    case DataValidation::TYPE_TEXTLENGTH:
2718
                        $type = 0x06;
2719
2720
                        break;
2721
                    case DataValidation::TYPE_CUSTOM:
2722
                        $type = 0x07;
2723
2724
                        break;
2725
                }
2726
2727 2
                $options |= $type << 0;
2728
2729
                // error style
2730 2
                $errorStyle = 0x00;
2731 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...
2732 2
                    case DataValidation::STYLE_STOP:
2733 1
                        $errorStyle = 0x00;
2734
2735 1
                        break;
2736 2
                    case DataValidation::STYLE_WARNING:
2737
                        $errorStyle = 0x01;
2738
2739
                        break;
2740 2
                    case DataValidation::STYLE_INFORMATION:
2741 2
                        $errorStyle = 0x02;
2742
2743 2
                        break;
2744
                }
2745
2746 2
                $options |= $errorStyle << 4;
2747
2748
                // explicit formula?
2749 2
                if ($type == 0x03 && preg_match('/^\".*\"$/', $dataValidation->getFormula1())) {
2750 1
                    $options |= 0x01 << 7;
2751
                }
2752
2753
                // empty cells allowed
2754 2
                $options |= $dataValidation->getAllowBlank() << 8;
2755
2756
                // show drop down
2757 2
                $options |= (!$dataValidation->getShowDropDown()) << 9;
2758
2759
                // show input message
2760 2
                $options |= $dataValidation->getShowInputMessage() << 18;
2761
2762
                // show error message
2763 2
                $options |= $dataValidation->getShowErrorMessage() << 19;
2764
2765
                // condition operator
2766 2
                $operator = 0x00;
2767 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...
2768 2
                    case DataValidation::OPERATOR_BETWEEN:
2769 2
                        $operator = 0x00;
2770
2771 2
                        break;
2772
                    case DataValidation::OPERATOR_NOTBETWEEN:
2773
                        $operator = 0x01;
2774
2775
                        break;
2776
                    case DataValidation::OPERATOR_EQUAL:
2777
                        $operator = 0x02;
2778
2779
                        break;
2780
                    case DataValidation::OPERATOR_NOTEQUAL:
2781
                        $operator = 0x03;
2782
2783
                        break;
2784
                    case DataValidation::OPERATOR_GREATERTHAN:
2785
                        $operator = 0x04;
2786
2787
                        break;
2788
                    case DataValidation::OPERATOR_LESSTHAN:
2789
                        $operator = 0x05;
2790
2791
                        break;
2792
                    case DataValidation::OPERATOR_GREATERTHANOREQUAL:
2793
                        $operator = 0x06;
2794
2795
                        break;
2796
                    case DataValidation::OPERATOR_LESSTHANOREQUAL:
2797
                        $operator = 0x07;
2798
2799
                        break;
2800
                }
2801
2802 2
                $options |= $operator << 20;
2803
2804 2
                $data = pack('V', $options);
2805
2806
                // prompt title
2807 2
                $promptTitle = $dataValidation->getPromptTitle() !== '' ?
2808 2
                    $dataValidation->getPromptTitle() : chr(0);
2809 2
                $data .= StringHelper::UTF8toBIFF8UnicodeLong($promptTitle);
2810
2811
                // error title
2812 2
                $errorTitle = $dataValidation->getErrorTitle() !== '' ?
2813 2
                    $dataValidation->getErrorTitle() : chr(0);
2814 2
                $data .= StringHelper::UTF8toBIFF8UnicodeLong($errorTitle);
2815
2816
                // prompt text
2817 2
                $prompt = $dataValidation->getPrompt() !== '' ?
2818 2
                    $dataValidation->getPrompt() : chr(0);
2819 2
                $data .= StringHelper::UTF8toBIFF8UnicodeLong($prompt);
2820
2821
                // error text
2822 2
                $error = $dataValidation->getError() !== '' ?
2823 2
                    $dataValidation->getError() : chr(0);
2824 2
                $data .= StringHelper::UTF8toBIFF8UnicodeLong($error);
2825
2826
                // formula 1
2827
                try {
2828 2
                    $formula1 = $dataValidation->getFormula1();
2829 2
                    if ($type == 0x03) { // list type
2830 2
                        $formula1 = str_replace(',', chr(0), $formula1);
2831
                    }
2832 2
                    $this->parser->parse($formula1);
2833 1
                    $formula1 = $this->parser->toReversePolish();
2834 1
                    $sz1 = strlen($formula1);
2835 2
                } catch (PhpSpreadsheetException $e) {
2836 2
                    $sz1 = 0;
2837 2
                    $formula1 = '';
2838
                }
2839 2
                $data .= pack('vv', $sz1, 0x0000);
2840 2
                $data .= $formula1;
2841
2842
                // formula 2
2843
                try {
2844 2
                    $formula2 = $dataValidation->getFormula2();
2845 2
                    if ($formula2 === '') {
2846 2
                        throw new WriterException('No formula2');
2847
                    }
2848 1
                    $this->parser->parse($formula2);
2849
                    $formula2 = $this->parser->toReversePolish();
2850
                    $sz2 = strlen($formula2);
2851 2
                } catch (PhpSpreadsheetException $e) {
2852 2
                    $sz2 = 0;
2853 2
                    $formula2 = '';
2854
                }
2855 2
                $data .= pack('vv', $sz2, 0x0000);
2856 2
                $data .= $formula2;
2857
2858
                // cell range address list
2859 2
                $data .= pack('v', 0x0001);
2860 2
                $data .= $this->writeBIFF8CellRangeAddressFixed($cellCoordinate);
2861
2862 2
                $length = strlen($data);
2863 2
                $header = pack('vv', $record, $length);
2864
2865 2
                $this->append($header . $data);
2866
            }
2867
        }
2868 39
    }
2869
2870
    /**
2871
     * Map Error code.
2872
     *
2873
     * @param string $errorCode
2874
     *
2875
     * @return int
2876
     */
2877 4
    private static function mapErrorCode($errorCode)
2878
    {
2879
        switch ($errorCode) {
2880 4
            case '#NULL!':
2881
                return 0x00;
2882 4
            case '#DIV/0!':
2883 3
                return 0x07;
2884 2
            case '#VALUE!':
2885 1
                return 0x0F;
2886 1
            case '#REF!':
2887
                return 0x17;
2888 1
            case '#NAME?':
2889
                return 0x1D;
2890 1
            case '#NUM!':
2891
                return 0x24;
2892 1
            case '#N/A':
2893 1
                return 0x2A;
2894
        }
2895
2896
        return 0;
2897
    }
2898
2899
    /**
2900
     * Write PLV Record.
2901
     */
2902 39
    private function writePageLayoutView()
2903
    {
2904 39
        $record = 0x088B; // Record identifier
2905 39
        $length = 0x0010; // Bytes to follow
2906
2907 39
        $rt = 0x088B; // 2
2908 39
        $grbitFrt = 0x0000; // 2
2909 39
        $reserved = 0x0000000000000000; // 8
2910 39
        $wScalvePLV = $this->phpSheet->getSheetView()->getZoomScale(); // 2
2911
2912
        // The options flags that comprise $grbit
2913 39
        if ($this->phpSheet->getSheetView()->getView() == SheetView::SHEETVIEW_PAGE_LAYOUT) {
2914 1
            $fPageLayoutView = 1;
2915
        } else {
2916 38
            $fPageLayoutView = 0;
2917
        }
2918 39
        $fRulerVisible = 0;
2919 39
        $fWhitespaceHidden = 0;
2920
2921 39
        $grbit = $fPageLayoutView; // 2
2922 39
        $grbit |= $fRulerVisible << 1;
2923 39
        $grbit |= $fWhitespaceHidden << 3;
2924
2925 39
        $header = pack('vv', $record, $length);
2926 39
        $data = pack('vvVVvv', $rt, $grbitFrt, 0x00000000, 0x00000000, $wScalvePLV, $grbit);
2927 39
        $this->append($header . $data);
2928 39
    }
2929
2930
    /**
2931
     * Write CFRule Record.
2932
     *
2933
     * @param Conditional $conditional
2934
     */
2935 2
    private function writeCFRule(Conditional $conditional)
2936
    {
2937 2
        $record = 0x01B1; // Record identifier
2938
2939
        // $type : Type of the CF
2940
        // $operatorType : Comparison operator
2941 2
        if ($conditional->getConditionType() == Conditional::CONDITION_EXPRESSION) {
2942
            $type = 0x02;
2943
            $operatorType = 0x00;
2944 2
        } elseif ($conditional->getConditionType() == Conditional::CONDITION_CELLIS) {
2945 2
            $type = 0x01;
2946
2947 2
            switch ($conditional->getOperatorType()) {
2948 2
                case Conditional::OPERATOR_NONE:
2949
                    $operatorType = 0x00;
2950
2951
                    break;
2952 2
                case Conditional::OPERATOR_EQUAL:
2953
                    $operatorType = 0x03;
2954
2955
                    break;
2956 2
                case Conditional::OPERATOR_GREATERTHAN:
2957
                    $operatorType = 0x05;
2958
2959
                    break;
2960 2
                case Conditional::OPERATOR_GREATERTHANOREQUAL:
2961 2
                    $operatorType = 0x07;
2962
2963 2
                    break;
2964 2
                case Conditional::OPERATOR_LESSTHAN:
2965 2
                    $operatorType = 0x06;
2966
2967 2
                    break;
2968 1
                case Conditional::OPERATOR_LESSTHANOREQUAL:
2969
                    $operatorType = 0x08;
2970
2971
                    break;
2972 1
                case Conditional::OPERATOR_NOTEQUAL:
2973
                    $operatorType = 0x04;
2974
2975
                    break;
2976 1
                case Conditional::OPERATOR_BETWEEN:
2977 1
                    $operatorType = 0x01;
2978
2979 1
                    break;
2980
                    // not OPERATOR_NOTBETWEEN 0x02
2981
            }
2982
        }
2983
2984
        // $szValue1 : size of the formula data for first value or formula
2985
        // $szValue2 : size of the formula data for second value or formula
2986 2
        $arrConditions = $conditional->getConditions();
2987 2
        $numConditions = count($arrConditions);
2988 2
        if ($numConditions == 1) {
2989 2
            $szValue1 = ($arrConditions[0] <= 65535 ? 3 : 0x0000);
2990 2
            $szValue2 = 0x0000;
2991 2
            $operand1 = pack('Cv', 0x1E, $arrConditions[0]);
2992 2
            $operand2 = null;
2993 1
        } elseif ($numConditions == 2 && ($conditional->getOperatorType() == Conditional::OPERATOR_BETWEEN)) {
2994 1
            $szValue1 = ($arrConditions[0] <= 65535 ? 3 : 0x0000);
2995 1
            $szValue2 = ($arrConditions[1] <= 65535 ? 3 : 0x0000);
2996 1
            $operand1 = pack('Cv', 0x1E, $arrConditions[0]);
2997 1
            $operand2 = pack('Cv', 0x1E, $arrConditions[1]);
2998
        } else {
2999
            $szValue1 = 0x0000;
3000
            $szValue2 = 0x0000;
3001
            $operand1 = null;
3002
            $operand2 = null;
3003
        }
3004
3005
        // $flags : Option flags
3006
        // Alignment
3007 2
        $bAlignHz = ($conditional->getStyle()->getAlignment()->getHorizontal() == null ? 1 : 0);
3008 2
        $bAlignVt = ($conditional->getStyle()->getAlignment()->getVertical() == null ? 1 : 0);
3009 2
        $bAlignWrapTx = ($conditional->getStyle()->getAlignment()->getWrapText() == false ? 1 : 0);
3010 2
        $bTxRotation = ($conditional->getStyle()->getAlignment()->getTextRotation() == null ? 1 : 0);
3011 2
        $bIndent = ($conditional->getStyle()->getAlignment()->getIndent() == 0 ? 1 : 0);
3012 2
        $bShrinkToFit = ($conditional->getStyle()->getAlignment()->getShrinkToFit() == false ? 1 : 0);
3013 2
        if ($bAlignHz == 0 || $bAlignVt == 0 || $bAlignWrapTx == 0 || $bTxRotation == 0 || $bIndent == 0 || $bShrinkToFit == 0) {
3014
            $bFormatAlign = 1;
3015
        } else {
3016 2
            $bFormatAlign = 0;
3017
        }
3018
        // Protection
3019 2
        $bProtLocked = ($conditional->getStyle()->getProtection()->getLocked() == null ? 1 : 0);
3020 2
        $bProtHidden = ($conditional->getStyle()->getProtection()->getHidden() == null ? 1 : 0);
3021 2
        if ($bProtLocked == 0 || $bProtHidden == 0) {
3022
            $bFormatProt = 1;
3023
        } else {
3024 2
            $bFormatProt = 0;
3025
        }
3026
        // Border
3027 2
        $bBorderLeft = ($conditional->getStyle()->getBorders()->getLeft()->getColor()->getARGB() == Color::COLOR_BLACK
3028 2
                        && $conditional->getStyle()->getBorders()->getLeft()->getBorderStyle() == Border::BORDER_NONE ? 1 : 0);
3029 2
        $bBorderRight = ($conditional->getStyle()->getBorders()->getRight()->getColor()->getARGB() == Color::COLOR_BLACK
3030 2
                        && $conditional->getStyle()->getBorders()->getRight()->getBorderStyle() == Border::BORDER_NONE ? 1 : 0);
3031 2
        $bBorderTop = ($conditional->getStyle()->getBorders()->getTop()->getColor()->getARGB() == Color::COLOR_BLACK
3032 2
                        && $conditional->getStyle()->getBorders()->getTop()->getBorderStyle() == Border::BORDER_NONE ? 1 : 0);
3033 2
        $bBorderBottom = ($conditional->getStyle()->getBorders()->getBottom()->getColor()->getARGB() == Color::COLOR_BLACK
3034 2
                        && $conditional->getStyle()->getBorders()->getBottom()->getBorderStyle() == Border::BORDER_NONE ? 1 : 0);
3035 2
        if ($bBorderLeft == 0 || $bBorderRight == 0 || $bBorderTop == 0 || $bBorderBottom == 0) {
3036
            $bFormatBorder = 1;
3037
        } else {
3038 2
            $bFormatBorder = 0;
3039
        }
3040
        // Pattern
3041 2
        $bFillStyle = ($conditional->getStyle()->getFill()->getFillType() == null ? 0 : 1);
3042 2
        $bFillColor = ($conditional->getStyle()->getFill()->getStartColor()->getARGB() == null ? 0 : 1);
3043 2
        $bFillColorBg = ($conditional->getStyle()->getFill()->getEndColor()->getARGB() == null ? 0 : 1);
3044 2
        if ($bFillStyle == 0 || $bFillColor == 0 || $bFillColorBg == 0) {
3045 2
            $bFormatFill = 1;
3046
        } else {
3047
            $bFormatFill = 0;
3048
        }
3049
        // Font
3050 2
        if ($conditional->getStyle()->getFont()->getName() != null
3051 2
            || $conditional->getStyle()->getFont()->getSize() != null
3052 2
            || $conditional->getStyle()->getFont()->getBold() != null
3053 2
            || $conditional->getStyle()->getFont()->getItalic() != null
3054 1
            || $conditional->getStyle()->getFont()->getSuperscript() != null
3055 1
            || $conditional->getStyle()->getFont()->getSubscript() != null
3056 1
            || $conditional->getStyle()->getFont()->getUnderline() != null
3057 1
            || $conditional->getStyle()->getFont()->getStrikethrough() != null
3058 2
            || $conditional->getStyle()->getFont()->getColor()->getARGB() != null) {
3059 2
            $bFormatFont = 1;
3060
        } else {
3061
            $bFormatFont = 0;
3062
        }
3063
        // Alignment
3064 2
        $flags = 0;
3065 2
        $flags |= (1 == $bAlignHz ? 0x00000001 : 0);
3066 2
        $flags |= (1 == $bAlignVt ? 0x00000002 : 0);
3067 2
        $flags |= (1 == $bAlignWrapTx ? 0x00000004 : 0);
3068 2
        $flags |= (1 == $bTxRotation ? 0x00000008 : 0);
3069
        // Justify last line flag
3070 2
        $flags |= (1 == 1 ? 0x00000010 : 0);
3071 2
        $flags |= (1 == $bIndent ? 0x00000020 : 0);
3072 2
        $flags |= (1 == $bShrinkToFit ? 0x00000040 : 0);
3073
        // Default
3074 2
        $flags |= (1 == 1 ? 0x00000080 : 0);
3075
        // Protection
3076 2
        $flags |= (1 == $bProtLocked ? 0x00000100 : 0);
3077 2
        $flags |= (1 == $bProtHidden ? 0x00000200 : 0);
3078
        // Border
3079 2
        $flags |= (1 == $bBorderLeft ? 0x00000400 : 0);
3080 2
        $flags |= (1 == $bBorderRight ? 0x00000800 : 0);
3081 2
        $flags |= (1 == $bBorderTop ? 0x00001000 : 0);
3082 2
        $flags |= (1 == $bBorderBottom ? 0x00002000 : 0);
3083 2
        $flags |= (1 == 1 ? 0x00004000 : 0); // Top left to Bottom right border
3084 2
        $flags |= (1 == 1 ? 0x00008000 : 0); // Bottom left to Top right border
3085
        // Pattern
3086 2
        $flags |= (1 == $bFillStyle ? 0x00010000 : 0);
3087 2
        $flags |= (1 == $bFillColor ? 0x00020000 : 0);
3088 2
        $flags |= (1 == $bFillColorBg ? 0x00040000 : 0);
3089 2
        $flags |= (1 == 1 ? 0x00380000 : 0);
3090
        // Font
3091 2
        $flags |= (1 == $bFormatFont ? 0x04000000 : 0);
3092
        // Alignment:
3093 2
        $flags |= (1 == $bFormatAlign ? 0x08000000 : 0);
3094
        // Border
3095 2
        $flags |= (1 == $bFormatBorder ? 0x10000000 : 0);
3096
        // Pattern
3097 2
        $flags |= (1 == $bFormatFill ? 0x20000000 : 0);
3098
        // Protection
3099 2
        $flags |= (1 == $bFormatProt ? 0x40000000 : 0);
3100
        // Text direction
3101 2
        $flags |= (1 == 0 ? 0x80000000 : 0);
3102
3103
        // Data Blocks
3104 2
        if ($bFormatFont == 1) {
3105
            // Font Name
3106 2
            if ($conditional->getStyle()->getFont()->getName() == null) {
3107 2
                $dataBlockFont = pack('VVVVVVVV', 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
3108 2
                $dataBlockFont .= pack('VVVVVVVV', 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
3109
            } else {
3110
                $dataBlockFont = StringHelper::UTF8toBIFF8UnicodeLong($conditional->getStyle()->getFont()->getName());
3111
            }
3112
            // Font Size
3113 2
            if ($conditional->getStyle()->getFont()->getSize() == null) {
3114 2
                $dataBlockFont .= pack('V', 20 * 11);
3115
            } else {
3116
                $dataBlockFont .= pack('V', 20 * $conditional->getStyle()->getFont()->getSize());
3117
            }
3118
            // Font Options
3119 2
            $dataBlockFont .= pack('V', 0);
3120
            // Font weight
3121 2
            if ($conditional->getStyle()->getFont()->getBold() == true) {
3122 1
                $dataBlockFont .= pack('v', 0x02BC);
3123
            } else {
3124 2
                $dataBlockFont .= pack('v', 0x0190);
3125
            }
3126
            // Escapement type
3127 2
            if ($conditional->getStyle()->getFont()->getSubscript() == true) {
3128
                $dataBlockFont .= pack('v', 0x02);
3129
                $fontEscapement = 0;
3130 2
            } elseif ($conditional->getStyle()->getFont()->getSuperscript() == true) {
3131
                $dataBlockFont .= pack('v', 0x01);
3132
                $fontEscapement = 0;
3133
            } else {
3134 2
                $dataBlockFont .= pack('v', 0x00);
3135 2
                $fontEscapement = 1;
3136
            }
3137
            // Underline type
3138 2
            switch ($conditional->getStyle()->getFont()->getUnderline()) {
3139 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_NONE:
3140
                    $dataBlockFont .= pack('C', 0x00);
3141
                    $fontUnderline = 0;
3142
3143
                    break;
3144 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_DOUBLE:
3145
                    $dataBlockFont .= pack('C', 0x02);
3146
                    $fontUnderline = 0;
3147
3148
                    break;
3149 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_DOUBLEACCOUNTING:
3150
                    $dataBlockFont .= pack('C', 0x22);
3151
                    $fontUnderline = 0;
3152
3153
                    break;
3154 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_SINGLE:
3155
                    $dataBlockFont .= pack('C', 0x01);
3156
                    $fontUnderline = 0;
3157
3158
                    break;
3159 2
                case \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_SINGLEACCOUNTING:
3160
                    $dataBlockFont .= pack('C', 0x21);
3161
                    $fontUnderline = 0;
3162
3163
                    break;
3164
                default:
3165 2
                    $dataBlockFont .= pack('C', 0x00);
3166 2
                    $fontUnderline = 1;
3167
3168 2
                    break;
3169
            }
3170
            // 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...
3171 2
            $dataBlockFont .= pack('vC', 0x0000, 0x00);
3172
            // Font color index
3173 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...
3174 2
                case '000000':
3175
                    $colorIdx = 0x08;
3176
3177
                    break;
3178 2
                case 'FFFFFF':
3179
                    $colorIdx = 0x09;
3180
3181
                    break;
3182 2
                case 'FF0000':
3183 2
                    $colorIdx = 0x0A;
3184
3185 2
                    break;
3186 2
                case '00FF00':
3187 2
                    $colorIdx = 0x0B;
3188
3189 2
                    break;
3190 1
                case '0000FF':
3191
                    $colorIdx = 0x0C;
3192
3193
                    break;
3194 1
                case 'FFFF00':
3195 1
                    $colorIdx = 0x0D;
3196
3197 1
                    break;
3198
                case 'FF00FF':
3199
                    $colorIdx = 0x0E;
3200
3201
                    break;
3202
                case '00FFFF':
3203
                    $colorIdx = 0x0F;
3204
3205
                    break;
3206
                case '800000':
3207
                    $colorIdx = 0x10;
3208
3209
                    break;
3210
                case '008000':
3211
                    $colorIdx = 0x11;
3212
3213
                    break;
3214
                case '000080':
3215
                    $colorIdx = 0x12;
3216
3217
                    break;
3218
                case '808000':
3219
                    $colorIdx = 0x13;
3220
3221
                    break;
3222
                case '800080':
3223
                    $colorIdx = 0x14;
3224
3225
                    break;
3226
                case '008080':
3227
                    $colorIdx = 0x15;
3228
3229
                    break;
3230
                case 'C0C0C0':
3231
                    $colorIdx = 0x16;
3232
3233
                    break;
3234
                case '808080':
3235
                    $colorIdx = 0x17;
3236
3237
                    break;
3238
                case '9999FF':
3239
                    $colorIdx = 0x18;
3240
3241
                    break;
3242
                case '993366':
3243
                    $colorIdx = 0x19;
3244
3245
                    break;
3246
                case 'FFFFCC':
3247
                    $colorIdx = 0x1A;
3248
3249
                    break;
3250
                case 'CCFFFF':
3251
                    $colorIdx = 0x1B;
3252
3253
                    break;
3254
                case '660066':
3255
                    $colorIdx = 0x1C;
3256
3257
                    break;
3258
                case 'FF8080':
3259
                    $colorIdx = 0x1D;
3260
3261
                    break;
3262
                case '0066CC':
3263
                    $colorIdx = 0x1E;
3264
3265
                    break;
3266
                case 'CCCCFF':
3267
                    $colorIdx = 0x1F;
3268
3269
                    break;
3270
                case '000080':
3271
                    $colorIdx = 0x20;
3272
3273
                    break;
3274
                case 'FF00FF':
3275
                    $colorIdx = 0x21;
3276
3277
                    break;
3278
                case 'FFFF00':
3279
                    $colorIdx = 0x22;
3280
3281
                    break;
3282
                case '00FFFF':
3283
                    $colorIdx = 0x23;
3284
3285
                    break;
3286
                case '800080':
3287
                    $colorIdx = 0x24;
3288
3289
                    break;
3290
                case '800000':
3291
                    $colorIdx = 0x25;
3292
3293
                    break;
3294
                case '008080':
3295
                    $colorIdx = 0x26;
3296
3297
                    break;
3298
                case '0000FF':
3299
                    $colorIdx = 0x27;
3300
3301
                    break;
3302
                case '00CCFF':
3303
                    $colorIdx = 0x28;
3304
3305
                    break;
3306
                case 'CCFFFF':
3307
                    $colorIdx = 0x29;
3308
3309
                    break;
3310
                case 'CCFFCC':
3311
                    $colorIdx = 0x2A;
3312
3313
                    break;
3314
                case 'FFFF99':
3315
                    $colorIdx = 0x2B;
3316
3317
                    break;
3318
                case '99CCFF':
3319
                    $colorIdx = 0x2C;
3320
3321
                    break;
3322
                case 'FF99CC':
3323
                    $colorIdx = 0x2D;
3324
3325
                    break;
3326
                case 'CC99FF':
3327
                    $colorIdx = 0x2E;
3328
3329
                    break;
3330
                case 'FFCC99':
3331
                    $colorIdx = 0x2F;
3332
3333
                    break;
3334
                case '3366FF':
3335
                    $colorIdx = 0x30;
3336
3337
                    break;
3338
                case '33CCCC':
3339
                    $colorIdx = 0x31;
3340
3341
                    break;
3342
                case '99CC00':
3343
                    $colorIdx = 0x32;
3344
3345
                    break;
3346
                case 'FFCC00':
3347
                    $colorIdx = 0x33;
3348
3349
                    break;
3350
                case 'FF9900':
3351
                    $colorIdx = 0x34;
3352
3353
                    break;
3354
                case 'FF6600':
3355
                    $colorIdx = 0x35;
3356
3357
                    break;
3358
                case '666699':
3359
                    $colorIdx = 0x36;
3360
3361
                    break;
3362
                case '969696':
3363
                    $colorIdx = 0x37;
3364
3365
                    break;
3366
                case '003366':
3367
                    $colorIdx = 0x38;
3368
3369
                    break;
3370
                case '339966':
3371
                    $colorIdx = 0x39;
3372
3373
                    break;
3374
                case '003300':
3375
                    $colorIdx = 0x3A;
3376
3377
                    break;
3378
                case '333300':
3379
                    $colorIdx = 0x3B;
3380
3381
                    break;
3382
                case '993300':
3383
                    $colorIdx = 0x3C;
3384
3385
                    break;
3386
                case '993366':
3387
                    $colorIdx = 0x3D;
3388
3389
                    break;
3390
                case '333399':
3391
                    $colorIdx = 0x3E;
3392
3393
                    break;
3394
                case '333333':
3395
                    $colorIdx = 0x3F;
3396
3397
                    break;
3398
                default:
3399
                    $colorIdx = 0x00;
3400
3401
                    break;
3402
            }
3403 2
            $dataBlockFont .= pack('V', $colorIdx);
3404
            // 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...
3405 2
            $dataBlockFont .= pack('V', 0x00000000);
3406
            // Options flags for modified font attributes
3407 2
            $optionsFlags = 0;
3408 2
            $optionsFlagsBold = ($conditional->getStyle()->getFont()->getBold() == null ? 1 : 0);
3409 2
            $optionsFlags |= (1 == $optionsFlagsBold ? 0x00000002 : 0);
3410 2
            $optionsFlags |= (1 == 1 ? 0x00000008 : 0);
3411 2
            $optionsFlags |= (1 == 1 ? 0x00000010 : 0);
3412 2
            $optionsFlags |= (1 == 0 ? 0x00000020 : 0);
3413 2
            $optionsFlags |= (1 == 1 ? 0x00000080 : 0);
3414 2
            $dataBlockFont .= pack('V', $optionsFlags);
3415
            // Escapement type
3416 2
            $dataBlockFont .= pack('V', $fontEscapement);
3417
            // Underline type
3418 2
            $dataBlockFont .= pack('V', $fontUnderline);
3419
            // Always
3420 2
            $dataBlockFont .= pack('V', 0x00000000);
3421
            // Always
3422 2
            $dataBlockFont .= pack('V', 0x00000000);
3423
            // 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...
3424 2
            $dataBlockFont .= pack('VV', 0x00000000, 0x00000000);
3425
            // Always
3426 2
            $dataBlockFont .= pack('v', 0x0001);
3427
        }
3428 2
        if ($bFormatAlign == 1) {
3429
            $blockAlign = 0;
3430
            // Alignment and text break
3431
            switch ($conditional->getStyle()->getAlignment()->getHorizontal()) {
3432
                case Alignment::HORIZONTAL_GENERAL:
3433
                    $blockAlign = 0;
3434
3435
                    break;
3436
                case Alignment::HORIZONTAL_LEFT:
3437
                    $blockAlign = 1;
3438
3439
                    break;
3440
                case Alignment::HORIZONTAL_RIGHT:
3441
                    $blockAlign = 3;
3442
3443
                    break;
3444
                case Alignment::HORIZONTAL_CENTER:
3445
                    $blockAlign = 2;
3446
3447
                    break;
3448
                case Alignment::HORIZONTAL_CENTER_CONTINUOUS:
3449
                    $blockAlign = 6;
3450
3451
                    break;
3452
                case Alignment::HORIZONTAL_JUSTIFY:
3453
                    $blockAlign = 5;
3454
3455
                    break;
3456
            }
3457
            if ($conditional->getStyle()->getAlignment()->getWrapText() == true) {
3458
                $blockAlign |= 1 << 3;
3459
            } else {
3460
                $blockAlign |= 0 << 3;
3461
            }
3462
            switch ($conditional->getStyle()->getAlignment()->getVertical()) {
3463
                case Alignment::VERTICAL_BOTTOM:
3464
                    $blockAlign = 2 << 4;
3465
3466
                    break;
3467
                case Alignment::VERTICAL_TOP:
3468
                    $blockAlign = 0 << 4;
3469
3470
                    break;
3471
                case Alignment::VERTICAL_CENTER:
3472
                    $blockAlign = 1 << 4;
3473
3474
                    break;
3475
                case Alignment::VERTICAL_JUSTIFY:
3476
                    $blockAlign = 3 << 4;
3477
3478
                    break;
3479
            }
3480
            $blockAlign |= 0 << 7;
3481
3482
            // Text rotation angle
3483
            $blockRotation = $conditional->getStyle()->getAlignment()->getTextRotation();
3484
3485
            // Indentation
3486
            $blockIndent = $conditional->getStyle()->getAlignment()->getIndent();
3487
            if ($conditional->getStyle()->getAlignment()->getShrinkToFit() == true) {
3488
                $blockIndent |= 1 << 4;
3489
            } else {
3490
                $blockIndent |= 0 << 4;
3491
            }
3492
            $blockIndent |= 0 << 6;
3493
3494
            // Relative indentation
3495
            $blockIndentRelative = 255;
3496
3497
            $dataBlockAlign = pack('CCvvv', $blockAlign, $blockRotation, $blockIndent, $blockIndentRelative, 0x0000);
3498
        }
3499 2
        if ($bFormatBorder == 1) {
3500
            $blockLineStyle = 0;
3501
            switch ($conditional->getStyle()->getBorders()->getLeft()->getBorderStyle()) {
3502
                case Border::BORDER_NONE:
3503
                    $blockLineStyle |= 0x00;
3504
3505
                    break;
3506
                case Border::BORDER_THIN:
3507
                    $blockLineStyle |= 0x01;
3508
3509
                    break;
3510
                case Border::BORDER_MEDIUM:
3511
                    $blockLineStyle |= 0x02;
3512
3513
                    break;
3514
                case Border::BORDER_DASHED:
3515
                    $blockLineStyle |= 0x03;
3516
3517
                    break;
3518
                case Border::BORDER_DOTTED:
3519
                    $blockLineStyle |= 0x04;
3520
3521
                    break;
3522
                case Border::BORDER_THICK:
3523
                    $blockLineStyle |= 0x05;
3524
3525
                    break;
3526
                case Border::BORDER_DOUBLE:
3527
                    $blockLineStyle |= 0x06;
3528
3529
                    break;
3530
                case Border::BORDER_HAIR:
3531
                    $blockLineStyle |= 0x07;
3532
3533
                    break;
3534
                case Border::BORDER_MEDIUMDASHED:
3535
                    $blockLineStyle |= 0x08;
3536
3537
                    break;
3538
                case Border::BORDER_DASHDOT:
3539
                    $blockLineStyle |= 0x09;
3540
3541
                    break;
3542
                case Border::BORDER_MEDIUMDASHDOT:
3543
                    $blockLineStyle |= 0x0A;
3544
3545
                    break;
3546
                case Border::BORDER_DASHDOTDOT:
3547
                    $blockLineStyle |= 0x0B;
3548
3549
                    break;
3550
                case Border::BORDER_MEDIUMDASHDOTDOT:
3551
                    $blockLineStyle |= 0x0C;
3552
3553
                    break;
3554
                case Border::BORDER_SLANTDASHDOT:
3555
                    $blockLineStyle |= 0x0D;
3556
3557
                    break;
3558
            }
3559 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...
3560
                case Border::BORDER_NONE:
3561
                    $blockLineStyle |= 0x00 << 4;
3562
3563
                    break;
3564
                case Border::BORDER_THIN:
3565
                    $blockLineStyle |= 0x01 << 4;
3566
3567
                    break;
3568
                case Border::BORDER_MEDIUM:
3569
                    $blockLineStyle |= 0x02 << 4;
3570
3571
                    break;
3572
                case Border::BORDER_DASHED:
3573
                    $blockLineStyle |= 0x03 << 4;
3574
3575
                    break;
3576
                case Border::BORDER_DOTTED:
3577
                    $blockLineStyle |= 0x04 << 4;
3578
3579
                    break;
3580
                case Border::BORDER_THICK:
3581
                    $blockLineStyle |= 0x05 << 4;
3582
3583
                    break;
3584
                case Border::BORDER_DOUBLE:
3585
                    $blockLineStyle |= 0x06 << 4;
3586
3587
                    break;
3588
                case Border::BORDER_HAIR:
3589
                    $blockLineStyle |= 0x07 << 4;
3590
3591
                    break;
3592
                case Border::BORDER_MEDIUMDASHED:
3593
                    $blockLineStyle |= 0x08 << 4;
3594
3595
                    break;
3596
                case Border::BORDER_DASHDOT:
3597
                    $blockLineStyle |= 0x09 << 4;
3598
3599
                    break;
3600
                case Border::BORDER_MEDIUMDASHDOT:
3601
                    $blockLineStyle |= 0x0A << 4;
3602
3603
                    break;
3604
                case Border::BORDER_DASHDOTDOT:
3605
                    $blockLineStyle |= 0x0B << 4;
3606
3607
                    break;
3608
                case Border::BORDER_MEDIUMDASHDOTDOT:
3609
                    $blockLineStyle |= 0x0C << 4;
3610
3611
                    break;
3612
                case Border::BORDER_SLANTDASHDOT:
3613
                    $blockLineStyle |= 0x0D << 4;
3614
3615
                    break;
3616
            }
3617 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...
3618
                case Border::BORDER_NONE:
3619
                    $blockLineStyle |= 0x00 << 8;
3620
3621
                    break;
3622
                case Border::BORDER_THIN:
3623
                    $blockLineStyle |= 0x01 << 8;
3624
3625
                    break;
3626
                case Border::BORDER_MEDIUM:
3627
                    $blockLineStyle |= 0x02 << 8;
3628
3629
                    break;
3630
                case Border::BORDER_DASHED:
3631
                    $blockLineStyle |= 0x03 << 8;
3632
3633
                    break;
3634
                case Border::BORDER_DOTTED:
3635
                    $blockLineStyle |= 0x04 << 8;
3636
3637
                    break;
3638
                case Border::BORDER_THICK:
3639
                    $blockLineStyle |= 0x05 << 8;
3640
3641
                    break;
3642
                case Border::BORDER_DOUBLE:
3643
                    $blockLineStyle |= 0x06 << 8;
3644
3645
                    break;
3646
                case Border::BORDER_HAIR:
3647
                    $blockLineStyle |= 0x07 << 8;
3648
3649
                    break;
3650
                case Border::BORDER_MEDIUMDASHED:
3651
                    $blockLineStyle |= 0x08 << 8;
3652
3653
                    break;
3654
                case Border::BORDER_DASHDOT:
3655
                    $blockLineStyle |= 0x09 << 8;
3656
3657
                    break;
3658
                case Border::BORDER_MEDIUMDASHDOT:
3659
                    $blockLineStyle |= 0x0A << 8;
3660
3661
                    break;
3662
                case Border::BORDER_DASHDOTDOT:
3663
                    $blockLineStyle |= 0x0B << 8;
3664
3665
                    break;
3666
                case Border::BORDER_MEDIUMDASHDOTDOT:
3667
                    $blockLineStyle |= 0x0C << 8;
3668
3669
                    break;
3670
                case Border::BORDER_SLANTDASHDOT:
3671
                    $blockLineStyle |= 0x0D << 8;
3672
3673
                    break;
3674
            }
3675 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...
3676
                case Border::BORDER_NONE:
3677
                    $blockLineStyle |= 0x00 << 12;
3678
3679
                    break;
3680
                case Border::BORDER_THIN:
3681
                    $blockLineStyle |= 0x01 << 12;
3682
3683
                    break;
3684
                case Border::BORDER_MEDIUM:
3685
                    $blockLineStyle |= 0x02 << 12;
3686
3687
                    break;
3688
                case Border::BORDER_DASHED:
3689
                    $blockLineStyle |= 0x03 << 12;
3690
3691
                    break;
3692
                case Border::BORDER_DOTTED:
3693
                    $blockLineStyle |= 0x04 << 12;
3694
3695
                    break;
3696
                case Border::BORDER_THICK:
3697
                    $blockLineStyle |= 0x05 << 12;
3698
3699
                    break;
3700
                case Border::BORDER_DOUBLE:
3701
                    $blockLineStyle |= 0x06 << 12;
3702
3703
                    break;
3704
                case Border::BORDER_HAIR:
3705
                    $blockLineStyle |= 0x07 << 12;
3706
3707
                    break;
3708
                case Border::BORDER_MEDIUMDASHED:
3709
                    $blockLineStyle |= 0x08 << 12;
3710
3711
                    break;
3712
                case Border::BORDER_DASHDOT:
3713
                    $blockLineStyle |= 0x09 << 12;
3714
3715
                    break;
3716
                case Border::BORDER_MEDIUMDASHDOT:
3717
                    $blockLineStyle |= 0x0A << 12;
3718
3719
                    break;
3720
                case Border::BORDER_DASHDOTDOT:
3721
                    $blockLineStyle |= 0x0B << 12;
3722
3723
                    break;
3724
                case Border::BORDER_MEDIUMDASHDOTDOT:
3725
                    $blockLineStyle |= 0x0C << 12;
3726
3727
                    break;
3728
                case Border::BORDER_SLANTDASHDOT:
3729
                    $blockLineStyle |= 0x0D << 12;
3730
3731
                    break;
3732
            }
3733
            //@todo writeCFRule() => $blockLineStyle => Index Color for left line
3734
            //@todo writeCFRule() => $blockLineStyle => Index Color for right line
3735
            //@todo writeCFRule() => $blockLineStyle => Top-left to bottom-right on/off
3736
            //@todo writeCFRule() => $blockLineStyle => Bottom-left to top-right on/off
3737
            $blockColor = 0;
3738
            //@todo writeCFRule() => $blockColor => Index Color for top line
3739
            //@todo writeCFRule() => $blockColor => Index Color for bottom line
3740
            //@todo writeCFRule() => $blockColor => Index Color for diagonal line
3741 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...
3742
                case Border::BORDER_NONE:
3743
                    $blockColor |= 0x00 << 21;
3744
3745
                    break;
3746
                case Border::BORDER_THIN:
3747
                    $blockColor |= 0x01 << 21;
3748
3749
                    break;
3750
                case Border::BORDER_MEDIUM:
3751
                    $blockColor |= 0x02 << 21;
3752
3753
                    break;
3754
                case Border::BORDER_DASHED:
3755
                    $blockColor |= 0x03 << 21;
3756
3757
                    break;
3758
                case Border::BORDER_DOTTED:
3759
                    $blockColor |= 0x04 << 21;
3760
3761
                    break;
3762
                case Border::BORDER_THICK:
3763
                    $blockColor |= 0x05 << 21;
3764
3765
                    break;
3766
                case Border::BORDER_DOUBLE:
3767
                    $blockColor |= 0x06 << 21;
3768
3769
                    break;
3770
                case Border::BORDER_HAIR:
3771
                    $blockColor |= 0x07 << 21;
3772
3773
                    break;
3774
                case Border::BORDER_MEDIUMDASHED:
3775
                    $blockColor |= 0x08 << 21;
3776
3777
                    break;
3778
                case Border::BORDER_DASHDOT:
3779
                    $blockColor |= 0x09 << 21;
3780
3781
                    break;
3782
                case Border::BORDER_MEDIUMDASHDOT:
3783
                    $blockColor |= 0x0A << 21;
3784
3785
                    break;
3786
                case Border::BORDER_DASHDOTDOT:
3787
                    $blockColor |= 0x0B << 21;
3788
3789
                    break;
3790
                case Border::BORDER_MEDIUMDASHDOTDOT:
3791
                    $blockColor |= 0x0C << 21;
3792
3793
                    break;
3794
                case Border::BORDER_SLANTDASHDOT:
3795
                    $blockColor |= 0x0D << 21;
3796
3797
                    break;
3798
            }
3799
            $dataBlockBorder = pack('vv', $blockLineStyle, $blockColor);
3800
        }
3801 2
        if ($bFormatFill == 1) {
3802
            // Fill Patern Style
3803 2
            $blockFillPatternStyle = 0;
3804 2
            switch ($conditional->getStyle()->getFill()->getFillType()) {
3805 2
                case Fill::FILL_NONE:
3806
                    $blockFillPatternStyle = 0x00;
3807
3808
                    break;
3809 2
                case Fill::FILL_SOLID:
3810
                    $blockFillPatternStyle = 0x01;
3811
3812
                    break;
3813 2
                case Fill::FILL_PATTERN_MEDIUMGRAY:
3814
                    $blockFillPatternStyle = 0x02;
3815
3816
                    break;
3817 2
                case Fill::FILL_PATTERN_DARKGRAY:
3818
                    $blockFillPatternStyle = 0x03;
3819
3820
                    break;
3821 2
                case Fill::FILL_PATTERN_LIGHTGRAY:
3822
                    $blockFillPatternStyle = 0x04;
3823
3824
                    break;
3825 2
                case Fill::FILL_PATTERN_DARKHORIZONTAL:
3826
                    $blockFillPatternStyle = 0x05;
3827
3828
                    break;
3829 2
                case Fill::FILL_PATTERN_DARKVERTICAL:
3830
                    $blockFillPatternStyle = 0x06;
3831
3832
                    break;
3833 2
                case Fill::FILL_PATTERN_DARKDOWN:
3834
                    $blockFillPatternStyle = 0x07;
3835
3836
                    break;
3837 2
                case Fill::FILL_PATTERN_DARKUP:
3838
                    $blockFillPatternStyle = 0x08;
3839
3840
                    break;
3841 2
                case Fill::FILL_PATTERN_DARKGRID:
3842
                    $blockFillPatternStyle = 0x09;
3843
3844
                    break;
3845 2
                case Fill::FILL_PATTERN_DARKTRELLIS:
3846
                    $blockFillPatternStyle = 0x0A;
3847
3848
                    break;
3849 2
                case Fill::FILL_PATTERN_LIGHTHORIZONTAL:
3850
                    $blockFillPatternStyle = 0x0B;
3851
3852
                    break;
3853 2
                case Fill::FILL_PATTERN_LIGHTVERTICAL:
3854
                    $blockFillPatternStyle = 0x0C;
3855
3856
                    break;
3857 2
                case Fill::FILL_PATTERN_LIGHTDOWN:
3858
                    $blockFillPatternStyle = 0x0D;
3859
3860
                    break;
3861 2
                case Fill::FILL_PATTERN_LIGHTUP:
3862
                    $blockFillPatternStyle = 0x0E;
3863
3864
                    break;
3865 2
                case Fill::FILL_PATTERN_LIGHTGRID:
3866
                    $blockFillPatternStyle = 0x0F;
3867
3868
                    break;
3869 2
                case Fill::FILL_PATTERN_LIGHTTRELLIS:
3870
                    $blockFillPatternStyle = 0x10;
3871
3872
                    break;
3873 2
                case Fill::FILL_PATTERN_GRAY125:
3874
                    $blockFillPatternStyle = 0x11;
3875
3876
                    break;
3877 2
                case Fill::FILL_PATTERN_GRAY0625:
3878
                    $blockFillPatternStyle = 0x12;
3879
3880
                    break;
3881 2
                case Fill::FILL_GRADIENT_LINEAR:
3882
                    $blockFillPatternStyle = 0x00;
3883
3884
                    break; // does not exist in BIFF8
3885 2
                case Fill::FILL_GRADIENT_PATH:
3886
                    $blockFillPatternStyle = 0x00;
3887
3888
                    break; // does not exist in BIFF8
3889
                default:
3890 2
                    $blockFillPatternStyle = 0x00;
3891
3892 2
                    break;
3893
            }
3894
            // Color
3895 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...
3896 2
                case '000000':
3897
                    $colorIdxBg = 0x08;
3898
3899
                    break;
3900 2
                case 'FFFFFF':
3901
                    $colorIdxBg = 0x09;
3902
3903
                    break;
3904 2
                case 'FF0000':
3905
                    $colorIdxBg = 0x0A;
3906
3907
                    break;
3908 2
                case '00FF00':
3909
                    $colorIdxBg = 0x0B;
3910
3911
                    break;
3912 2
                case '0000FF':
3913
                    $colorIdxBg = 0x0C;
3914
3915
                    break;
3916 2
                case 'FFFF00':
3917
                    $colorIdxBg = 0x0D;
3918
3919
                    break;
3920 2
                case 'FF00FF':
3921
                    $colorIdxBg = 0x0E;
3922
3923
                    break;
3924 2
                case '00FFFF':
3925
                    $colorIdxBg = 0x0F;
3926
3927
                    break;
3928 2
                case '800000':
3929
                    $colorIdxBg = 0x10;
3930
3931
                    break;
3932 2
                case '008000':
3933
                    $colorIdxBg = 0x11;
3934
3935
                    break;
3936 2
                case '000080':
3937
                    $colorIdxBg = 0x12;
3938
3939
                    break;
3940 2
                case '808000':
3941
                    $colorIdxBg = 0x13;
3942
3943
                    break;
3944 2
                case '800080':
3945
                    $colorIdxBg = 0x14;
3946
3947
                    break;
3948 2
                case '008080':
3949
                    $colorIdxBg = 0x15;
3950
3951
                    break;
3952 2
                case 'C0C0C0':
3953
                    $colorIdxBg = 0x16;
3954
3955
                    break;
3956 2
                case '808080':
3957
                    $colorIdxBg = 0x17;
3958
3959
                    break;
3960 2
                case '9999FF':
3961
                    $colorIdxBg = 0x18;
3962
3963
                    break;
3964 2
                case '993366':
3965
                    $colorIdxBg = 0x19;
3966
3967
                    break;
3968 2
                case 'FFFFCC':
3969
                    $colorIdxBg = 0x1A;
3970
3971
                    break;
3972 2
                case 'CCFFFF':
3973
                    $colorIdxBg = 0x1B;
3974
3975
                    break;
3976 2
                case '660066':
3977
                    $colorIdxBg = 0x1C;
3978
3979
                    break;
3980 2
                case 'FF8080':
3981
                    $colorIdxBg = 0x1D;
3982
3983
                    break;
3984 2
                case '0066CC':
3985
                    $colorIdxBg = 0x1E;
3986
3987
                    break;
3988 2
                case 'CCCCFF':
3989
                    $colorIdxBg = 0x1F;
3990
3991
                    break;
3992 2
                case '000080':
3993
                    $colorIdxBg = 0x20;
3994
3995
                    break;
3996 2
                case 'FF00FF':
3997
                    $colorIdxBg = 0x21;
3998
3999
                    break;
4000 2
                case 'FFFF00':
4001
                    $colorIdxBg = 0x22;
4002
4003
                    break;
4004 2
                case '00FFFF':
4005
                    $colorIdxBg = 0x23;
4006
4007
                    break;
4008 2
                case '800080':
4009
                    $colorIdxBg = 0x24;
4010
4011
                    break;
4012 2
                case '800000':
4013
                    $colorIdxBg = 0x25;
4014
4015
                    break;
4016 2
                case '008080':
4017
                    $colorIdxBg = 0x26;
4018
4019
                    break;
4020 2
                case '0000FF':
4021
                    $colorIdxBg = 0x27;
4022
4023
                    break;
4024 2
                case '00CCFF':
4025
                    $colorIdxBg = 0x28;
4026
4027
                    break;
4028 2
                case 'CCFFFF':
4029
                    $colorIdxBg = 0x29;
4030
4031
                    break;
4032 2
                case 'CCFFCC':
4033
                    $colorIdxBg = 0x2A;
4034
4035
                    break;
4036 2
                case 'FFFF99':
4037
                    $colorIdxBg = 0x2B;
4038
4039
                    break;
4040 2
                case '99CCFF':
4041
                    $colorIdxBg = 0x2C;
4042
4043
                    break;
4044 2
                case 'FF99CC':
4045
                    $colorIdxBg = 0x2D;
4046
4047
                    break;
4048 2
                case 'CC99FF':
4049
                    $colorIdxBg = 0x2E;
4050
4051
                    break;
4052 2
                case 'FFCC99':
4053
                    $colorIdxBg = 0x2F;
4054
4055
                    break;
4056 2
                case '3366FF':
4057
                    $colorIdxBg = 0x30;
4058
4059
                    break;
4060 2
                case '33CCCC':
4061
                    $colorIdxBg = 0x31;
4062
4063
                    break;
4064 2
                case '99CC00':
4065
                    $colorIdxBg = 0x32;
4066
4067
                    break;
4068 2
                case 'FFCC00':
4069
                    $colorIdxBg = 0x33;
4070
4071
                    break;
4072 2
                case 'FF9900':
4073
                    $colorIdxBg = 0x34;
4074
4075
                    break;
4076 2
                case 'FF6600':
4077
                    $colorIdxBg = 0x35;
4078
4079
                    break;
4080 2
                case '666699':
4081
                    $colorIdxBg = 0x36;
4082
4083
                    break;
4084 2
                case '969696':
4085
                    $colorIdxBg = 0x37;
4086
4087
                    break;
4088 2
                case '003366':
4089
                    $colorIdxBg = 0x38;
4090
4091
                    break;
4092 2
                case '339966':
4093
                    $colorIdxBg = 0x39;
4094
4095
                    break;
4096 2
                case '003300':
4097
                    $colorIdxBg = 0x3A;
4098
4099
                    break;
4100 2
                case '333300':
4101
                    $colorIdxBg = 0x3B;
4102
4103
                    break;
4104 2
                case '993300':
4105
                    $colorIdxBg = 0x3C;
4106
4107
                    break;
4108 2
                case '993366':
4109
                    $colorIdxBg = 0x3D;
4110
4111
                    break;
4112 2
                case '333399':
4113
                    $colorIdxBg = 0x3E;
4114
4115
                    break;
4116 2
                case '333333':
4117
                    $colorIdxBg = 0x3F;
4118
4119
                    break;
4120
                default:
4121 2
                          $colorIdxBg = 0x41;
4122
4123 2
                    break;
4124
            }
4125
            // Fg Color
4126 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...
4127 2
                case '000000':
4128
                    $colorIdxFg = 0x08;
4129
4130
                    break;
4131 2
                case 'FFFFFF':
4132
                    $colorIdxFg = 0x09;
4133
4134
                    break;
4135 2
                case 'FF0000':
4136
                    $colorIdxFg = 0x0A;
4137
4138
                    break;
4139 2
                case '00FF00':
4140
                    $colorIdxFg = 0x0B;
4141
4142
                    break;
4143 2
                case '0000FF':
4144
                    $colorIdxFg = 0x0C;
4145
4146
                    break;
4147 2
                case 'FFFF00':
4148
                    $colorIdxFg = 0x0D;
4149
4150
                    break;
4151 2
                case 'FF00FF':
4152
                    $colorIdxFg = 0x0E;
4153
4154
                    break;
4155 2
                case '00FFFF':
4156
                    $colorIdxFg = 0x0F;
4157
4158
                    break;
4159 2
                case '800000':
4160
                    $colorIdxFg = 0x10;
4161
4162
                    break;
4163 2
                case '008000':
4164
                    $colorIdxFg = 0x11;
4165
4166
                    break;
4167 2
                case '000080':
4168
                    $colorIdxFg = 0x12;
4169
4170
                    break;
4171 2
                case '808000':
4172
                    $colorIdxFg = 0x13;
4173
4174
                    break;
4175 2
                case '800080':
4176
                    $colorIdxFg = 0x14;
4177
4178
                    break;
4179 2
                case '008080':
4180
                    $colorIdxFg = 0x15;
4181
4182
                    break;
4183 2
                case 'C0C0C0':
4184
                    $colorIdxFg = 0x16;
4185
4186
                    break;
4187 2
                case '808080':
4188
                    $colorIdxFg = 0x17;
4189
4190
                    break;
4191 2
                case '9999FF':
4192
                    $colorIdxFg = 0x18;
4193
4194
                    break;
4195 2
                case '993366':
4196
                    $colorIdxFg = 0x19;
4197
4198
                    break;
4199 2
                case 'FFFFCC':
4200
                    $colorIdxFg = 0x1A;
4201
4202
                    break;
4203 2
                case 'CCFFFF':
4204
                    $colorIdxFg = 0x1B;
4205
4206
                    break;
4207 2
                case '660066':
4208
                    $colorIdxFg = 0x1C;
4209
4210
                    break;
4211 2
                case 'FF8080':
4212
                    $colorIdxFg = 0x1D;
4213
4214
                    break;
4215 2
                case '0066CC':
4216
                    $colorIdxFg = 0x1E;
4217
4218
                    break;
4219 2
                case 'CCCCFF':
4220
                    $colorIdxFg = 0x1F;
4221
4222
                    break;
4223 2
                case '000080':
4224
                    $colorIdxFg = 0x20;
4225
4226
                    break;
4227 2
                case 'FF00FF':
4228
                    $colorIdxFg = 0x21;
4229
4230
                    break;
4231 2
                case 'FFFF00':
4232
                    $colorIdxFg = 0x22;
4233
4234
                    break;
4235 2
                case '00FFFF':
4236
                    $colorIdxFg = 0x23;
4237
4238
                    break;
4239 2
                case '800080':
4240
                    $colorIdxFg = 0x24;
4241
4242
                    break;
4243 2
                case '800000':
4244
                    $colorIdxFg = 0x25;
4245
4246
                    break;
4247 2
                case '008080':
4248
                    $colorIdxFg = 0x26;
4249
4250
                    break;
4251 2
                case '0000FF':
4252
                    $colorIdxFg = 0x27;
4253
4254
                    break;
4255 2
                case '00CCFF':
4256
                    $colorIdxFg = 0x28;
4257
4258
                    break;
4259 2
                case 'CCFFFF':
4260
                    $colorIdxFg = 0x29;
4261
4262
                    break;
4263 2
                case 'CCFFCC':
4264
                    $colorIdxFg = 0x2A;
4265
4266
                    break;
4267 2
                case 'FFFF99':
4268
                    $colorIdxFg = 0x2B;
4269
4270
                    break;
4271 2
                case '99CCFF':
4272
                    $colorIdxFg = 0x2C;
4273
4274
                    break;
4275 2
                case 'FF99CC':
4276
                    $colorIdxFg = 0x2D;
4277
4278
                    break;
4279 2
                case 'CC99FF':
4280
                    $colorIdxFg = 0x2E;
4281
4282
                    break;
4283 2
                case 'FFCC99':
4284
                    $colorIdxFg = 0x2F;
4285
4286
                    break;
4287 2
                case '3366FF':
4288
                    $colorIdxFg = 0x30;
4289
4290
                    break;
4291 2
                case '33CCCC':
4292
                    $colorIdxFg = 0x31;
4293
4294
                    break;
4295 2
                case '99CC00':
4296
                    $colorIdxFg = 0x32;
4297
4298
                    break;
4299 2
                case 'FFCC00':
4300
                    $colorIdxFg = 0x33;
4301
4302
                    break;
4303 2
                case 'FF9900':
4304
                    $colorIdxFg = 0x34;
4305
4306
                    break;
4307 2
                case 'FF6600':
4308
                    $colorIdxFg = 0x35;
4309
4310
                    break;
4311 2
                case '666699':
4312
                    $colorIdxFg = 0x36;
4313
4314
                    break;
4315 2
                case '969696':
4316
                    $colorIdxFg = 0x37;
4317
4318
                    break;
4319 2
                case '003366':
4320
                    $colorIdxFg = 0x38;
4321
4322
                    break;
4323 2
                case '339966':
4324
                    $colorIdxFg = 0x39;
4325
4326
                    break;
4327 2
                case '003300':
4328
                    $colorIdxFg = 0x3A;
4329
4330
                    break;
4331 2
                case '333300':
4332
                    $colorIdxFg = 0x3B;
4333
4334
                    break;
4335 2
                case '993300':
4336
                    $colorIdxFg = 0x3C;
4337
4338
                    break;
4339 2
                case '993366':
4340
                    $colorIdxFg = 0x3D;
4341
4342
                    break;
4343 2
                case '333399':
4344
                    $colorIdxFg = 0x3E;
4345
4346
                    break;
4347 2
                case '333333':
4348
                    $colorIdxFg = 0x3F;
4349
4350
                    break;
4351
                default:
4352 2
                          $colorIdxFg = 0x40;
4353
4354 2
                    break;
4355
            }
4356 2
            $dataBlockFill = pack('v', $blockFillPatternStyle);
4357 2
            $dataBlockFill .= pack('v', $colorIdxFg | ($colorIdxBg << 7));
4358
        }
4359 2
        if ($bFormatProt == 1) {
4360
            $dataBlockProtection = 0;
4361
            if ($conditional->getStyle()->getProtection()->getLocked() == Protection::PROTECTION_PROTECTED) {
4362
                $dataBlockProtection = 1;
4363
            }
4364
            if ($conditional->getStyle()->getProtection()->getHidden() == Protection::PROTECTION_PROTECTED) {
4365
                $dataBlockProtection = 1 << 1;
4366
            }
4367
        }
4368
4369 2
        $data = pack('CCvvVv', $type, $operatorType, $szValue1, $szValue2, $flags, 0x0000);
4370 2
        if ($bFormatFont == 1) { // Block Formatting : OK
4371 2
            $data .= $dataBlockFont;
4372
        }
4373 2
        if ($bFormatAlign == 1) {
4374
            $data .= $dataBlockAlign;
4375
        }
4376 2
        if ($bFormatBorder == 1) {
4377
            $data .= $dataBlockBorder;
4378
        }
4379 2
        if ($bFormatFill == 1) { // Block Formatting : OK
4380 2
            $data .= $dataBlockFill;
4381
        }
4382 2
        if ($bFormatProt == 1) {
4383
            $data .= $dataBlockProtection;
4384
        }
4385 2
        if ($operand1 !== null) {
4386 2
            $data .= $operand1;
4387
        }
4388 2
        if ($operand2 !== null) {
4389 1
            $data .= $operand2;
4390
        }
4391 2
        $header = pack('vv', $record, strlen($data));
4392 2
        $this->append($header . $data);
4393 2
    }
4394
4395
    /**
4396
     * Write CFHeader record.
4397
     */
4398 2
    private function writeCFHeader()
4399
    {
4400 2
        $record = 0x01B0; // Record identifier
4401 2
        $length = 0x0016; // Bytes to follow
4402
4403 2
        $numColumnMin = null;
4404 2
        $numColumnMax = null;
4405 2
        $numRowMin = null;
4406 2
        $numRowMax = null;
4407 2
        $arrConditional = [];
4408 2
        foreach ($this->phpSheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) {
4409 2
            foreach ($conditionalStyles as $conditional) {
4410 2
                if ($conditional->getConditionType() == Conditional::CONDITION_EXPRESSION
4411 2
                        || $conditional->getConditionType() == Conditional::CONDITION_CELLIS) {
4412 2
                    if (!in_array($conditional->getHashCode(), $arrConditional)) {
4413 2
                        $arrConditional[] = $conditional->getHashCode();
4414
                    }
4415
                    // Cells
4416 2
                    $arrCoord = Coordinate::coordinateFromString($cellCoordinate);
4417 2
                    if (!is_numeric($arrCoord[0])) {
4418 2
                        $arrCoord[0] = Coordinate::columnIndexFromString($arrCoord[0]);
4419
                    }
4420 2
                    if ($numColumnMin === null || ($numColumnMin > $arrCoord[0])) {
4421 2
                        $numColumnMin = $arrCoord[0];
4422
                    }
4423 2
                    if ($numColumnMax === null || ($numColumnMax < $arrCoord[0])) {
4424 2
                        $numColumnMax = $arrCoord[0];
4425
                    }
4426 2
                    if ($numRowMin === null || ($numRowMin > $arrCoord[1])) {
4427 2
                        $numRowMin = $arrCoord[1];
4428
                    }
4429 2
                    if ($numRowMax === null || ($numRowMax < $arrCoord[1])) {
4430 2
                        $numRowMax = $arrCoord[1];
4431
                    }
4432
                }
4433
            }
4434
        }
4435 2
        $needRedraw = 1;
4436 2
        $cellRange = pack('vvvv', $numRowMin - 1, $numRowMax - 1, $numColumnMin - 1, $numColumnMax - 1);
4437
4438 2
        $header = pack('vv', $record, $length);
4439 2
        $data = pack('vv', count($arrConditional), $needRedraw);
4440 2
        $data .= $cellRange;
4441 2
        $data .= pack('v', 0x0001);
4442 2
        $data .= $cellRange;
4443 2
        $this->append($header . $data);
4444 2
    }
4445
}
4446