For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

4240 lines
157 KiB

<?php
/**
* PHPExcel_Writer_Excel5_Worksheet
*
* Copyright (c) 2006 - 2015 PHPExcel
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* @category PHPExcel
* @package PHPExcel_Writer_Excel5
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
* @version ##VERSION##, ##DATE##
*/
// Original file header of PEAR::Spreadsheet_Excel_Writer_Worksheet (used as the base for this class):
// -----------------------------------------------------------------------------------------
// /*
// * Module written/ported by Xavier Noguer <[email protected]>
// *
// * The majority of this is _NOT_ my code. I simply ported it from the
// * PERL Spreadsheet::WriteExcel module.
// *
// * The author of the Spreadsheet::WriteExcel module is John McNamara
// * <[email protected]>
// *
// * I _DO_ maintain this code, and John McNamara has nothing to do with the
// * porting of this code to PHP. Any questions directly related to this
// * class library should be directed to me.
// *
// * License Information:
// *
// * Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets
// * Copyright (c) 2002-2003 Xavier Noguer [email protected]
// *
// * This library is free software; you can redistribute it and/or
// * modify it under the terms of the GNU Lesser General Public
// * License as published by the Free Software Foundation; either
// * version 2.1 of the License, or (at your option) any later version.
// *
// * This library is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// * Lesser General Public License for more details.
// *
// * You should have received a copy of the GNU Lesser General Public
// * License along with this library; if not, write to the Free Software
// * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// */
class PHPExcel_Writer_Excel5_Worksheet extends PHPExcel_Writer_Excel5_BIFFwriter
{
/**
* Formula parser
*
* @var PHPExcel_Writer_Excel5_Parser
*/
private $parser;
/**
* Maximum number of characters for a string (LABEL record in BIFF5)
* @var integer
*/
private $xlsStringMaxLength;
/**
* Array containing format information for columns
* @var array
*/
private $columnInfo;
/**
* Array containing the selected area for the worksheet
* @var array
*/
private $selection;
/**
* The active pane for the worksheet
* @var integer
*/
private $activePane;
/**
* Whether to use outline.
* @var integer
*/
private $outlineOn;
/**
* Auto outline styles.
* @var bool
*/
private $outlineStyle;
/**
* Whether to have outline summary below.
* @var bool
*/
private $outlineBelow;
/**
* Whether to have outline summary at the right.
* @var bool
*/
private $outlineRight;
/**
* Reference to the total number of strings in the workbook
* @var integer
*/
private $stringTotal;
/**
* Reference to the number of unique strings in the workbook
* @var integer
*/
private $stringUnique;
/**
* Reference to the array containing all the unique strings in the workbook
* @var array
*/
private $stringTable;
/**
* Color cache
*/
private $colors;
/**
* Index of first used row (at least 0)
* @var int
*/
private $firstRowIndex;
/**
* Index of last used row. (no used rows means -1)
* @var int
*/
private $lastRowIndex;
/**
* Index of first used column (at least 0)
* @var int
*/
private $firstColumnIndex;
/**
* Index of last used column (no used columns means -1)
* @var int
*/
private $lastColumnIndex;
/**
* Sheet object
* @var PHPExcel_Worksheet
*/
public $phpSheet;
/**
* Count cell style Xfs
*
* @var int
*/
private $countCellStyleXfs;
/**
* Escher object corresponding to MSODRAWING
*
* @var PHPExcel_Shared_Escher
*/
private $escher;
/**
* Array of font hashes associated to FONT records index
*
* @var array
*/
public $fontHashIndex;
/**
* Constructor
*
* @param int &$str_total Total number of strings
* @param int &$str_unique Total number of unique strings
* @param array &$str_table String Table
* @param array &$colors Colour Table
* @param mixed $parser The formula parser created for the Workbook
* @param boolean $preCalculateFormulas Flag indicating whether formulas should be calculated or just written
* @param string $phpSheet The worksheet to write
* @param PHPExcel_Worksheet $phpSheet
*/
public function __construct(&$str_total, &$str_unique, &$str_table, &$colors, $parser, $preCalculateFormulas, $phpSheet)
{
// It needs to call its parent's constructor explicitly
parent::__construct();
// change BIFFwriter limit for CONTINUE records
// $this->_limit = 8224;
$this->_preCalculateFormulas = $preCalculateFormulas;
$this->stringTotal = &$str_total;
$this->stringUnique = &$str_unique;
$this->stringTable = &$str_table;
$this->colors = &$colors;
$this->parser = $parser;
$this->phpSheet = $phpSheet;
//$this->ext_sheets = array();
//$this->offset = 0;
$this->xlsStringMaxLength = 255;
$this->columnInfo = array();
$this->selection = array(0,0,0,0);
$this->activePane = 3;
$this->_print_headers = 0;
$this->outlineStyle = 0;
$this->outlineBelow = 1;
$this->outlineRight = 1;
$this->outlineOn = 1;
$this->fontHashIndex = array();
// calculate values for DIMENSIONS record
$minR = 1;
$minC = 'A';
$maxR = $this->phpSheet->getHighestRow();
$maxC = $this->phpSheet->getHighestColumn();
// Determine lowest and highest column and row
// $this->firstRowIndex = ($minR > 65535) ? 65535 : $minR;
$this->lastRowIndex = ($maxR > 65535) ? 65535 : $maxR ;
$this->firstColumnIndex = PHPExcel_Cell::columnIndexFromString($minC);
$this->lastColumnIndex = PHPExcel_Cell::columnIndexFromString($maxC);
// if ($this->firstColumnIndex > 255) $this->firstColumnIndex = 255;
if ($this->lastColumnIndex > 255) {
$this->lastColumnIndex = 255;
}
$this->countCellStyleXfs = count($phpSheet->getParent()->getCellStyleXfCollection());
}
/**
* Add data to the beginning of the workbook (note the reverse order)
* and to the end of the workbook.
*
* @access public
* @see PHPExcel_Writer_Excel5_Workbook::storeWorkbook()
*/
public function close()
{
$phpSheet = $this->phpSheet;
$num_sheets = $phpSheet->getParent()->getSheetCount();
// Write BOF record
$this->storeBof(0x0010);
// Write PRINTHEADERS
$this->writePrintHeaders();
// Write PRINTGRIDLINES
$this->writePrintGridlines();
// Write GRIDSET
$this->writeGridset();
// Calculate column widths
$phpSheet->calculateColumnWidths();
// Column dimensions
if (($defaultWidth = $phpSheet->getDefaultColumnDimension()->getWidth()) < 0) {
$defaultWidth = PHPExcel_Shared_Font::getDefaultColumnWidthByFont($phpSheet->getParent()->getDefaultStyle()->getFont());
}
$columnDimensions = $phpSheet->getColumnDimensions();
$maxCol = $this->lastColumnIndex -1;
for ($i = 0; $i <= $maxCol; ++$i) {
$hidden = 0;
$level = 0;
$xfIndex = 15; // there are 15 cell style Xfs
$width = $defaultWidth;
$columnLetter = PHPExcel_Cell::stringFromColumnIndex($i);
if (isset($columnDimensions[$columnLetter])) {
$columnDimension = $columnDimensions[$columnLetter];
if ($columnDimension->getWidth() >= 0) {
$width = $columnDimension->getWidth();
}
$hidden = $columnDimension->getVisible() ? 0 : 1;
$level = $columnDimension->getOutlineLevel();
$xfIndex = $columnDimension->getXfIndex() + 15; // there are 15 cell style Xfs
}
// Components of columnInfo:
// $firstcol first column on the range
// $lastcol last column on the range
// $width width to set
// $xfIndex The optional cell style Xf index to apply to the columns
// $hidden The optional hidden atribute
// $level The optional outline level
$this->columnInfo[] = array($i, $i, $width, $xfIndex, $hidden, $level);
}
// Write GUTS
$this->writeGuts();
// Write DEFAULTROWHEIGHT
$this->writeDefaultRowHeight();
// Write WSBOOL
$this->writeWsbool();
// Write horizontal and vertical page breaks
$this->writeBreaks();
// Write page header
$this->writeHeader();
// Write page footer
$this->writeFooter();
// Write page horizontal centering
$this->writeHcenter();
// Write page vertical centering
$this->writeVcenter();
// Write left margin
$this->writeMarginLeft();
// Write right margin
$this->writeMarginRight();
// Write top margin
$this->writeMarginTop();
// Write bottom margin
$this->writeMarginBottom();
// Write page setup
$this->writeSetup();
// Write sheet protection
$this->writeProtect();
// Write SCENPROTECT
$this->writeScenProtect();
// Write OBJECTPROTECT
$this->writeObjectProtect();
// Write sheet password
$this->writePassword();
// Write DEFCOLWIDTH record
$this->writeDefcol();
// Write the COLINFO records if they exist
if (!empty($this->columnInfo)) {
$colcount = count($this->columnInfo);
for ($i = 0; $i < $colcount; ++$i) {
$this->writeColinfo($this->columnInfo[$i]);
}
}
$autoFilterRange = $phpSheet->getAutoFilter()->getRange();
if (!empty($autoFilterRange)) {
// Write AUTOFILTERINFO
$this->writeAutoFilterInfo();
}
// Write sheet dimensions
$this->writeDimensions();
// Row dimensions
foreach ($phpSheet->getRowDimensions() as $rowDimension) {
$xfIndex = $rowDimension->getXfIndex() + 15; // there are 15 cellXfs
$this->writeRow($rowDimension->getRowIndex() - 1, $rowDimension->getRowHeight(), $xfIndex, ($rowDimension->getVisible() ? '0' : '1'), $rowDimension->getOutlineLevel());
}
// Write Cells
foreach ($phpSheet->getCellCollection() as $cellID) {
$cell = $phpSheet->getCell($cellID);
$row = $cell->getRow() - 1;
$column = PHPExcel_Cell::columnIndexFromString($cell->getColumn()) - 1;
// Don't break Excel!
// if ($row + 1 > 65536 or $column + 1 > 256) {
if ($row > 65535 || $column > 255) {
break;
}
// Write cell value
$xfIndex = $cell->getXfIndex() + 15; // there are 15 cell style Xfs
$cVal = $cell->getValue();
if ($cVal instanceof PHPExcel_RichText) {
// $this->writeString($row, $column, $cVal->getPlainText(), $xfIndex);
$arrcRun = array();
$str_len = PHPExcel_Shared_String::CountCharacters($cVal->getPlainText(), 'UTF-8');
$str_pos = 0;
$elements = $cVal->getRichTextElements();
foreach ($elements as $element) {
// FONT Index
if ($element instanceof PHPExcel_RichText_Run) {
$str_fontidx = $this->fontHashIndex[$element->getFont()->getHashCode()];
} else {
$str_fontidx = 0;
}
$arrcRun[] = array('strlen' => $str_pos, 'fontidx' => $str_fontidx);
// Position FROM
$str_pos += PHPExcel_Shared_String::CountCharacters($element->getText(), 'UTF-8');
}
$this->writeRichTextString($row, $column, $cVal->getPlainText(), $xfIndex, $arrcRun);
} else {
switch ($cell->getDatatype()) {
case PHPExcel_Cell_DataType::TYPE_STRING:
case PHPExcel_Cell_DataType::TYPE_NULL:
if ($cVal === '' || $cVal === null) {
$this->writeBlank($row, $column, $xfIndex);
} else {
$this->writeString($row, $column, $cVal, $xfIndex);
}
break;
case PHPExcel_Cell_DataType::TYPE_NUMERIC:
$this->writeNumber($row, $column, $cVal, $xfIndex);
break;
case PHPExcel_Cell_DataType::TYPE_FORMULA:
$calculatedValue = $this->_preCalculateFormulas ?
$cell->getCalculatedValue() : null;
$this->writeFormula($row, $column, $cVal, $xfIndex, $calculatedValue);
break;
case PHPExcel_Cell_DataType::TYPE_BOOL:
$this->writeBoolErr($row, $column, $cVal, 0, $xfIndex);
break;
case PHPExcel_Cell_DataType::TYPE_ERROR:
$this->writeBoolErr($row, $column, self::mapErrorCode($cVal), 1, $xfIndex);
break;
}
}
}
// Append
$this->writeMsoDrawing();
// Write WINDOW2 record
$this->writeWindow2();
// Write PLV record
$this->writePageLayoutView();
// Write ZOOM record
$this->writeZoom();
if ($phpSheet->getFreezePane()) {
$this->writePanes();
}
// Write SELECTION record
$this->writeSelection();
// Write MergedCellsTable Record
$this->writeMergedCells();
// Hyperlinks
foreach ($phpSheet->getHyperLinkCollection() as $coordinate => $hyperlink) {
list($column, $row) = PHPExcel_Cell::coordinateFromString($coordinate);
$url = $hyperlink->getUrl();
if (strpos($url, 'sheet://') !== false) {
// internal to current workbook
$url = str_replace('sheet://', 'internal:', $url);
} elseif (preg_match('/^(http:|https:|ftp:|mailto:)/', $url)) {
// URL
// $url = $url;
} else {
// external (local file)
$url = 'external:' . $url;
}
$this->writeUrl($row - 1, PHPExcel_Cell::columnIndexFromString($column) - 1, $url);
}
$this->writeDataValidity();
$this->writeSheetLayout();
// Write SHEETPROTECTION record
$this->writeSheetProtection();
$this->writeRangeProtection();
$arrConditionalStyles = $phpSheet->getConditionalStylesCollection();
if (!empty($arrConditionalStyles)) {
$arrConditional = array();
// @todo CFRule & CFHeader
// Write CFHEADER record
$this->writeCFHeader();
// Write ConditionalFormattingTable records
foreach ($arrConditionalStyles as $cellCoordinate => $conditionalStyles) {
foreach ($conditionalStyles as $conditional) {
if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_EXPRESSION
|| $conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CELLIS) {
if (!in_array($conditional->getHashCode(), $arrConditional)) {
$arrConditional[] = $conditional->getHashCode();
// Write CFRULE record
$this->writeCFRule($conditional);
}
}
}
}
}
$this->storeEof();
}
/**
* Write a cell range address in BIFF8
* always fixed range
* See section 2.5.14 in OpenOffice.org's Documentation of the Microsoft Excel File Format
*
* @param string $range E.g. 'A1' or 'A1:B6'
* @return string Binary data
*/
private function writeBIFF8CellRangeAddressFixed($range = 'A1')
{
$explodes = explode(':', $range);
// extract first cell, e.g. 'A1'
$firstCell = $explodes[0];
// extract last cell, e.g. 'B6'
if (count($explodes) == 1) {
$lastCell = $firstCell;
} else {
$lastCell = $explodes[1];
}
$firstCellCoordinates = PHPExcel_Cell::coordinateFromString($firstCell); // e.g. array(0, 1)
$lastCellCoordinates = PHPExcel_Cell::coordinateFromString($lastCell); // e.g. array(1, 6)
return pack('vvvv', $firstCellCoordinates[1] - 1, $lastCellCoordinates[1] - 1, PHPExcel_Cell::columnIndexFromString($firstCellCoordinates[0]) - 1, PHPExcel_Cell::columnIndexFromString($lastCellCoordinates[0]) - 1);
}
/**
* Retrieves data from memory in one chunk, or from disk in $buffer
* sized chunks.
*
* @return string The data
*/
public function getData()
{
$buffer = 4096;
// Return data stored in memory
if (isset($this->_data)) {
$tmp = $this->_data;
unset($this->_data);
return $tmp;
}
// No data to return
return false;
}
/**
* Set the option to print the row and column headers on the printed page.
*
* @access public
* @param integer $print Whether to print the headers or not. Defaults to 1 (print).
*/
public function printRowColHeaders($print = 1)
{
$this->_print_headers = $print;
}
/**
* This method sets the properties for outlining and grouping. The defaults
* correspond to Excel's defaults.
*
* @param bool $visible
* @param bool $symbols_below
* @param bool $symbols_right
* @param bool $auto_style
*/
public function setOutline($visible = true, $symbols_below = true, $symbols_right = true, $auto_style = false)
{
$this->outlineOn = $visible;
$this->outlineBelow = $symbols_below;
$this->outlineRight = $symbols_right;
$this->outlineStyle = $auto_style;
// Ensure this is a boolean vale for Window2
if ($this->outlineOn) {
$this->outlineOn = 1;
}
}
/**
* Write a double to the specified row and column (zero indexed).
* An integer can be written as a double. Excel will display an
* integer. $format is optional.
*
* Returns 0 : normal termination
* -2 : row or column out of range
*
* @param integer $row Zero indexed row
* @param integer $col Zero indexed column
* @param float $num The number to write
* @param mixed $xfIndex The optional XF format
* @return integer
*/
private function writeNumber($row, $col, $num, $xfIndex)
{
$record = 0x0203; // Record identifier
$length = 0x000E; // Number of bytes to follow
$header = pack("vv", $record, $length);
$data = pack("vvv", $row, $col, $xfIndex);
$xl_double = pack("d", $num);
if (self::getByteOrder()) { // if it's Big Endian
$xl_double = strrev($xl_double);
}
$this->append($header.$data.$xl_double);
return(0);
}
/**
* Write a LABELSST record or a LABEL record. Which one depends on BIFF version
*
* @param int $row Row index (0-based)
* @param int $col Column index (0-based)
* @param string $str The string
* @param int $xfIndex Index to XF record
*/
private function writeString($row, $col, $str, $xfIndex)
{
$this->writeLabelSst($row, $col, $str, $xfIndex);
}
/**
* Write a LABELSST record or a LABEL record. Which one depends on BIFF version
* It differs from writeString by the writing of rich text strings.
* @param int $row Row index (0-based)
* @param int $col Column index (0-based)
* @param string $str The string
* @param mixed $xfIndex The XF format index for the cell
* @param array $arrcRun Index to Font record and characters beginning
*/
private function writeRichTextString($row, $col, $str, $xfIndex, $arrcRun)
{
$record = 0x00FD; // Record identifier
$length = 0x000A; // Bytes to follow
$str = PHPExcel_Shared_String::UTF8toBIFF8UnicodeShort($str, $arrcRun);
/* check if string is already present */
if (!isset($this->stringTable[$str])) {
$this->stringTable[$str] = $this->stringUnique++;
}
$this->stringTotal++;
$header = pack('vv', $record, $length);
$data = pack('vvvV', $row, $col, $xfIndex, $this->stringTable[$str]);
$this->append($header.$data);
}
/**
* Write a string to the specified row and column (zero indexed).
* NOTE: there is an Excel 5 defined limit of 255 characters.
* $format is optional.
* Returns 0 : normal termination
* -2 : row or column out of range
* -3 : long string truncated to 255 chars
*
* @access public
* @param integer $row Zero indexed row
* @param integer $col Zero indexed column
* @param string $str The string to write
* @param mixed $xfIndex The XF format index for the cell
* @return integer
*/
private function writeLabel($row, $col, $str, $xfIndex)
{
$strlen = strlen($str);
$record = 0x0204; // Record identifier
$length = 0x0008 + $strlen; // Bytes to follow
$str_error = 0;
if ($strlen > $this->xlsStringMaxLength) { // LABEL must be < 255 chars
$str = substr($str, 0, $this->xlsStringMaxLength);
$length = 0x0008 + $this->xlsStringMaxLength;
$strlen = $this->xlsStringMaxLength;
$str_error = -3;
}
$header = pack("vv", $record, $length);
$data = pack("vvvv", $row, $col, $xfIndex, $strlen);
$this->append($header . $data . $str);
return($str_error);
}
/**
* Write a string to the specified row and column (zero indexed).
* This is the BIFF8 version (no 255 chars limit).
* $format is optional.
* Returns 0 : normal termination
* -2 : row or column out of range
* -3 : long string truncated to 255 chars
*
* @access public
* @param integer $row Zero indexed row
* @param integer $col Zero indexed column
* @param string $str The string to write
* @param mixed $xfIndex The XF format index for the cell
* @return integer
*/
private function writeLabelSst($row, $col, $str, $xfIndex)
{
$record = 0x00FD; // Record identifier
$length = 0x000A; // Bytes to follow
$str = PHPExcel_Shared_String::UTF8toBIFF8UnicodeLong($str);
/* check if string is already present */
if (!isset($this->stringTable[$str])) {
$this->stringTable[$str] = $this->stringUnique++;
}
$this->stringTotal++;
$header = pack('vv', $record, $length);
$data = pack('vvvV', $row, $col, $xfIndex, $this->stringTable[$str]);
$this->append($header.$data);
}
/**
* Writes a note associated with the cell given by the row and column.
* NOTE records don't have a length limit.
*
* @param integer $row Zero indexed row
* @param integer $col Zero indexed column
* @param string $note The note to write
*/
private function writeNote($row, $col, $note)
{
$note_length = strlen($note);
$record = 0x001C; // Record identifier
$max_length = 2048; // Maximun length for a NOTE record
// Length for this record is no more than 2048 + 6
$length = 0x0006 + min($note_length, 2048);
$header = pack("vv", $record, $length);
$data = pack("vvv", $row, $col, $note_length);
$this->append($header . $data . substr($note, 0, 2048));
for ($i = $max_length; $i < $note_length; $i += $max_length) {
$chunk = substr($note, $i, $max_length);
$length = 0x0006 + strlen($chunk);
$header = pack("vv", $record, $length);
$data = pack("vvv", -1, 0, strlen($chunk));
$this->append($header.$data.$chunk);
}
return(0);
}
/**
* Write a blank cell to the specified row and column (zero indexed).
* A blank cell is used to specify formatting without adding a string
* or a number.
*
* A blank cell without a format serves no purpose. Therefore, we don't write
* a BLANK record unless a format is specified.
*
* Returns 0 : normal termination (including no format)
* -1 : insufficient number of arguments
* -2 : row or column out of range
*
* @param integer $row Zero indexed row
* @param integer $col Zero indexed column
* @param mixed $xfIndex The XF format index
*/
public function writeBlank($row, $col, $xfIndex)
{
$record = 0x0201; // Record identifier
$length = 0x0006; // Number of bytes to follow
$header = pack("vv", $record, $length);
$data = pack("vvv", $row, $col, $xfIndex);
$this->append($header . $data);
return 0;
}
/**
* Write a boolean or an error type to the specified row and column (zero indexed)
*
* @param int $row Row index (0-based)
* @param int $col Column index (0-based)
* @param int $value
* @param boolean $isError Error or Boolean?
* @param int $xfIndex
*/
private function writeBoolErr($row, $col, $value, $isError, $xfIndex)
{
$record = 0x0205;
$length = 8;
$header = pack("vv", $record, $length);
$data = pack("vvvCC", $row, $col, $xfIndex, $value, $isError);
$this->append($header . $data);
return 0;
}
/**
* Write a formula to the specified row and column (zero indexed).
* The textual representation of the formula is passed to the parser in
* Parser.php which returns a packed binary string.
*
* Returns 0 : normal termination
* -1 : formula errors (bad formula)
* -2 : row or column out of range
*
* @param integer $row Zero indexed row
* @param integer $col Zero indexed column
* @param string $formula The formula text string
* @param mixed $xfIndex The XF format index
* @param mixed $calculatedValue Calculated value
* @return integer
*/
private function writeFormula($row, $col, $formula, $xfIndex, $calculatedValue)
{
$record = 0x0006; // Record identifier
// Initialize possible additional value for STRING record that should be written after the FORMULA record?
$stringValue = null;
// calculated value
if (isset($calculatedValue)) {
// Since we can't yet get the data type of the calculated value,
// we use best effort to determine data type
if (is_bool($calculatedValue)) {
// Boolean value
$num = pack('CCCvCv', 0x01, 0x00, (int)$calculatedValue, 0x00, 0x00, 0xFFFF);
} elseif (is_int($calculatedValue) || is_float($calculatedValue)) {
// Numeric value
$num = pack('d', $calculatedValue);
} elseif (is_string($calculatedValue)) {
if (array_key_exists($calculatedValue, PHPExcel_Cell_DataType::getErrorCodes())) {
// Error value
$num = pack('CCCvCv', 0x02, 0x00, self::mapErrorCode($calculatedValue), 0x00, 0x00, 0xFFFF);
} elseif ($calculatedValue === '') {
// Empty string (and BIFF8)
$num = pack('CCCvCv', 0x03, 0x00, 0x00, 0x00, 0x00, 0xFFFF);
} else {
// Non-empty string value (or empty string BIFF5)
$stringValue = $calculatedValue;
$num = pack('CCCvCv', 0x00, 0x00, 0x00, 0x00, 0x00, 0xFFFF);
}
} else {
// We are really not supposed to reach here
$num = pack('d', 0x00);
}
} else {
$num = pack('d', 0x00);
}
$grbit = 0x03; // Option flags
$unknown = 0x0000; // Must be zero
// Strip the '=' or '@' sign at the beginning of the formula string
if ($formula[0] == '=') {
$formula = substr($formula, 1);
} else {
// Error handling
$this->writeString($row, $col, 'Unrecognised character for formula');
return -1;
}
// Parse the formula using the parser in Parser.php
try {
$error = $this->parser->parse($formula);
$formula = $this->parser->toReversePolish();
$formlen = strlen($formula); // Length of the binary string
$length = 0x16 + $formlen; // Length of the record data
$header = pack("vv", $record, $length);
$data = pack("vvv", $row, $col, $xfIndex)
. $num
. pack("vVv", $grbit, $unknown, $formlen);
$this->append($header . $data . $formula);
// Append also a STRING record if necessary
if ($stringValue !== null) {
$this->writeStringRecord($stringValue);
}
return 0;
} catch (PHPExcel_Exception $e) {
// do nothing
}
}
/**
* Write a STRING record. This
*
* @param string $stringValue
*/
private function writeStringRecord($stringValue)
{
$record = 0x0207; // Record identifier
$data = PHPExcel_Shared_String::UTF8toBIFF8UnicodeLong($stringValue);
$length = strlen($data);
$header = pack('vv', $record, $length);
$this->append($header . $data);
}
/**
* Write a hyperlink.
* This is comprised of two elements: the visible label and
* the invisible link. The visible label is the same as the link unless an
* alternative string is specified. The label is written using the
* writeString() method. Therefore the 255 characters string limit applies.
* $string and $format are optional.
*
* The hyperlink can be to a http, ftp, mail, internal sheet (not yet), or external
* directory url.
*
* Returns 0 : normal termination
* -2 : row or column out of range
* -3 : long string truncated to 255 chars
*
* @param integer $row Row
* @param integer $col Column
* @param string $url URL string
* @return integer
*/
private function writeUrl($row, $col, $url)
{
// Add start row and col to arg list
return($this->writeUrlRange($row, $col, $row, $col, $url));
}
/**
* This is the more general form of writeUrl(). It allows a hyperlink to be
* written to a range of cells. This function also decides the type of hyperlink
* to be written. These are either, Web (http, ftp, mailto), Internal
* (Sheet1!A1) or external ('c:\temp\foo.xls#Sheet1!A1').
*
* @access private
* @see writeUrl()
* @param integer $row1 Start row
* @param integer $col1 Start column
* @param integer $row2 End row
* @param integer $col2 End column
* @param string $url URL string
* @return integer
*/
public function writeUrlRange($row1, $col1, $row2, $col2, $url)
{
// Check for internal/external sheet links or default to web link
if (preg_match('[^internal:]', $url)) {
return($this->writeUrlInternal($row1, $col1, $row2, $col2, $url));
}
if (preg_match('[^external:]', $url)) {
return($this->writeUrlExternal($row1, $col1, $row2, $col2, $url));
}
return($this->writeUrlWeb($row1, $col1, $row2, $col2, $url));
}
/**
* Used to write http, ftp and mailto hyperlinks.
* The link type ($options) is 0x03 is the same as absolute dir ref without
* sheet. However it is differentiated by the $unknown2 data stream.
*
* @access private
* @see writeUrl()
* @param integer $row1 Start row
* @param integer $col1 Start column
* @param integer $row2 End row
* @param integer $col2 End column
* @param string $url URL string
* @return integer
*/
public function writeUrlWeb($row1, $col1, $row2, $col2, $url)
{
$record = 0x01B8; // Record identifier
$length = 0x00000; // Bytes to follow
// Pack the undocumented parts of the hyperlink stream
$unknown1 = pack("H*", "D0C9EA79F9BACE118C8200AA004BA90B02000000");
$unknown2 = pack("H*", "E0C9EA79F9BACE118C8200AA004BA90B");
// Pack the option flags
$options = pack("V", 0x03);
// Convert URL to a null terminated wchar string
$url = join("\0", preg_split("''", $url, -1, PREG_SPLIT_NO_EMPTY));
$url = $url . "\0\0\0";
// Pack the length of the URL
$url_len = pack("V", strlen($url));
// Calculate the data length
$length = 0x34 + strlen($url);
// Pack the header data
$header = pack("vv", $record, $length);
$data = pack("vvvv", $row1, $row2, $col1, $col2);
// Write the packed data
$this->append($header . $data .
$unknown1 . $options .
$unknown2 . $url_len . $url);
return 0;
}
/**
* Used to write internal reference hyperlinks such as "Sheet1!A1".
*
* @access private
* @see writeUrl()
* @param integer $row1 Start row
* @param integer $col1 Start column
* @param integer $row2 End row
* @param integer $col2 End column
* @param string $url URL string
* @return integer
*/
public function writeUrlInternal($row1, $col1, $row2, $col2, $url)
{
$record = 0x01B8; // Record identifier
$length = 0x00000; // Bytes to follow
// Strip URL type
$url = preg_replace('/^internal:/', '', $url);
// Pack the undocumented parts of the hyperlink stream
$unknown1 = pack("H*", "D0C9EA79F9BACE118C8200AA004BA90B02000000");
// Pack the option flags
$options = pack("V", 0x08);
// Convert the URL type and to a null terminated wchar string
$url .= "\0";
// character count
$url_len = PHPExcel_Shared_String::CountCharacters($url);
$url_len = pack('V', $url_len);
$url = PHPExcel_Shared_String::ConvertEncoding($url, 'UTF-16LE', 'UTF-8');
// Calculate the data length
$length = 0x24 + strlen($url);
// Pack the header data
$header = pack("vv", $record, $length);
$data = pack("vvvv", $row1, $row2, $col1, $col2);
// Write the packed data
$this->append($header . $data .
$unknown1 . $options .
$url_len . $url);
return 0;
}
/**
* Write links to external directory names such as 'c:\foo.xls',
* c:\foo.xls#Sheet1!A1', '../../foo.xls'. and '../../foo.xls#Sheet1!A1'.
*
* Note: Excel writes some relative links with the $dir_long string. We ignore
* these cases for the sake of simpler code.
*
* @access private
* @see writeUrl()
* @param integer $row1 Start row
* @param integer $col1 Start column
* @param integer $row2 End row
* @param integer $col2 End column
* @param string $url URL string
* @return integer
*/
public function writeUrlExternal($row1, $col1, $row2, $col2, $url)
{
// Network drives are different. We will handle them separately
// MS/Novell network drives and shares start with \\
if (preg_match('[^external:\\\\]', $url)) {
return; //($this->writeUrlExternal_net($row1, $col1, $row2, $col2, $url, $str, $format));
}
$record = 0x01B8; // Record identifier
$length = 0x00000; // Bytes to follow
// Strip URL type and change Unix dir separator to Dos style (if needed)
//
$url = preg_replace('/^external:/', '', $url);
$url = preg_replace('/\//', "\\", $url);
// Determine if the link is relative or absolute:
// relative if link contains no dir separator, "somefile.xls"
// relative if link starts with up-dir, "..\..\somefile.xls"
// otherwise, absolute
$absolute = 0x00; // relative path
if (preg_match('/^[A-Z]:/', $url)) {
$absolute = 0x02; // absolute path on Windows, e.g. C:\...
}
$link_type = 0x01 | $absolute;
// Determine if the link contains a sheet reference and change some of the
// parameters accordingly.
// Split the dir name and sheet name (if it exists)
$dir_long = $url;
if (preg_match("/\#/", $url)) {
$link_type |= 0x08;
}
// Pack the link type
$link_type = pack("V", $link_type);
// Calculate the up-level dir count e.g.. (..\..\..\ == 3)
$up_count = preg_match_all("/\.\.\\\/", $dir_long, $useless);
$up_count = pack("v", $up_count);
// Store the short dos dir name (null terminated)
$dir_short = preg_replace("/\.\.\\\/", '', $dir_long) . "\0";
// Store the long dir name as a wchar string (non-null terminated)
$dir_long = $dir_long . "\0";
// Pack the lengths of the dir strings
$dir_short_len = pack("V", strlen($dir_short));
$dir_long_len = pack("V", strlen($dir_long));
$stream_len = pack("V", 0); //strlen($dir_long) + 0x06);
// Pack the undocumented parts of the hyperlink stream
$unknown1 = pack("H*", 'D0C9EA79F9BACE118C8200AA004BA90B02000000');
$unknown2 = pack("H*", '0303000000000000C000000000000046');
$unknown3 = pack("H*", 'FFFFADDE000000000000000000000000000000000000000');
$unknown4 = pack("v", 0x03);
// Pack the main data stream
$data = pack("vvvv", $row1, $row2, $col1, $col2) .
$unknown1 .
$link_type .
$unknown2 .
$up_count .
$dir_short_len.
$dir_short .
$unknown3 .
$stream_len ;/*.
$dir_long_len .
$unknown4 .
$dir_long .
$sheet_len .
$sheet ;*/
// Pack the header data
$length = strlen($data);
$header = pack("vv", $record, $length);
// Write the packed data
$this->append($header. $data);
return 0;
}
/**
* This method is used to set the height and format for a row.
*
* @param integer $row The row to set
* @param integer $height Height we are giving to the row.
* Use null to set XF without setting height
* @param integer $xfIndex The optional cell style Xf index to apply to the columns
* @param bool $hidden The optional hidden attribute
* @param integer $level The optional outline level for row, in range [0,7]
*/
private function writeRow($row, $height, $xfIndex, $hidden = false, $level = 0)
{
$record = 0x0208; // Record identifier
$length = 0x0010; // Number of bytes to follow
$colMic = 0x0000; // First defined column
$colMac = 0x0000; // Last defined column
$irwMac = 0x0000; // Used by Excel to optimise loading
$reserved = 0x0000; // Reserved
$grbit = 0x0000; // Option flags
$ixfe = $xfIndex;
if ($height < 0) {
$height = null;
}
// Use writeRow($row, null, $XF) to set XF format without setting height
if ($height != null) {
$miyRw = $height * 20; // row height
} else {
$miyRw = 0xff; // default row height is 256
}
// Set the options flags. fUnsynced is used to show that the font and row
// heights are not compatible. This is usually the case for WriteExcel.
// The collapsed flag 0x10 doesn't seem to be used to indicate that a row
// is collapsed. Instead it is used to indicate that the previous row is
// collapsed. The zero height flag, 0x20, is used to collapse a row.
$grbit |= $level;
if ($hidden) {
$grbit |= 0x0030;
}
if ($height !== null) {
$grbit |= 0x0040; // fUnsynced
}
if ($xfIndex !== 0xF) {
$grbit |= 0x0080;
}
$grbit |= 0x0100;
$header = pack("vv", $record, $length);
$data = pack("vvvvvvvv", $row, $colMic, $colMac, $miyRw, $irwMac, $reserved, $grbit, $ixfe);
$this->append($header.$data);
}
/**
* Writes Excel DIMENSIONS to define the area in which there is data.
*/
private function writeDimensions()
{
$record = 0x0200; // Record identifier
$length = 0x000E;
$data = pack('VVvvv', $this->firstRowIndex, $this->lastRowIndex + 1, $this->firstColumnIndex, $this->lastColumnIndex + 1, 0x0000); // reserved
$header = pack("vv", $record, $length);
$this->append($header.$data);
}
/**
* Write BIFF record Window2.
*/
private function writeWindow2()
{
$record = 0x023E; // Record identifier
$length = 0x0012;
$grbit = 0x00B6; // Option flags
$rwTop = 0x0000; // Top row visible in window
$colLeft = 0x0000; // Leftmost column visible in window
// The options flags that comprise $grbit
$fDspFmla = 0; // 0 - bit
$fDspGrid = $this->phpSheet->getShowGridlines() ? 1 : 0; // 1
$fDspRwCol = $this->phpSheet->getShowRowColHeaders() ? 1 : 0; // 2
$fFrozen = $this->phpSheet->getFreezePane() ? 1 : 0; // 3
$fDspZeros = 1; // 4
$fDefaultHdr = 1; // 5
$fArabic = $this->phpSheet->getRightToLeft() ? 1 : 0; // 6
$fDspGuts = $this->outlineOn; // 7
$fFrozenNoSplit = 0; // 0 - bit
// no support in PHPExcel for selected sheet, therefore sheet is only selected if it is the active sheet
$fSelected = ($this->phpSheet === $this->phpSheet->getParent()->getActiveSheet()) ? 1 : 0;
$fPaged = 1; // 2
$fPageBreakPreview = $this->phpSheet->getSheetView()->getView() === PHPExcel_Worksheet_SheetView::SHEETVIEW_PAGE_BREAK_PREVIEW;
$grbit = $fDspFmla;
$grbit |= $fDspGrid << 1;
$grbit |= $fDspRwCol << 2;
$grbit |= $fFrozen << 3;
$grbit |= $fDspZeros << 4;
$grbit |= $fDefaultHdr << 5;
$grbit |= $fArabic << 6;
$grbit |= $fDspGuts << 7;
$grbit |= $fFrozenNoSplit << 8;
$grbit |= $fSelected << 9;
$grbit |= $fPaged << 10;
$grbit |= $fPageBreakPreview << 11;
$header = pack("vv", $record, $length);
$data = pack("vvv", $grbit, $rwTop, $colLeft);
// FIXME !!!
$rgbHdr = 0x0040; // Row/column heading and gridline color index
$zoom_factor_page_break = ($fPageBreakPreview ? $this->phpSheet->getSheetView()->getZoomScale() : 0x0000);
$zoom_factor_normal = $this->phpSheet->getSheetView()->getZoomScaleNormal();
$data .= pack("vvvvV", $rgbHdr, 0x0000, $zoom_factor_page_break, $zoom_factor_normal, 0x00000000);
$this->append($header.$data);
}
/**
* Write BIFF record DEFAULTROWHEIGHT.
*/
private function writeDefaultRowHeight()
{
$defaultRowHeight = $this->phpSheet->getDefaultRowDimension()->getRowHeight();
if ($defaultRowHeight < 0) {
return;
}
// convert to twips
$defaultRowHeight = (int) 20 * $defaultRowHeight;
$record = 0x0225; // Record identifier
$length = 0x0004; // Number of bytes to follow
$header = pack("vv", $record, $length);
$data = pack("vv", 1, $defaultRowHeight);
$this->append($header . $data);
}
/**
* Write BIFF record DEFCOLWIDTH if COLINFO records are in use.
*/
private function writeDefcol()
{
$defaultColWidth = 8;
$record = 0x0055; // Record identifier
$length = 0x0002; // Number of bytes to follow
$header = pack("vv", $record, $length);
$data = pack("v", $defaultColWidth);
$this->append($header . $data);
}
/**
* Write BIFF record COLINFO to define column widths
*
* Note: The SDK says the record length is 0x0B but Excel writes a 0x0C
* length record.
*
* @param array $col_array This is the only parameter received and is composed of the following:
* 0 => First formatted column,
* 1 => Last formatted column,
* 2 => Col width (8.43 is Excel default),
* 3 => The optional XF format of the column,
* 4 => Option flags.
* 5 => Optional outline level
*/
private function writeColinfo($col_array)
{
if (isset($col_array[0])) {
$colFirst = $col_array[0];
}
if (isset($col_array[1])) {
$colLast = $col_array[1];
}
if (isset($col_array[2])) {
$coldx = $col_array[2];
} else {
$coldx = 8.43;
}
if (isset($col_array[3])) {
$xfIndex = $col_array[3];
} else {
$xfIndex = 15;
}
if (isset($col_array[4])) {
$grbit = $col_array[4];
} else {
$grbit = 0;
}
if (isset($col_array[5])) {
$level = $col_array[5];
} else {
$level = 0;
}
$record = 0x007D; // Record identifier
$length = 0x000C; // Number of bytes to follow
$coldx *= 256; // Convert to units of 1/256 of a char
$ixfe = $xfIndex;
$reserved = 0x0000; // Reserved
$level = max(0, min($level, 7));
$grbit |= $level << 8;
$header = pack("vv", $record, $length);
$data = pack("vvvvvv", $colFirst, $colLast, $coldx, $ixfe, $grbit, $reserved);
$this->append($header.$data);
}
/**
* Write BIFF record SELECTION.
*/
private function writeSelection()
{
// look up the selected cell range
$selectedCells = $this->phpSheet->getSelectedCells();
$selectedCells = PHPExcel_Cell::splitRange($this->phpSheet->getSelectedCells());
$selectedCells = $selectedCells[0];
if (count($selectedCells) == 2) {
list($first, $last) = $selectedCells;
} else {
$first = $selectedCells[0];
$last = $selectedCells[0];
}
list($colFirst, $rwFirst) = PHPExcel_Cell::coordinateFromString($first);
$colFirst = PHPExcel_Cell::columnIndexFromString($colFirst) - 1; // base 0 column index
--$rwFirst; // base 0 row index
list($colLast, $rwLast) = PHPExcel_Cell::coordinateFromString($last);
$colLast = PHPExcel_Cell::columnIndexFromString($colLast) - 1; // base 0 column index
--$rwLast; // base 0 row index
// make sure we are not out of bounds
$colFirst = min($colFirst, 255);
$colLast = min($colLast, 255);
$rwFirst = min($rwFirst, 65535);
$rwLast = min($rwLast, 65535);
$record = 0x001D; // Record identifier
$length = 0x000F; // Number of bytes to follow
$pnn = $this->activePane; // Pane position
$rwAct = $rwFirst; // Active row
$colAct = $colFirst; // Active column
$irefAct = 0; // Active cell ref
$cref = 1; // Number of refs
if (!isset($rwLast)) {
$rwLast = $rwFirst; // Last row in reference
}
if (!isset($colLast)) {
$colLast = $colFirst; // Last col in reference
}
// Swap last row/col for first row/col as necessary
if ($rwFirst > $rwLast) {
list($rwFirst, $rwLast) = array($rwLast, $rwFirst);
}
if ($colFirst > $colLast) {
list($colFirst, $colLast) = array($colLast, $colFirst);
}
$header = pack("vv", $record, $length);
$data = pack("CvvvvvvCC", $pnn, $rwAct, $colAct, $irefAct, $cref, $rwFirst, $rwLast, $colFirst, $colLast);
$this->append($header . $data);
}
/**
* Store the MERGEDCELLS records for all ranges of merged cells
*/
private function writeMergedCells()
{
$mergeCells = $this->phpSheet->getMergeCells();
$countMergeCells = count($mergeCells);
if ($countMergeCells == 0) {
return;
}
// maximum allowed number of merged cells per record
$maxCountMergeCellsPerRecord = 1027;
// record identifier
$record = 0x00E5;
// counter for total number of merged cells treated so far by the writer
$i = 0;
// counter for number of merged cells written in record currently being written
$j = 0;
// initialize record data
$recordData = '';
// loop through the merged cells
foreach ($mergeCells as $mergeCell) {
++$i;
++$j;
// extract the row and column indexes
$range = PHPExcel_Cell::splitRange($mergeCell);
list($first, $last) = $range[0];
list($firstColumn, $firstRow) = PHPExcel_Cell::coordinateFromString($first);
list($lastColumn, $lastRow) = PHPExcel_Cell::coordinateFromString($last);
$recordData .= pack('vvvv', $firstRow - 1, $lastRow - 1, PHPExcel_Cell::columnIndexFromString($firstColumn) - 1, PHPExcel_Cell::columnIndexFromString($lastColumn) - 1);
// flush record if we have reached limit for number of merged cells, or reached final merged cell
if ($j == $maxCountMergeCellsPerRecord or $i == $countMergeCells) {
$recordData = pack('v', $j) . $recordData;
$length = strlen($recordData);
$header = pack('vv', $record, $length);
$this->append($header . $recordData);
// initialize for next record, if any
$recordData = '';
$j = 0;
}
}
}
/**
* Write SHEETLAYOUT record
*/
private function writeSheetLayout()
{
if (!$this->phpSheet->isTabColorSet()) {
return;
}
$recordData = pack(
'vvVVVvv',
0x0862,
0x0000, // unused
0x00000000, // unused
0x00000000, // unused
0x00000014, // size of record data
$this->colors[$this->phpSheet->getTabColor()->getRGB()], // color index
0x0000 // unused
);
$length = strlen($recordData);
$record = 0x0862; // Record identifier
$header = pack('vv', $record, $length);
$this->append($header . $recordData);
}
/**
* Write SHEETPROTECTION
*/
private function writeSheetProtection()
{
// record identifier
$record = 0x0867;
// prepare options
$options = (int) !$this->phpSheet->getProtection()->getObjects()
| (int) !$this->phpSheet->getProtection()->getScenarios() << 1
| (int) !$this->phpSheet->getProtection()->getFormatCells() << 2
| (int) !$this->phpSheet->getProtection()->getFormatColumns() << 3
| (int) !$this->phpSheet->getProtection()->getFormatRows() << 4
| (int) !$this->phpSheet->getProtection()->getInsertColumns() << 5
| (int) !$this->phpSheet->getProtection()->getInsertRows() << 6
| (int) !$this->phpSheet->getProtection()->getInsertHyperlinks() << 7
| (int) !$this->phpSheet->getProtection()->getDeleteColumns() << 8
| (int) !$this->phpSheet->getProtection()->getDeleteRows() << 9
| (int) !$this->phpSheet->getProtection()->getSelectLockedCells() << 10
| (int) !$this->phpSheet->getProtection()->getSort() << 11
| (int) !$this->phpSheet->getProtection()->getAutoFilter() << 12
| (int) !$this->phpSheet->getProtection()->getPivotTables() << 13
| (int) !$this->phpSheet->getProtection()->getSelectUnlockedCells() << 14 ;
// record data
$recordData = pack(
'vVVCVVvv',
0x0867, // repeated record identifier
0x0000, // not used
0x0000, // not used
0x00, // not used
0x01000200, // unknown data
0xFFFFFFFF, // unknown data
$options, // options
0x0000 // not used
);
$length = strlen($recordData);
$header = pack('vv', $record, $length);
$this->append($header . $recordData);
}
/**
* Write BIFF record RANGEPROTECTION
*
* Openoffice.org's Documentaion of the Microsoft Excel File Format uses term RANGEPROTECTION for these records
* Microsoft Office Excel 97-2007 Binary File Format Specification uses term FEAT for these records
*/
private function writeRangeProtection()
{
foreach ($this->phpSheet->getProtectedCells() as $range => $password) {
// number of ranges, e.g. 'A1:B3 C20:D25'
$cellRanges = explode(' ', $range);
$cref = count($cellRanges);
$recordData = pack(
'vvVVvCVvVv',
0x0868,
0x00,
0x0000,
0x0000,
0x02,
0x0,
0x0000,
$cref,
0x0000,
0x00
);
foreach ($cellRanges as $cellRange) {
$recordData .= $this->writeBIFF8CellRangeAddressFixed($cellRange);
}
// the rgbFeat structure
$recordData .= pack(
'VV',
0x0000,
hexdec($password)
);
$recordData .= PHPExcel_Shared_String::UTF8toBIFF8UnicodeLong('p' . md5($recordData));
$length = strlen($recordData);
$record = 0x0868; // Record identifier
$header = pack("vv", $record, $length);
$this->append($header . $recordData);
}
}
/**
* Write BIFF record EXTERNCOUNT to indicate the number of external sheet
* references in a worksheet.
*
* Excel only stores references to external sheets that are used in formulas.
* For simplicity we store references to all the sheets in the workbook
* regardless of whether they are used or not. This reduces the overall
* complexity and eliminates the need for a two way dialogue between the formula
* parser the worksheet objects.
*
* @param integer $count The number of external sheet references in this worksheet
*/
private function writeExterncount($count)
{
$record = 0x0016; // Record identifier
$length = 0x0002; // Number of bytes to follow
$header = pack("vv", $record, $length);
$data = pack("v", $count);
$this->append($header . $data);
}
/**
* Writes the Excel BIFF EXTERNSHEET record. These references are used by
* formulas. A formula references a sheet name via an index. Since we store a
* reference to all of the external worksheets the EXTERNSHEET index is the same
* as the worksheet index.
*
* @param string $sheetname The name of a external worksheet
*/
private function writeExternsheet($sheetname)
{
$record = 0x0017; // Record identifier
// References to the current sheet are encoded differently to references to
// external sheets.
//
if ($this->phpSheet->getTitle() == $sheetname) {
$sheetname = '';
$length = 0x02; // The following 2 bytes
$cch = 1; // The following byte
$rgch = 0x02; // Self reference
} else {
$length = 0x02 + strlen($sheetname);
$cch = strlen($sheetname);
$rgch = 0x03; // Reference to a sheet in the current workbook
}
$header = pack("vv", $record, $length);
$data = pack("CC", $cch, $rgch);
$this->append($header . $data . $sheetname);
}
/**
* Writes the Excel BIFF PANE record.
* The panes can either be frozen or thawed (unfrozen).
* Frozen panes are specified in terms of an integer number of rows and columns.
* Thawed panes are specified in terms of Excel's units for rows and columns.
*/
private function writePanes()
{
$panes = array();
if ($freezePane = $this->phpSheet->getFreezePane()) {
list($column, $row) = PHPExcel_Cell::coordinateFromString($freezePane);
$panes[0] = $row - 1;
$panes[1] = PHPExcel_Cell::columnIndexFromString($column) - 1;
} else {
// thaw panes
return;
}
$y = isset($panes[0]) ? $panes[0] : null;
$x = isset($panes[1]) ? $panes[1] : null;
$rwTop = isset($panes[2]) ? $panes[2] : null;
$colLeft = isset($panes[3]) ? $panes[3] : null;
if (count($panes) > 4) { // if Active pane was received
$pnnAct = $panes[4];
} else {
$pnnAct = null;
}
$record = 0x0041; // Record identifier
$length = 0x000A; // Number of bytes to follow
// Code specific to frozen or thawed panes.
if ($this->phpSheet->getFreezePane()) {
// Set default values for $rwTop and $colLeft
if (!isset($rwTop)) {
$rwTop = $y;
}
if (!isset($colLeft)) {
$colLeft = $x;
}
} else {
// Set default values for $rwTop and $colLeft
if (!isset($rwTop)) {
$rwTop = 0;
}
if (!isset($colLeft)) {
$colLeft = 0;
}
// Convert Excel's row and column units to the internal units.
// The default row height is 12.75
// The default column width is 8.43
// The following slope and intersection values were interpolated.
//
$y = 20*$y + 255;
$x = 113.879*$x + 390;
}
// Determine which pane should be active. There is also the undocumented
// option to override this should it be necessary: may be removed later.
//
if (!isset($pnnAct)) {
if ($x != 0 && $y != 0) {
$pnnAct = 0; // Bottom right
}
if ($x != 0 && $y == 0) {
$pnnAct = 1; // Top right
}
if ($x == 0 && $y != 0) {
$pnnAct = 2; // Bottom left
}
if ($x == 0 && $y == 0) {
$pnnAct = 3; // Top left
}
}
$this->activePane = $pnnAct; // Used in writeSelection
$header = pack("vv", $record, $length);
$data = pack("vvvvv", $x, $y, $rwTop, $colLeft, $pnnAct);
$this->append($header . $data);
}
/**
* Store the page setup SETUP BIFF record.
*/
private function writeSetup()
{
$record = 0x00A1; // Record identifier
$length = 0x0022; // Number of bytes to follow
$iPaperSize = $this->phpSheet->getPageSetup()->getPaperSize(); // Paper size
$iScale = $this->phpSheet->getPageSetup()->getScale() ?
$this->phpSheet->getPageSetup()->getScale() : 100; // Print scaling factor
$iPageStart = 0x01; // Starting page number
$iFitWidth = (int) $this->phpSheet->getPageSetup()->getFitToWidth(); // Fit to number of pages wide
$iFitHeight = (int) $this->phpSheet->getPageSetup()->getFitToHeight(); // Fit to number of pages high
$grbit = 0x00; // Option flags
$iRes = 0x0258; // Print resolution
$iVRes = 0x0258; // Vertical print resolution
$numHdr = $this->phpSheet->getPageMargins()->getHeader(); // Header Margin
$numFtr = $this->phpSheet->getPageMargins()->getFooter(); // Footer Margin
$iCopies = 0x01; // Number of copies
$fLeftToRight = 0x0; // Print over then down
// Page orientation
$fLandscape = ($this->phpSheet->getPageSetup()->getOrientation() == PHPExcel_Worksheet_PageSetup::ORIENTATION_LANDSCAPE) ?
0x0 : 0x1;
$fNoPls = 0x0; // Setup not read from printer
$fNoColor = 0x0; // Print black and white
$fDraft = 0x0; // Print draft quality
$fNotes = 0x0; // Print notes
$fNoOrient = 0x0; // Orientation not set
$fUsePage = 0x0; // Use custom starting page
$grbit = $fLeftToRight;
$grbit |= $fLandscape << 1;
$grbit |= $fNoPls << 2;
$grbit |= $fNoColor << 3;
$grbit |= $fDraft << 4;
$grbit |= $fNotes << 5;
$grbit |= $fNoOrient << 6;
$grbit |= $fUsePage << 7;
$numHdr = pack("d", $numHdr);
$numFtr = pack("d", $numFtr);
if (self::getByteOrder()) { // if it's Big Endian
$numHdr = strrev($numHdr);
$numFtr = strrev($numFtr);
}
$header = pack("vv", $record, $length);
$data1 = pack("vvvvvvvv", $iPaperSize, $iScale, $iPageStart, $iFitWidth, $iFitHeight, $grbit, $iRes, $iVRes);
$data2 = $numHdr.$numFtr;
$data3 = pack("v", $iCopies);
$this->append($header . $data1 . $data2 . $data3);
}
/**
* Store the header caption BIFF record.
*/
private function writeHeader()
{
$record = 0x0014; // Record identifier
/* removing for now
// need to fix character count (multibyte!)
if (strlen($this->phpSheet->getHeaderFooter()->getOddHeader()) <= 255) {
$str = $this->phpSheet->getHeaderFooter()->getOddHeader(); // header string
} else {
$str = '';
}
*/
$recordData = PHPExcel_Shared_String::UTF8toBIFF8UnicodeLong($this->phpSheet->getHeaderFooter()->getOddHeader());
$length = strlen($recordData);
$header = pack("vv", $record, $length);
$this->append($header . $recordData);
}
/**
* Store the footer caption BIFF record.
*/
private function writeFooter()
{
$record = 0x0015; // Record identifier
/* removing for now
// need to fix character count (multibyte!)
if (strlen($this->phpSheet->getHeaderFooter()->getOddFooter()) <= 255) {
$str = $this->phpSheet->getHeaderFooter()->getOddFooter();
} else {
$str = '';
}
*/
$recordData = PHPExcel_Shared_String::UTF8toBIFF8UnicodeLong($this->phpSheet->getHeaderFooter()->getOddFooter());
$length = strlen($recordData);
$header = pack("vv", $record, $length);
$this->append($header . $recordData);
}
/**
* Store the horizontal centering HCENTER BIFF record.
*
* @access private
*/
private function writeHcenter()
{
$record = 0x0083; // Record identifier
$length = 0x0002; // Bytes to follow
$fHCenter = $this->phpSheet->getPageSetup()->getHorizontalCentered() ? 1 : 0; // Horizontal centering
$header = pack("vv", $record, $length);
$data = pack("v", $fHCenter);
$this->append($header.$data);
}
/**
* Store the vertical centering VCENTER BIFF record.
*/
private function writeVcenter()
{
$record = 0x0084; // Record identifier
$length = 0x0002; // Bytes to follow
$fVCenter = $this->phpSheet->getPageSetup()->getVerticalCentered() ? 1 : 0; // Horizontal centering
$header = pack("vv", $record, $length);
$data = pack("v", $fVCenter);
$this->append($header . $data);
}
/**
* Store the LEFTMARGIN BIFF record.
*/
private function writeMarginLeft()
{
$record = 0x0026; // Record identifier
$length = 0x0008; // Bytes to follow
$margin = $this->phpSheet->getPageMargins()->getLeft(); // Margin in inches
$header = pack("vv", $record, $length);
$data = pack("d", $margin);
if (self::getByteOrder()) { // if it's Big Endian
$data = strrev($data);
}
$this->append($header . $data);
}
/**
* Store the RIGHTMARGIN BIFF record.
*/
private function writeMarginRight()
{
$record = 0x0027; // Record identifier
$length = 0x0008; // Bytes to follow
$margin = $this->phpSheet->getPageMargins()->getRight(); // Margin in inches
$header = pack("vv", $record, $length);
$data = pack("d", $margin);
if (self::getByteOrder()) { // if it's Big Endian
$data = strrev($data);
}
$this->append($header . $data);
}
/**
* Store the TOPMARGIN BIFF record.
*/
private function writeMarginTop()
{
$record = 0x0028; // Record identifier
$length = 0x0008; // Bytes to follow
$margin = $this->phpSheet->getPageMargins()->getTop(); // Margin in inches
$header = pack("vv", $record, $length);
$data = pack("d", $margin);
if (self::getByteOrder()) { // if it's Big Endian
$data = strrev($data);
}
$this->append($header . $data);
}
/**
* Store the BOTTOMMARGIN BIFF record.
*/
private function writeMarginBottom()
{
$record = 0x0029; // Record identifier
$length = 0x0008; // Bytes to follow
$margin = $this->phpSheet->getPageMargins()->getBottom(); // Margin in inches
$header = pack("vv", $record, $length);
$data = pack("d", $margin);
if (self::getByteOrder()) { // if it's Big Endian
$data = strrev($data);
}
$this->append($header . $data);
}
/**
* Write the PRINTHEADERS BIFF record.
*/
private function writePrintHeaders()
{
$record = 0x002a; // Record identifier
$length = 0x0002; // Bytes to follow
$fPrintRwCol = $this->_print_headers; // Boolean flag
$header = pack("vv", $record, $length);
$data = pack("v", $fPrintRwCol);
$this->append($header . $data);
}
/**
* Write the PRINTGRIDLINES BIFF record. Must be used in conjunction with the
* GRIDSET record.
*/
private function writePrintGridlines()
{
$record = 0x002b; // Record identifier
$length = 0x0002; // Bytes to follow
$fPrintGrid = $this->phpSheet->getPrintGridlines() ? 1 : 0; // Boolean flag
$header = pack("vv", $record, $length);
$data = pack("v", $fPrintGrid);
$this->append($header . $data);
}
/**
* Write the GRIDSET BIFF record. Must be used in conjunction with the
* PRINTGRIDLINES record.
*/
private function writeGridset()
{
$record = 0x0082; // Record identifier
$length = 0x0002; // Bytes to follow
$fGridSet = !$this->phpSheet->getPrintGridlines(); // Boolean flag
$header = pack("vv", $record, $length);
$data = pack("v", $fGridSet);
$this->append($header . $data);
}
/**
* Write the AUTOFILTERINFO BIFF record. This is used to configure the number of autofilter select used in the sheet.
*/
private function writeAutoFilterInfo()
{
$record = 0x009D; // Record identifier
$length = 0x0002; // Bytes to follow
$rangeBounds = PHPExcel_Cell::rangeBoundaries($this->phpSheet->getAutoFilter()->getRange());
$iNumFilters = 1 + $rangeBounds[1][0] - $rangeBounds[0][0];
$header = pack("vv", $record, $length);
$data = pack("v", $iNumFilters);
$this->append($header . $data);
}
/**
* Write the GUTS BIFF record. This is used to configure the gutter margins
* where Excel outline symbols are displayed. The visibility of the gutters is
* controlled by a flag in WSBOOL.
*
* @see writeWsbool()
*/
private function writeGuts()
{
$record = 0x0080; // Record identifier
$length = 0x0008; // Bytes to follow
$dxRwGut = 0x0000; // Size of row gutter
$dxColGut = 0x0000; // Size of col gutter
// determine maximum row outline level
$maxRowOutlineLevel = 0;
foreach ($this->phpSheet->getRowDimensions() as $rowDimension) {
$maxRowOutlineLevel = max($maxRowOutlineLevel, $rowDimension->getOutlineLevel());
}
$col_level = 0;
// Calculate the maximum column outline level. The equivalent calculation
// for the row outline level is carried out in writeRow().
$colcount = count($this->columnInfo);
for ($i = 0; $i < $colcount; ++$i) {
$col_level = max($this->columnInfo[$i][5], $col_level);
}
// Set the limits for the outline levels (0 <= x <= 7).
$col_level = max(0, min($col_level, 7));
// The displayed level is one greater than the max outline levels
if ($maxRowOutlineLevel) {
++$maxRowOutlineLevel;
}
if ($col_level) {
++$col_level;
}
$header = pack("vv", $record, $length);
$data = pack("vvvv", $dxRwGut, $dxColGut, $maxRowOutlineLevel, $col_level);
$this->append($header.$data);
}
/**
* Write the WSBOOL BIFF record, mainly for fit-to-page. Used in conjunction
* with the SETUP record.
*/
private function writeWsbool()
{
$record = 0x0081; // Record identifier
$length = 0x0002; // Bytes to follow
$grbit = 0x0000;
// The only option that is of interest is the flag for fit to page. So we
// set all the options in one go.
//
// Set the option flags
$grbit |= 0x0001; // Auto page breaks visible
if ($this->outlineStyle) {
$grbit |= 0x0020; // Auto outline styles
}
if ($this->phpSheet->getShowSummaryBelow()) {
$grbit |= 0x0040; // Outline summary below
}
if ($this->phpSheet->getShowSummaryRight()) {
$grbit |= 0x0080; // Outline summary right
}
if ($this->phpSheet->getPageSetup()->getFitToPage()) {
$grbit |= 0x0100; // Page setup fit to page
}
if ($this->outlineOn) {
$grbit |= 0x0400; // Outline symbols displayed
}
$header = pack("vv", $record, $length);
$data = pack("v", $grbit);
$this->append($header . $data);
}
/**
* Write the HORIZONTALPAGEBREAKS and VERTICALPAGEBREAKS BIFF records.
*/
private function writeBreaks()
{
// initialize
$vbreaks = array();
$hbreaks = array();
foreach ($this->phpSheet->getBreaks() as $cell => $breakType) {
// Fetch coordinates
$coordinates = PHPExcel_Cell::coordinateFromString($cell);
// Decide what to do by the type of break
switch ($breakType) {
case PHPExcel_Worksheet::BREAK_COLUMN:
// Add to list of vertical breaks
$vbreaks[] = PHPExcel_Cell::columnIndexFromString($coordinates[0]) - 1;
break;
case PHPExcel_Worksheet::BREAK_ROW:
// Add to list of horizontal breaks
$hbreaks[] = $coordinates[1];
break;
case PHPExcel_Worksheet::BREAK_NONE:
default:
// Nothing to do
break;
}
}
//horizontal page breaks
if (!empty($hbreaks)) {
// Sort and filter array of page breaks
sort($hbreaks, SORT_NUMERIC);
if ($hbreaks[0] == 0) { // don't use first break if it's 0
array_shift($hbreaks);
}
$record = 0x001b; // Record identifier
$cbrk = count($hbreaks); // Number of page breaks
$length = 2 + 6 * $cbrk; // Bytes to follow
$header = pack("vv", $record, $length);
$data = pack("v", $cbrk);
// Append each page break
foreach ($hbreaks as $hbreak) {
$data .= pack("vvv", $hbreak, 0x0000, 0x00ff);
}
$this->append($header . $data);
}
// vertical page breaks
if (!empty($vbreaks)) {
// 1000 vertical pagebreaks appears to be an internal Excel 5 limit.
// It is slightly higher in Excel 97/200, approx. 1026
$vbreaks = array_slice($vbreaks, 0, 1000);
// Sort and filter array of page breaks
sort($vbreaks, SORT_NUMERIC);
if ($vbreaks[0] == 0) { // don't use first break if it's 0
array_shift($vbreaks);
}
$record = 0x001a; // Record identifier
$cbrk = count($vbreaks); // Number of page breaks
$length = 2 + 6 * $cbrk; // Bytes to follow
$header = pack("vv", $record, $length);
$data = pack("v", $cbrk);
// Append each page break
foreach ($vbreaks as $vbreak) {
$data .= pack("vvv", $vbreak, 0x0000, 0xffff);
}
$this->append($header . $data);
}
}
/**
* Set the Biff PROTECT record to indicate that the worksheet is protected.
*/
private function writeProtect()
{
// Exit unless sheet protection has been specified
if (!$this->phpSheet->getProtection()->getSheet()) {
return;
}
$record = 0x0012; // Record identifier
$length = 0x0002; // Bytes to follow
$fLock = 1; // Worksheet is protected
$header = pack("vv", $record, $length);
$data = pack("v", $fLock);
$this->append($header.$data);
}
/**
* Write SCENPROTECT
*/
private function writeScenProtect()
{
// Exit if sheet protection is not active
if (!$this->phpSheet->getProtection()->getSheet()) {
return;
}
// Exit if scenarios are not protected
if (!$this->phpSheet->getProtection()->getScenarios()) {
return;
}
$record = 0x00DD; // Record identifier
$length = 0x0002; // Bytes to follow
$header = pack('vv', $record, $length);
$data = pack('v', 1);
$this->append($header . $data);
}
/**
* Write OBJECTPROTECT
*/
private function writeObjectProtect()
{
// Exit if sheet protection is not active
if (!$this->phpSheet->getProtection()->getSheet()) {
return;
}
// Exit if objects are not protected
if (!$this->phpSheet->getProtection()->getObjects()) {
return;
}
$record = 0x0063; // Record identifier
$length = 0x0002; // Bytes to follow
$header = pack('vv', $record, $length);
$data = pack('v', 1);
$this->append($header . $data);
}
/**
* Write the worksheet PASSWORD record.
*/
private function writePassword()
{
// Exit unless sheet protection and password have been specified
if (!$this->phpSheet->getProtection()->getSheet() || !$this->phpSheet->getProtection()->getPassword()) {
return;
}
$record = 0x0013; // Record identifier
$length = 0x0002; // Bytes to follow
$wPassword = hexdec($this->phpSheet->getProtection()->getPassword()); // Encoded password
$header = pack("vv", $record, $length);
$data = pack("v", $wPassword);
$this->append($header . $data);
}
/**
* Insert a 24bit bitmap image in a worksheet.
*
* @access public
* @param integer $row The row we are going to insert the bitmap into
* @param integer $col The column we are going to insert the bitmap into
* @param mixed $bitmap The bitmap filename or GD-image resource
* @param integer $x The horizontal position (offset) of the image inside the cell.
* @param integer $y The vertical position (offset) of the image inside the cell.
* @param float $scale_x The horizontal scale
* @param float $scale_y The vertical scale
*/
public function insertBitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1)
{
$bitmap_array = (is_resource($bitmap) ? $this->processBitmapGd($bitmap) : $this->processBitmap($bitmap));
list($width, $height, $size, $data) = $bitmap_array; //$this->processBitmap($bitmap);
// Scale the frame of the image.
$width *= $scale_x;
$height *= $scale_y;
// Calculate the vertices of the image and write the OBJ record
$this->positionImage($col, $row, $x, $y, $width, $height);
// Write the IMDATA record to store the bitmap data
$record = 0x007f;
$length = 8 + $size;
$cf = 0x09;
$env = 0x01;
$lcb = $size;
$header = pack("vvvvV", $record, $length, $cf, $env, $lcb);
$this->append($header.$data);
}
/**
* Calculate the vertices that define the position of the image as required by
* the OBJ record.
*
* +------------+------------+
* | A | B |
* +-----+------------+------------+
* | |(x1,y1) | |
* | 1 |(A1)._______|______ |
* | | | | |
* | | | | |
* +-----+----| BITMAP |-----+
* | | | | |
* | 2 | |______________. |
* | | | (B2)|
* | | | (x2,y2)|
* +---- +------------+------------+
*
* Example of a bitmap that covers some of the area from cell A1 to cell B2.
*
* Based on the width and height of the bitmap we need to calculate 8 vars:
* $col_start, $row_start, $col_end, $row_end, $x1, $y1, $x2, $y2.
* The width and height of the cells are also variable and have to be taken into
* account.
* The values of $col_start and $row_start are passed in from the calling
* function. The values of $col_end and $row_end are calculated by subtracting
* the width and height of the bitmap from the width and height of the
* underlying cells.
* The vertices are expressed as a percentage of the underlying cell width as
* follows (rhs values are in pixels):
*
* x1 = X / W *1024
* y1 = Y / H *256
* x2 = (X-1) / W *1024
* y2 = (Y-1) / H *256
*
* Where: X is distance from the left side of the underlying cell
* Y is distance from the top of the underlying cell
* W is the width of the cell
* H is the height of the cell
* The SDK incorrectly states that the height should be expressed as a
* percentage of 1024.
*
* @access private
* @param integer $col_start Col containing upper left corner of object
* @param integer $row_start Row containing top left corner of object
* @param integer $x1 Distance to left side of object
* @param integer $y1 Distance to top of object
* @param integer $width Width of image frame
* @param integer $height Height of image frame
*/
public function positionImage($col_start, $row_start, $x1, $y1, $width, $height)
{
// Initialise end cell to the same as the start cell
$col_end = $col_start; // Col containing lower right corner of object
$row_end = $row_start; // Row containing bottom right corner of object
// Zero the specified offset if greater than the cell dimensions
if ($x1 >= PHPExcel_Shared_Excel5::sizeCol($this->phpSheet, PHPExcel_Cell::stringFromColumnIndex($col_start))) {
$x1 = 0;
}
if ($y1 >= PHPExcel_Shared_Excel5::sizeRow($this->phpSheet, $row_start + 1)) {
$y1 = 0;
}
$width = $width + $x1 -1;
$height = $height + $y1 -1;
// Subtract the underlying cell widths to find the end cell of the image
while ($width >= PHPExcel_Shared_Excel5::sizeCol($this->phpSheet, PHPExcel_Cell::stringFromColumnIndex($col_end))) {
$width -= PHPExcel_Shared_Excel5::sizeCol($this->phpSheet, PHPExcel_Cell::stringFromColumnIndex($col_end));
++$col_end;
}
// Subtract the underlying cell heights to find the end cell of the image
while ($height >= PHPExcel_Shared_Excel5::sizeRow($this->phpSheet, $row_end + 1)) {
$height -= PHPExcel_Shared_Excel5::sizeRow($this->phpSheet, $row_end + 1);
++$row_end;
}
// Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell
// with zero eight or width.
//
if (PHPExcel_Shared_Excel5::sizeCol($this->phpSheet, PHPExcel_Cell::stringFromColumnIndex($col_start)) == 0) {
return;
}
if (PHPExcel_Shared_Excel5::sizeCol($this->phpSheet, PHPExcel_Cell::stringFromColumnIndex($col_end)) == 0) {
return;
}
if (PHPExcel_Shared_Excel5::sizeRow($this->phpSheet, $row_start + 1) == 0) {
return;
}
if (PHPExcel_Shared_Excel5::sizeRow($this->phpSheet, $row_end + 1) == 0) {
return;
}
// Convert the pixel values to the percentage value expected by Excel
$x1 = $x1 / PHPExcel_Shared_Excel5::sizeCol($this->phpSheet, PHPExcel_Cell::stringFromColumnIndex($col_start)) * 1024;
$y1 = $y1 / PHPExcel_Shared_Excel5::sizeRow($this->phpSheet, $row_start + 1) * 256;
$x2 = $width / PHPExcel_Shared_Excel5::sizeCol($this->phpSheet, PHPExcel_Cell::stringFromColumnIndex($col_end)) * 1024; // Distance to right side of object
$y2 = $height / PHPExcel_Shared_Excel5::sizeRow($this->phpSheet, $row_end + 1) * 256; // Distance to bottom of object
$this->writeObjPicture($col_start, $x1, $row_start, $y1, $col_end, $x2, $row_end, $y2);
}
/**
* Store the OBJ record that precedes an IMDATA record. This could be generalise
* to support other Excel objects.
*
* @param integer $colL Column containing upper left corner of object
* @param integer $dxL Distance from left side of cell
* @param integer $rwT Row containing top left corner of object
* @param integer $dyT Distance from top of cell
* @param integer $colR Column containing lower right corner of object
* @param integer $dxR Distance from right of cell
* @param integer $rwB Row containing bottom right corner of object
* @param integer $dyB Distance from bottom of cell
*/
private function writeObjPicture($colL, $dxL, $rwT, $dyT, $colR, $dxR, $rwB, $dyB)
{
$record = 0x005d; // Record identifier
$length = 0x003c; // Bytes to follow
$cObj = 0x0001; // Count of objects in file (set to 1)
$OT = 0x0008; // Object type. 8 = Picture
$id = 0x0001; // Object ID
$grbit = 0x0614; // Option flags
$cbMacro = 0x0000; // Length of FMLA structure
$Reserved1 = 0x0000; // Reserved
$Reserved2 = 0x0000; // Reserved
$icvBack = 0x09; // Background colour
$icvFore = 0x09; // Foreground colour
$fls = 0x00; // Fill pattern
$fAuto = 0x00; // Automatic fill
$icv = 0x08; // Line colour
$lns = 0xff; // Line style
$lnw = 0x01; // Line weight
$fAutoB = 0x00; // Automatic border
$frs = 0x0000; // Frame style
$cf = 0x0009; // Image format, 9 = bitmap
$Reserved3 = 0x0000; // Reserved
$cbPictFmla = 0x0000; // Length of FMLA structure
$Reserved4 = 0x0000; // Reserved
$grbit2 = 0x0001; // Option flags
$Reserved5 = 0x0000; // Reserved
$header = pack("vv", $record, $length);
$data = pack("V", $cObj);
$data .= pack("v", $OT);
$data .= pack("v", $id);
$data .= pack("v", $grbit);
$data .= pack("v", $colL);
$data .= pack("v", $dxL);
$data .= pack("v", $rwT);
$data .= pack("v", $dyT);
$data .= pack("v", $colR);
$data .= pack("v", $dxR);
$data .= pack("v", $rwB);
$data .= pack("v", $dyB);
$data .= pack("v", $cbMacro);
$data .= pack("V", $Reserved1);
$data .= pack("v", $Reserved2);
$data .= pack("C", $icvBack);
$data .= pack("C", $icvFore);
$data .= pack("C", $fls);
$data .= pack("C", $fAuto);
$data .= pack("C", $icv);
$data .= pack("C", $lns);
$data .= pack("C", $lnw);
$data .= pack("C", $fAutoB);
$data .= pack("v", $frs);
$data .= pack("V", $cf);
$data .= pack("v", $Reserved3);
$data .= pack("v", $cbPictFmla);
$data .= pack("v", $Reserved4);
$data .= pack("v", $grbit2);
$data .= pack("V", $Reserved5);
$this->append($header . $data);
}
/**
* Convert a GD-image into the internal format.
*
* @access private
* @param resource $image The image to process
* @return array Array with data and properties of the bitmap
*/
public function processBitmapGd($image)
{
$width = imagesx($image);
$height = imagesy($image);
$data = pack("Vvvvv", 0x000c, $width, $height, 0x01, 0x18);
for ($j=$height; $j--;) {
for ($i=0; $i < $width; ++$i) {
$color = imagecolorsforindex($image, imagecolorat($image, $i, $j));
foreach (array("red", "green", "blue") as $key) {
$color[$key] = $color[$key] + round((255 - $color[$key]) * $color["alpha"] / 127);
}
$data .= chr($color["blue"]) . chr($color["green"]) . chr($color["red"]);
}
if (3*$width % 4) {
$data .= str_repeat("\x00", 4 - 3*$width % 4);
}
}
return array($width, $height, strlen($data), $data);
}
/**
* Convert a 24 bit bitmap into the modified internal format used by Windows.
* This is described in BITMAPCOREHEADER and BITMAPCOREINFO structures in the
* MSDN library.
*
* @access private
* @param string $bitmap The bitmap to process
* @return array Array with data and properties of the bitmap
*/
public function processBitmap($bitmap)
{
// Open file.
$bmp_fd = @fopen($bitmap, "rb");
if (!$bmp_fd) {
throw new PHPExcel_Writer_Exception("Couldn't import $bitmap");
}
// Slurp the file into a string.
$data = fread($bmp_fd, filesize($bitmap));
// Check that the file is big enough to be a bitmap.
if (strlen($data) <= 0x36) {
throw new PHPExcel_Writer_Exception("$bitmap doesn't contain enough data.\n");
}
// The first 2 bytes are used to identify the bitmap.
$identity = unpack("A2ident", $data);
if ($identity['ident'] != "BM") {
throw new PHPExcel_Writer_Exception("$bitmap doesn't appear to be a valid bitmap image.\n");
}
// Remove bitmap data: ID.
$data = substr($data, 2);
// Read and remove the bitmap size. This is more reliable than reading
// the data size at offset 0x22.
//
$size_array = unpack("Vsa", substr($data, 0, 4));
$size = $size_array['sa'];
$data = substr($data, 4);
$size -= 0x36; // Subtract size of bitmap header.
$size += 0x0C; // Add size of BIFF header.
// Remove bitmap data: reserved, offset, header length.
$data = substr($data, 12);
// Read and remove the bitmap width and height. Verify the sizes.
$width_and_height = unpack("V2", substr($data, 0, 8));
$width = $width_and_height[1];
$height = $width_and_height[2];
$data = substr($data, 8);
if ($width > 0xFFFF) {
throw new PHPExcel_Writer_Exception("$bitmap: largest image width supported is 65k.\n");
}
if ($height > 0xFFFF) {
throw new PHPExcel_Writer_Exception("$bitmap: largest image height supported is 65k.\n");
}
// Read and remove the bitmap planes and bpp data. Verify them.
$planes_and_bitcount = unpack("v2", substr($data, 0, 4));
$data = substr($data, 4);
if ($planes_and_bitcount[2] != 24) { // Bitcount
throw new PHPExcel_Writer_Exception("$bitmap isn't a 24bit true color bitmap.\n");
}
if ($planes_and_bitcount[1] != 1) {
throw new PHPExcel_Writer_Exception("$bitmap: only 1 plane supported in bitmap image.\n");
}
// Read and remove the bitmap compression. Verify compression.
$compression = unpack("Vcomp", substr($data, 0, 4));
$data = substr($data, 4);
//$compression = 0;
if ($compression['comp'] != 0) {
throw new PHPExcel_Writer_Exception("$bitmap: compression not supported in bitmap image.\n");
}
// Remove bitmap data: data size, hres, vres, colours, imp. colours.
$data = substr($data, 20);
// Add the BITMAPCOREHEADER data
$header = pack("Vvvvv", 0x000c, $width, $height, 0x01, 0x18);
$data = $header . $data;
return (array($width, $height, $size, $data));
}
/**
* Store the window zoom factor. This should be a reduced fraction but for
* simplicity we will store all fractions with a numerator of 100.
*/
private function writeZoom()
{
// If scale is 100 we don't need to write a record
if ($this->phpSheet->getSheetView()->getZoomScale() == 100) {
return;
}
$record = 0x00A0; // Record identifier
$length = 0x0004; // Bytes to follow
$header = pack("vv", $record, $length);
$data = pack("vv", $this->phpSheet->getSheetView()->getZoomScale(), 100);
$this->append($header . $data);
}
/**
* Get Escher object
*
* @return PHPExcel_Shared_Escher
*/
public function getEscher()
{
return $this->escher;
}
/**
* Set Escher object
*
* @param PHPExcel_Shared_Escher $pValue
*/
public function setEscher(PHPExcel_Shared_Escher $pValue = null)
{
$this->escher = $pValue;
}
/**
* Write MSODRAWING record
*/
private function writeMsoDrawing()
{
// write the Escher stream if necessary
if (isset($this->escher)) {
$writer = new PHPExcel_Writer_Excel5_Escher($this->escher);
$data = $writer->close();
$spOffsets = $writer->getSpOffsets();
$spTypes = $writer->getSpTypes();
// write the neccesary MSODRAWING, OBJ records
// split the Escher stream
$spOffsets[0] = 0;
$nm = count($spOffsets) - 1; // number of shapes excluding first shape
for ($i = 1; $i <= $nm; ++$i) {
// MSODRAWING record
$record = 0x00EC; // Record identifier
// chunk of Escher stream for one shape
$dataChunk = substr($data, $spOffsets[$i -1], $spOffsets[$i] - $spOffsets[$i - 1]);
$length = strlen($dataChunk);
$header = pack("vv", $record, $length);
$this->append($header . $dataChunk);
// OBJ record
$record = 0x005D; // record identifier
$objData = '';
// ftCmo
if ($spTypes[$i] == 0x00C9) {
// Add ftCmo (common object data) subobject
$objData .=
pack(
'vvvvvVVV',
0x0015, // 0x0015 = ftCmo
0x0012, // length of ftCmo data
0x0014, // object type, 0x0014 = filter
$i, // object id number, Excel seems to use 1-based index, local for the sheet
0x2101, // option flags, 0x2001 is what OpenOffice.org uses
0, // reserved
0, // reserved
0 // reserved
);
// Add ftSbs Scroll bar subobject
$objData .= pack('vv', 0x00C, 0x0014);
$objData .= pack('H*', '0000000000000000640001000A00000010000100');
// Add ftLbsData (List box data) subobject
$objData .= pack('vv', 0x0013, 0x1FEE);
$objData .= pack('H*', '00000000010001030000020008005700');
} else {
// Add ftCmo (common object data) subobject
$objData .=
pack(
'vvvvvVVV',
0x0015, // 0x0015 = ftCmo
0x0012, // length of ftCmo data
0x0008, // object type, 0x0008 = picture
$i, // object id number, Excel seems to use 1-based index, local for the sheet
0x6011, // option flags, 0x6011 is what OpenOffice.org uses
0, // reserved
0, // reserved
0 // reserved
);
}
// ftEnd
$objData .=
pack(
'vv',
0x0000, // 0x0000 = ftEnd
0x0000 // length of ftEnd data
);
$length = strlen($objData);
$header = pack('vv', $record, $length);
$this->append($header . $objData);
}
}
}
/**
* Store the DATAVALIDATIONS and DATAVALIDATION records.
*/
private function writeDataValidity()
{
// Datavalidation collection
$dataValidationCollection = $this->phpSheet->getDataValidationCollection();
// Write data validations?
if (!empty($dataValidationCollection)) {
// DATAVALIDATIONS record
$record = 0x01B2; // Record identifier
$length = 0x0012; // Bytes to follow
$grbit = 0x0000; // Prompt box at cell, no cached validity data at DV records
$horPos = 0x00000000; // Horizontal position of prompt box, if fixed position
$verPos = 0x00000000; // Vertical position of prompt box, if fixed position
$objId = 0xFFFFFFFF; // Object identifier of drop down arrow object, or -1 if not visible
$header = pack('vv', $record, $length);
$data = pack('vVVVV', $grbit, $horPos, $verPos, $objId, count($dataValidationCollection));
$this->append($header.$data);
// DATAVALIDATION records
$record = 0x01BE; // Record identifier
foreach ($dataValidationCollection as $cellCoordinate => $dataValidation) {
// initialize record data
$data = '';
// options
$options = 0x00000000;
// data type
$type = $dataValidation->getType();
switch ($type) {
case PHPExcel_Cell_DataValidation::TYPE_NONE:
$type = 0x00;
break;
case PHPExcel_Cell_DataValidation::TYPE_WHOLE:
$type = 0x01;
break;
case PHPExcel_Cell_DataValidation::TYPE_DECIMAL:
$type = 0x02;
break;
case PHPExcel_Cell_DataValidation::TYPE_LIST:
$type = 0x03;
break;
case PHPExcel_Cell_DataValidation::TYPE_DATE:
$type = 0x04;
break;
case PHPExcel_Cell_DataValidation::TYPE_TIME:
$type = 0x05;
break;
case PHPExcel_Cell_DataValidation::TYPE_TEXTLENGTH:
$type = 0x06;
break;
case PHPExcel_Cell_DataValidation::TYPE_CUSTOM:
$type = 0x07;
break;
}
$options |= $type << 0;
// error style
$errorStyle = $dataValidation->getType();
switch ($errorStyle) {
case PHPExcel_Cell_DataValidation::STYLE_STOP:
$errorStyle = 0x00;
break;
case PHPExcel_Cell_DataValidation::STYLE_WARNING:
$errorStyle = 0x01;
break;
case PHPExcel_Cell_DataValidation::STYLE_INFORMATION:
$errorStyle = 0x02;
break;
}
$options |= $errorStyle << 4;
// explicit formula?
if ($type == 0x03 && preg_match('/^\".*\"$/', $dataValidation->getFormula1())) {
$options |= 0x01 << 7;
}
// empty cells allowed
$options |= $dataValidation->getAllowBlank() << 8;
// show drop down
$options |= (!$dataValidation->getShowDropDown()) << 9;
// show input message
$options |= $dataValidation->getShowInputMessage() << 18;
// show error message
$options |= $dataValidation->getShowErrorMessage() << 19;
// condition operator
$operator = $dataValidation->getOperator();
switch ($operator) {
case PHPExcel_Cell_DataValidation::OPERATOR_BETWEEN:
$operator = 0x00;
break;
case PHPExcel_Cell_DataValidation::OPERATOR_NOTBETWEEN:
$operator = 0x01;
break;
case PHPExcel_Cell_DataValidation::OPERATOR_EQUAL:
$operator = 0x02;
break;
case PHPExcel_Cell_DataValidation::OPERATOR_NOTEQUAL:
$operator = 0x03;
break;
case PHPExcel_Cell_DataValidation::OPERATOR_GREATERTHAN:
$operator = 0x04;
break;
case PHPExcel_Cell_DataValidation::OPERATOR_LESSTHAN:
$operator = 0x05;
break;
case PHPExcel_Cell_DataValidation::OPERATOR_GREATERTHANOREQUAL:
$operator = 0x06;
break;
case PHPExcel_Cell_DataValidation::OPERATOR_LESSTHANOREQUAL:
$operator = 0x07;
break;
}
$options |= $operator << 20;
$data = pack('V', $options);
// prompt title
$promptTitle = $dataValidation->getPromptTitle() !== '' ?
$dataValidation->getPromptTitle() : chr(0);
$data .= PHPExcel_Shared_String::UTF8toBIFF8UnicodeLong($promptTitle);
// error title
$errorTitle = $dataValidation->getErrorTitle() !== '' ?
$dataValidation->getErrorTitle() : chr(0);
$data .= PHPExcel_Shared_String::UTF8toBIFF8UnicodeLong($errorTitle);
// prompt text
$prompt = $dataValidation->getPrompt() !== '' ?
$dataValidation->getPrompt() : chr(0);
$data .= PHPExcel_Shared_String::UTF8toBIFF8UnicodeLong($prompt);
// error text
$error = $dataValidation->getError() !== '' ?
$dataValidation->getError() : chr(0);
$data .= PHPExcel_Shared_String::UTF8toBIFF8UnicodeLong($error);
// formula 1
try {
$formula1 = $dataValidation->getFormula1();
if ($type == 0x03) { // list type
$formula1 = str_replace(',', chr(0), $formula1);
}
$this->parser->parse($formula1);
$formula1 = $this->parser->toReversePolish();
$sz1 = strlen($formula1);
} catch (PHPExcel_Exception $e) {
$sz1 = 0;
$formula1 = '';
}
$data .= pack('vv', $sz1, 0x0000);
$data .= $formula1;
// formula 2
try {
$formula2 = $dataValidation->getFormula2();
if ($formula2 === '') {
throw new PHPExcel_Writer_Exception('No formula2');
}
$this->parser->parse($formula2);
$formula2 = $this->parser->toReversePolish();
$sz2 = strlen($formula2);
} catch (PHPExcel_Exception $e) {
$sz2 = 0;
$formula2 = '';
}
$data .= pack('vv', $sz2, 0x0000);
$data .= $formula2;
// cell range address list
$data .= pack('v', 0x0001);
$data .= $this->writeBIFF8CellRangeAddressFixed($cellCoordinate);
$length = strlen($data);
$header = pack("vv", $record, $length);
$this->append($header . $data);
}
}
}
/**
* Map Error code
*
* @param string $errorCode
* @return int
*/
private static function mapErrorCode($errorCode)
{
switch ($errorCode) {
case '#NULL!':
return 0x00;
case '#DIV/0!':
return 0x07;
case '#VALUE!':
return 0x0F;
case '#REF!':
return 0x17;
case '#NAME?':
return 0x1D;
case '#NUM!':
return 0x24;
case '#N/A':
return 0x2A;
}
return 0;
}
/**
* Write PLV Record
*/
private function writePageLayoutView()
{
$record = 0x088B; // Record identifier
$length = 0x0010; // Bytes to follow
$rt = 0x088B; // 2
$grbitFrt = 0x0000; // 2
$reserved = 0x0000000000000000; // 8
$wScalvePLV = $this->phpSheet->getSheetView()->getZoomScale(); // 2
// The options flags that comprise $grbit
if ($this->phpSheet->getSheetView()->getView() == PHPExcel_Worksheet_SheetView::SHEETVIEW_PAGE_LAYOUT) {
$fPageLayoutView = 1;
} else {
$fPageLayoutView = 0;
}
$fRulerVisible = 0;
$fWhitespaceHidden = 0;
$grbit = $fPageLayoutView; // 2
$grbit |= $fRulerVisible << 1;
$grbit |= $fWhitespaceHidden << 3;
$header = pack("vv", $record, $length);
$data = pack("vvVVvv", $rt, $grbitFrt, 0x00000000, 0x00000000, $wScalvePLV, $grbit);
$this->append($header . $data);
}
/**
* Write CFRule Record
* @param PHPExcel_Style_Conditional $conditional
*/
private function writeCFRule(PHPExcel_Style_Conditional $conditional)
{
$record = 0x01B1; // Record identifier
// $type : Type of the CF
// $operatorType : Comparison operator
if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_EXPRESSION) {
$type = 0x02;
$operatorType = 0x00;
} elseif ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CELLIS) {
$type = 0x01;
switch ($conditional->getOperatorType()) {
case PHPExcel_Style_Conditional::OPERATOR_NONE:
$operatorType = 0x00;
break;
case PHPExcel_Style_Conditional::OPERATOR_EQUAL:
$operatorType = 0x03;
break;
case PHPExcel_Style_Conditional::OPERATOR_GREATERTHAN:
$operatorType = 0x05;
break;
case PHPExcel_Style_Conditional::OPERATOR_GREATERTHANOREQUAL:
$operatorType = 0x07;
break;
case PHPExcel_Style_Conditional::OPERATOR_LESSTHAN:
$operatorType = 0x06;
break;
case PHPExcel_Style_Conditional::OPERATOR_LESSTHANOREQUAL:
$operatorType = 0x08;
break;
case PHPExcel_Style_Conditional::OPERATOR_NOTEQUAL:
$operatorType = 0x04;
break;
case PHPExcel_Style_Conditional::OPERATOR_BETWEEN:
$operatorType = 0x01;
break;
// not OPERATOR_NOTBETWEEN 0x02
}
}
// $szValue1 : size of the formula data for first value or formula
// $szValue2 : size of the formula data for second value or formula
$arrConditions = $conditional->getConditions();
$numConditions = sizeof($arrConditions);
if ($numConditions == 1) {
$szValue1 = ($arrConditions[0] <= 65535 ? 3 : 0x0000);
$szValue2 = 0x0000;
$operand1 = pack('Cv', 0x1E, $arrConditions[0]);
$operand2 = null;
} elseif ($numConditions == 2 && ($conditional->getOperatorType() == PHPExcel_Style_Conditional::OPERATOR_BETWEEN)) {
$szValue1 = ($arrConditions[0] <= 65535 ? 3 : 0x0000);
$szValue2 = ($arrConditions[1] <= 65535 ? 3 : 0x0000);
$operand1 = pack('Cv', 0x1E, $arrConditions[0]);
$operand2 = pack('Cv', 0x1E, $arrConditions[1]);
} else {
$szValue1 = 0x0000;
$szValue2 = 0x0000;
$operand1 = null;
$operand2 = null;
}
// $flags : Option flags
// Alignment
$bAlignHz = ($conditional->getStyle()->getAlignment()->getHorizontal() == null ? 1 : 0);
$bAlignVt = ($conditional->getStyle()->getAlignment()->getVertical() == null ? 1 : 0);
$bAlignWrapTx = ($conditional->getStyle()->getAlignment()->getWrapText() == false ? 1 : 0);
$bTxRotation = ($conditional->getStyle()->getAlignment()->getTextRotation() == null ? 1 : 0);
$bIndent = ($conditional->getStyle()->getAlignment()->getIndent() == 0 ? 1 : 0);
$bShrinkToFit = ($conditional->getStyle()->getAlignment()->getShrinkToFit() == false ? 1 : 0);
if ($bAlignHz == 0 || $bAlignVt == 0 || $bAlignWrapTx == 0 || $bTxRotation == 0 || $bIndent == 0 || $bShrinkToFit == 0) {
$bFormatAlign = 1;
} else {
$bFormatAlign = 0;
}
// Protection
$bProtLocked = ($conditional->getStyle()->getProtection()->getLocked() == null ? 1 : 0);
$bProtHidden = ($conditional->getStyle()->getProtection()->getHidden() == null ? 1 : 0);
if ($bProtLocked == 0 || $bProtHidden == 0) {
$bFormatProt = 1;
} else {
$bFormatProt = 0;
}
// Border
$bBorderLeft = ($conditional->getStyle()->getBorders()->getLeft()->getColor()->getARGB() == PHPExcel_Style_Color::COLOR_BLACK
&& $conditional->getStyle()->getBorders()->getLeft()->getBorderStyle() == PHPExcel_Style_Border::BORDER_NONE ? 1 : 0);
$bBorderRight = ($conditional->getStyle()->getBorders()->getRight()->getColor()->getARGB() == PHPExcel_Style_Color::COLOR_BLACK
&& $conditional->getStyle()->getBorders()->getRight()->getBorderStyle() == PHPExcel_Style_Border::BORDER_NONE ? 1 : 0);
$bBorderTop = ($conditional->getStyle()->getBorders()->getTop()->getColor()->getARGB() == PHPExcel_Style_Color::COLOR_BLACK
&& $conditional->getStyle()->getBorders()->getTop()->getBorderStyle() == PHPExcel_Style_Border::BORDER_NONE ? 1 : 0);
$bBorderBottom = ($conditional->getStyle()->getBorders()->getBottom()->getColor()->getARGB() == PHPExcel_Style_Color::COLOR_BLACK
&& $conditional->getStyle()->getBorders()->getBottom()->getBorderStyle() == PHPExcel_Style_Border::BORDER_NONE ? 1 : 0);
if ($bBorderLeft == 0 || $bBorderRight == 0 || $bBorderTop == 0 || $bBorderBottom == 0) {
$bFormatBorder = 1;
} else {
$bFormatBorder = 0;
}
// Pattern
$bFillStyle = ($conditional->getStyle()->getFill()->getFillType() == null ? 0 : 1);
$bFillColor = ($conditional->getStyle()->getFill()->getStartColor()->getARGB() == null ? 0 : 1);
$bFillColorBg = ($conditional->getStyle()->getFill()->getEndColor()->getARGB() == null ? 0 : 1);
if ($bFillStyle == 0 || $bFillColor == 0 || $bFillColorBg == 0) {
$bFormatFill = 1;
} else {
$bFormatFill = 0;
}
// Font
if ($conditional->getStyle()->getFont()->getName() != null
|| $conditional->getStyle()->getFont()->getSize() != null
|| $conditional->getStyle()->getFont()->getBold() != null
|| $conditional->getStyle()->getFont()->getItalic() != null
|| $conditional->getStyle()->getFont()->getSuperScript() != null
|| $conditional->getStyle()->getFont()->getSubScript() != null
|| $conditional->getStyle()->getFont()->getUnderline() != null
|| $conditional->getStyle()->getFont()->getStrikethrough() != null
|| $conditional->getStyle()->getFont()->getColor()->getARGB() != null) {
$bFormatFont = 1;
} else {
$bFormatFont = 0;
}
// Alignment
$flags = 0;
$flags |= (1 == $bAlignHz ? 0x00000001 : 0);
$flags |= (1 == $bAlignVt ? 0x00000002 : 0);
$flags |= (1 == $bAlignWrapTx ? 0x00000004 : 0);
$flags |= (1 == $bTxRotation ? 0x00000008 : 0);
// Justify last line flag
$flags |= (1 == 1 ? 0x00000010 : 0);
$flags |= (1 == $bIndent ? 0x00000020 : 0);
$flags |= (1 == $bShrinkToFit ? 0x00000040 : 0);
// Default
$flags |= (1 == 1 ? 0x00000080 : 0);
// Protection
$flags |= (1 == $bProtLocked ? 0x00000100 : 0);
$flags |= (1 == $bProtHidden ? 0x00000200 : 0);
// Border
$flags |= (1 == $bBorderLeft ? 0x00000400 : 0);
$flags |= (1 == $bBorderRight ? 0x00000800 : 0);
$flags |= (1 == $bBorderTop ? 0x00001000 : 0);
$flags |= (1 == $bBorderBottom ? 0x00002000 : 0);
$flags |= (1 == 1 ? 0x00004000 : 0); // Top left to Bottom right border
$flags |= (1 == 1 ? 0x00008000 : 0); // Bottom left to Top right border
// Pattern
$flags |= (1 == $bFillStyle ? 0x00010000 : 0);
$flags |= (1 == $bFillColor ? 0x00020000 : 0);
$flags |= (1 == $bFillColorBg ? 0x00040000 : 0);
$flags |= (1 == 1 ? 0x00380000 : 0);
// Font
$flags |= (1 == $bFormatFont ? 0x04000000 : 0);
// Alignment:
$flags |= (1 == $bFormatAlign ? 0x08000000 : 0);
// Border
$flags |= (1 == $bFormatBorder ? 0x10000000 : 0);
// Pattern
$flags |= (1 == $bFormatFill ? 0x20000000 : 0);
// Protection
$flags |= (1 == $bFormatProt ? 0x40000000 : 0);
// Text direction
$flags |= (1 == 0 ? 0x80000000 : 0);
// Data Blocks
if ($bFormatFont == 1) {
// Font Name
if ($conditional->getStyle()->getFont()->getName() == null) {
$dataBlockFont = pack('VVVVVVVV', 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
$dataBlockFont .= pack('VVVVVVVV', 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
} else {
$dataBlockFont = PHPExcel_Shared_String::UTF8toBIFF8UnicodeLong($conditional->getStyle()->getFont()->getName());
}
// Font Size
if ($conditional->getStyle()->getFont()->getSize() == null) {
$dataBlockFont .= pack('V', 20 * 11);
} else {
$dataBlockFont .= pack('V', 20 * $conditional->getStyle()->getFont()->getSize());
}
// Font Options
$dataBlockFont .= pack('V', 0);
// Font weight
if ($conditional->getStyle()->getFont()->getBold() == true) {
$dataBlockFont .= pack('v', 0x02BC);
} else {
$dataBlockFont .= pack('v', 0x0190);
}
// Escapement type
if ($conditional->getStyle()->getFont()->getSubScript() == true) {
$dataBlockFont .= pack('v', 0x02);
$fontEscapement = 0;
} elseif ($conditional->getStyle()->getFont()->getSuperScript() == true) {
$dataBlockFont .= pack('v', 0x01);
$fontEscapement = 0;
} else {
$dataBlockFont .= pack('v', 0x00);
$fontEscapement = 1;
}
// Underline type
switch ($conditional->getStyle()->getFont()->getUnderline()) {
case PHPExcel_Style_Font::UNDERLINE_NONE:
$dataBlockFont .= pack('C', 0x00);
$fontUnderline = 0;
break;
case PHPExcel_Style_Font::UNDERLINE_DOUBLE:
$dataBlockFont .= pack('C', 0x02);
$fontUnderline = 0;
break;
case PHPExcel_Style_Font::UNDERLINE_DOUBLEACCOUNTING:
$dataBlockFont .= pack('C', 0x22);
$fontUnderline = 0;
break;
case PHPExcel_Style_Font::UNDERLINE_SINGLE:
$dataBlockFont .= pack('C', 0x01);
$fontUnderline = 0;
break;
case PHPExcel_Style_Font::UNDERLINE_SINGLEACCOUNTING:
$dataBlockFont .= pack('C', 0x21);
$fontUnderline = 0;
break;
default: $dataBlockFont .= pack('C', 0x00);
$fontUnderline = 1;
break;
}
// Not used (3)
$dataBlockFont .= pack('vC', 0x0000, 0x00);
// Font color index
switch ($conditional->getStyle()->getFont()->getColor()->getRGB()) {
case '000000':
$colorIdx = 0x08;
break;
case 'FFFFFF':
$colorIdx = 0x09;
break;
case 'FF0000':
$colorIdx = 0x0A;
break;
case '00FF00':
$colorIdx = 0x0B;
break;
case '0000FF':
$colorIdx = 0x0C;
break;
case 'FFFF00':
$colorIdx = 0x0D;
break;
case 'FF00FF':
$colorIdx = 0x0E;
break;
case '00FFFF':
$colorIdx = 0x0F;
break;
case '800000':
$colorIdx = 0x10;
break;
case '008000':
$colorIdx = 0x11;
break;
case '000080':
$colorIdx = 0x12;
break;
case '808000':
$colorIdx = 0x13;
break;
case '800080':
$colorIdx = 0x14;
break;
case '008080':
$colorIdx = 0x15;
break;
case 'C0C0C0':
$colorIdx = 0x16;
break;
case '808080':
$colorIdx = 0x17;
break;
case '9999FF':
$colorIdx = 0x18;
break;
case '993366':
$colorIdx = 0x19;
break;
case 'FFFFCC':
$colorIdx = 0x1A;
break;
case 'CCFFFF':
$colorIdx = 0x1B;
break;
case '660066':
$colorIdx = 0x1C;
break;
case 'FF8080':
$colorIdx = 0x1D;
break;
case '0066CC':
$colorIdx = 0x1E;
break;
case 'CCCCFF':
$colorIdx = 0x1F;
break;
case '000080':
$colorIdx = 0x20;
break;
case 'FF00FF':
$colorIdx = 0x21;
break;
case 'FFFF00':
$colorIdx = 0x22;
break;
case '00FFFF':
$colorIdx = 0x23;
break;
case '800080':
$colorIdx = 0x24;
break;
case '800000':
$colorIdx = 0x25;
break;
case '008080':
$colorIdx = 0x26;
break;
case '0000FF':
$colorIdx = 0x27;
break;
case '00CCFF':
$colorIdx = 0x28;
break;
case 'CCFFFF':
$colorIdx = 0x29;
break;
case 'CCFFCC':
$colorIdx = 0x2A;
break;
case 'FFFF99':
$colorIdx = 0x2B;
break;
case '99CCFF':
$colorIdx = 0x2C;
break;
case 'FF99CC':
$colorIdx = 0x2D;
break;
case 'CC99FF':
$colorIdx = 0x2E;
break;
case 'FFCC99':
$colorIdx = 0x2F;
break;
case '3366FF':
$colorIdx = 0x30;
break;
case '33CCCC':
$colorIdx = 0x31;
break;
case '99CC00':
$colorIdx = 0x32;
break;
case 'FFCC00':
$colorIdx = 0x33;
break;
case 'FF9900':
$colorIdx = 0x34;
break;
case 'FF6600':
$colorIdx = 0x35;
break;
case '666699':
$colorIdx = 0x36;
break;
case '969696':
$colorIdx = 0x37;
break;
case '003366':
$colorIdx = 0x38;
break;
case '339966':
$colorIdx = 0x39;
break;
case '003300':
$colorIdx = 0x3A;
break;
case '333300':
$colorIdx = 0x3B;
break;
case '993300':
$colorIdx = 0x3C;
break;
case '993366':
$colorIdx = 0x3D;
break;
case '333399':
$colorIdx = 0x3E;
break;
case '333333':
$colorIdx = 0x3F;
break;
default:
$colorIdx = 0x00;
break;
}
$dataBlockFont .= pack('V', $colorIdx);
// Not used (4)
$dataBlockFont .= pack('V', 0x00000000);
// Options flags for modified font attributes
$optionsFlags = 0;
$optionsFlagsBold = ($conditional->getStyle()->getFont()->getBold() == null ? 1 : 0);
$optionsFlags |= (1 == $optionsFlagsBold ? 0x00000002 : 0);
$optionsFlags |= (1 == 1 ? 0x00000008 : 0);
$optionsFlags |= (1 == 1 ? 0x00000010 : 0);
$optionsFlags |= (1 == 0 ? 0x00000020 : 0);
$optionsFlags |= (1 == 1 ? 0x00000080 : 0);
$dataBlockFont .= pack('V', $optionsFlags);
// Escapement type
$dataBlockFont .= pack('V', $fontEscapement);
// Underline type
$dataBlockFont .= pack('V', $fontUnderline);
// Always
$dataBlockFont .= pack('V', 0x00000000);
// Always
$dataBlockFont .= pack('V', 0x00000000);
// Not used (8)
$dataBlockFont .= pack('VV', 0x00000000, 0x00000000);
// Always
$dataBlockFont .= pack('v', 0x0001);
}
if ($bFormatAlign == 1) {
$blockAlign = 0;
// Alignment and text break
switch ($conditional->getStyle()->getAlignment()->getHorizontal()) {
case PHPExcel_Style_Alignment::HORIZONTAL_GENERAL:
$blockAlign = 0;
break;
case PHPExcel_Style_Alignment::HORIZONTAL_LEFT:
$blockAlign = 1;
break;
case PHPExcel_Style_Alignment::HORIZONTAL_RIGHT:
$blockAlign = 3;
break;
case PHPExcel_Style_Alignment::HORIZONTAL_CENTER:
$blockAlign = 2;
break;
case PHPExcel_Style_Alignment::HORIZONTAL_CENTER_CONTINUOUS:
$blockAlign = 6;
break;
case PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY:
$blockAlign = 5;
break;
}
if ($conditional->getStyle()->getAlignment()->getWrapText() == true) {
$blockAlign |= 1 << 3;
} else {
$blockAlign |= 0 << 3;
}
switch ($conditional->getStyle()->getAlignment()->getVertical()) {
case PHPExcel_Style_Alignment::VERTICAL_BOTTOM:
$blockAlign = 2 << 4;
break;
case PHPExcel_Style_Alignment::VERTICAL_TOP:
$blockAlign = 0 << 4;
break;
case PHPExcel_Style_Alignment::VERTICAL_CENTER:
$blockAlign = 1 << 4;
break;
case PHPExcel_Style_Alignment::VERTICAL_JUSTIFY:
$blockAlign = 3 << 4;
break;
}
$blockAlign |= 0 << 7;
// Text rotation angle
$blockRotation = $conditional->getStyle()->getAlignment()->getTextRotation();
// Indentation
$blockIndent = $conditional->getStyle()->getAlignment()->getIndent();
if ($conditional->getStyle()->getAlignment()->getShrinkToFit() == true) {
$blockIndent |= 1 << 4;
} else {
$blockIndent |= 0 << 4;
}
$blockIndent |= 0 << 6;
// Relative indentation
$blockIndentRelative = 255;
$dataBlockAlign = pack('CCvvv', $blockAlign, $blockRotation, $blockIndent, $blockIndentRelative, 0x0000);
}
if ($bFormatBorder == 1) {
$blockLineStyle = 0;
switch ($conditional->getStyle()->getBorders()->getLeft()->getBorderStyle()) {
case PHPExcel_Style_Border::BORDER_NONE:
$blockLineStyle |= 0x00;
break;
case PHPExcel_Style_Border::BORDER_THIN:
$blockLineStyle |= 0x01;
break;
case PHPExcel_Style_Border::BORDER_MEDIUM:
$blockLineStyle |= 0x02;
break;
case PHPExcel_Style_Border::BORDER_DASHED:
$blockLineStyle |= 0x03;
break;
case PHPExcel_Style_Border::BORDER_DOTTED:
$blockLineStyle |= 0x04;
break;
case PHPExcel_Style_Border::BORDER_THICK:
$blockLineStyle |= 0x05;
break;
case PHPExcel_Style_Border::BORDER_DOUBLE:
$blockLineStyle |= 0x06;
break;
case PHPExcel_Style_Border::BORDER_HAIR:
$blockLineStyle |= 0x07;
break;
case PHPExcel_Style_Border::BORDER_MEDIUMDASHED:
$blockLineStyle |= 0x08;
break;
case PHPExcel_Style_Border::BORDER_DASHDOT:
$blockLineStyle |= 0x09;
break;
case PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT:
$blockLineStyle |= 0x0A;
break;
case PHPExcel_Style_Border::BORDER_DASHDOTDOT:
$blockLineStyle |= 0x0B;
break;
case PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT:
$blockLineStyle |= 0x0C;
break;
case PHPExcel_Style_Border::BORDER_SLANTDASHDOT:
$blockLineStyle |= 0x0D;
break;
}
switch ($conditional->getStyle()->getBorders()->getRight()->getBorderStyle()) {
case PHPExcel_Style_Border::BORDER_NONE:
$blockLineStyle |= 0x00 << 4;
break;
case PHPExcel_Style_Border::BORDER_THIN:
$blockLineStyle |= 0x01 << 4;
break;
case PHPExcel_Style_Border::BORDER_MEDIUM:
$blockLineStyle |= 0x02 << 4;
break;
case PHPExcel_Style_Border::BORDER_DASHED:
$blockLineStyle |= 0x03 << 4;
break;
case PHPExcel_Style_Border::BORDER_DOTTED:
$blockLineStyle |= 0x04 << 4;
break;
case PHPExcel_Style_Border::BORDER_THICK:
$blockLineStyle |= 0x05 << 4;
break;
case PHPExcel_Style_Border::BORDER_DOUBLE:
$blockLineStyle |= 0x06 << 4;
break;
case PHPExcel_Style_Border::BORDER_HAIR:
$blockLineStyle |= 0x07 << 4;
break;
case PHPExcel_Style_Border::BORDER_MEDIUMDASHED:
$blockLineStyle |= 0x08 << 4;
break;
case PHPExcel_Style_Border::BORDER_DASHDOT:
$blockLineStyle |= 0x09 << 4;
break;
case PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT:
$blockLineStyle |= 0x0A << 4;
break;
case PHPExcel_Style_Border::BORDER_DASHDOTDOT:
$blockLineStyle |= 0x0B << 4;
break;
case PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT:
$blockLineStyle |= 0x0C << 4;
break;
case PHPExcel_Style_Border::BORDER_SLANTDASHDOT:
$blockLineStyle |= 0x0D << 4;
break;
}
switch ($conditional->getStyle()->getBorders()->getTop()->getBorderStyle()) {
case PHPExcel_Style_Border::BORDER_NONE:
$blockLineStyle |= 0x00 << 8;
break;
case PHPExcel_Style_Border::BORDER_THIN:
$blockLineStyle |= 0x01 << 8;
break;
case PHPExcel_Style_Border::BORDER_MEDIUM:
$blockLineStyle |= 0x02 << 8;
break;
case PHPExcel_Style_Border::BORDER_DASHED:
$blockLineStyle |= 0x03 << 8;
break;
case PHPExcel_Style_Border::BORDER_DOTTED:
$blockLineStyle |= 0x04 << 8;
break;
case PHPExcel_Style_Border::BORDER_THICK:
$blockLineStyle |= 0x05 << 8;
break;
case PHPExcel_Style_Border::BORDER_DOUBLE:
$blockLineStyle |= 0x06 << 8;
break;
case PHPExcel_Style_Border::BORDER_HAIR:
$blockLineStyle |= 0x07 << 8;
break;
case PHPExcel_Style_Border::BORDER_MEDIUMDASHED:
$blockLineStyle |= 0x08 << 8;
break;
case PHPExcel_Style_Border::BORDER_DASHDOT:
$blockLineStyle |= 0x09 << 8;
break;
case PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT:
$blockLineStyle |= 0x0A << 8;
break;
case PHPExcel_Style_Border::BORDER_DASHDOTDOT:
$blockLineStyle |= 0x0B << 8;
break;
case PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT:
$blockLineStyle |= 0x0C << 8;
break;
case PHPExcel_Style_Border::BORDER_SLANTDASHDOT:
$blockLineStyle |= 0x0D << 8;
break;
}
switch ($conditional->getStyle()->getBorders()->getBottom()->getBorderStyle()) {
case PHPExcel_Style_Border::BORDER_NONE:
$blockLineStyle |= 0x00 << 12;
break;
case PHPExcel_Style_Border::BORDER_THIN:
$blockLineStyle |= 0x01 << 12;
break;
case PHPExcel_Style_Border::BORDER_MEDIUM:
$blockLineStyle |= 0x02 << 12;
break;
case PHPExcel_Style_Border::BORDER_DASHED:
$blockLineStyle |= 0x03 << 12;
break;
case PHPExcel_Style_Border::BORDER_DOTTED:
$blockLineStyle |= 0x04 << 12;
break;
case PHPExcel_Style_Border::BORDER_THICK:
$blockLineStyle |= 0x05 << 12;
break;
case PHPExcel_Style_Border::BORDER_DOUBLE:
$blockLineStyle |= 0x06 << 12;
break;
case PHPExcel_Style_Border::BORDER_HAIR:
$blockLineStyle |= 0x07 << 12;
break;
case PHPExcel_Style_Border::BORDER_MEDIUMDASHED:
$blockLineStyle |= 0x08 << 12;
break;
case PHPExcel_Style_Border::BORDER_DASHDOT:
$blockLineStyle |= 0x09 << 12;
break;
case PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT:
$blockLineStyle |= 0x0A << 12;
break;
case PHPExcel_Style_Border::BORDER_DASHDOTDOT:
$blockLineStyle |= 0x0B << 12;
break;
case PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT:
$blockLineStyle |= 0x0C << 12;
break;
case PHPExcel_Style_Border::BORDER_SLANTDASHDOT:
$blockLineStyle |= 0x0D << 12;
break;
}
//@todo writeCFRule() => $blockLineStyle => Index Color for left line
//@todo writeCFRule() => $blockLineStyle => Index Color for right line
//@todo writeCFRule() => $blockLineStyle => Top-left to bottom-right on/off
//@todo writeCFRule() => $blockLineStyle => Bottom-left to top-right on/off
$blockColor = 0;
//@todo writeCFRule() => $blockColor => Index Color for top line
//@todo writeCFRule() => $blockColor => Index Color for bottom line
//@todo writeCFRule() => $blockColor => Index Color for diagonal line
switch ($conditional->getStyle()->getBorders()->getDiagonal()->getBorderStyle()) {
case PHPExcel_Style_Border::BORDER_NONE:
$blockColor |= 0x00 << 21;
break;
case PHPExcel_Style_Border::BORDER_THIN:
$blockColor |= 0x01 << 21;
break;
case PHPExcel_Style_Border::BORDER_MEDIUM:
$blockColor |= 0x02 << 21;
break;
case PHPExcel_Style_Border::BORDER_DASHED:
$blockColor |= 0x03 << 21;
break;
case PHPExcel_Style_Border::BORDER_DOTTED:
$blockColor |= 0x04 << 21;
break;
case PHPExcel_Style_Border::BORDER_THICK:
$blockColor |= 0x05 << 21;
break;
case PHPExcel_Style_Border::BORDER_DOUBLE:
$blockColor |= 0x06 << 21;
break;
case PHPExcel_Style_Border::BORDER_HAIR:
$blockColor |= 0x07 << 21;
break;
case PHPExcel_Style_Border::BORDER_MEDIUMDASHED:
$blockColor |= 0x08 << 21;
break;
case PHPExcel_Style_Border::BORDER_DASHDOT:
$blockColor |= 0x09 << 21;
break;
case PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT:
$blockColor |= 0x0A << 21;
break;
case PHPExcel_Style_Border::BORDER_DASHDOTDOT:
$blockColor |= 0x0B << 21;
break;
case PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT:
$blockColor |= 0x0C << 21;
break;
case PHPExcel_Style_Border::BORDER_SLANTDASHDOT:
$blockColor |= 0x0D << 21;
break;
}
$dataBlockBorder = pack('vv', $blockLineStyle, $blockColor);
}
if ($bFormatFill == 1) {
// Fill Patern Style
$blockFillPatternStyle = 0;
switch ($conditional->getStyle()->getFill()->getFillType()) {
case PHPExcel_Style_Fill::FILL_NONE:
$blockFillPatternStyle = 0x00;
break;
case PHPExcel_Style_Fill::FILL_SOLID:
$blockFillPatternStyle = 0x01;
break;
case PHPExcel_Style_Fill::FILL_PATTERN_MEDIUMGRAY:
$blockFillPatternStyle = 0x02;
break;
case PHPExcel_Style_Fill::FILL_PATTERN_DARKGRAY:
$blockFillPatternStyle = 0x03;
break;
case PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRAY:
$blockFillPatternStyle = 0x04;
break;
case PHPExcel_Style_Fill::FILL_PATTERN_DARKHORIZONTAL:
$blockFillPatternStyle = 0x05;
break;
case PHPExcel_Style_Fill::FILL_PATTERN_DARKVERTICAL:
$blockFillPatternStyle = 0x06;
break;
case PHPExcel_Style_Fill::FILL_PATTERN_DARKDOWN:
$blockFillPatternStyle = 0x07;
break;
case PHPExcel_Style_Fill::FILL_PATTERN_DARKUP:
$blockFillPatternStyle = 0x08;
break;
case PHPExcel_Style_Fill::FILL_PATTERN_DARKGRID:
$blockFillPatternStyle = 0x09;
break;
case PHPExcel_Style_Fill::FILL_PATTERN_DARKTRELLIS:
$blockFillPatternStyle = 0x0A;
break;
case PHPExcel_Style_Fill::FILL_PATTERN_LIGHTHORIZONTAL:
$blockFillPatternStyle = 0x0B;
break;
case PHPExcel_Style_Fill::FILL_PATTERN_LIGHTVERTICAL:
$blockFillPatternStyle = 0x0C;
break;
case PHPExcel_Style_Fill::FILL_PATTERN_LIGHTDOWN:
$blockFillPatternStyle = 0x0D;
break;
case PHPExcel_Style_Fill::FILL_PATTERN_LIGHTUP:
$blockFillPatternStyle = 0x0E;
break;
case PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRID:
$blockFillPatternStyle = 0x0F;
break;
case PHPExcel_Style_Fill::FILL_PATTERN_LIGHTTRELLIS:
$blockFillPatternStyle = 0x10;
break;
case PHPExcel_Style_Fill::FILL_PATTERN_GRAY125:
$blockFillPatternStyle = 0x11;
break;
case PHPExcel_Style_Fill::FILL_PATTERN_GRAY0625:
$blockFillPatternStyle = 0x12;
break;
case PHPExcel_Style_Fill::FILL_GRADIENT_LINEAR:
$blockFillPatternStyle = 0x00;
break; // does not exist in BIFF8
case PHPExcel_Style_Fill::FILL_GRADIENT_PATH:
$blockFillPatternStyle = 0x00;
break; // does not exist in BIFF8
default:
$blockFillPatternStyle = 0x00;
break;
}
// Color
switch ($conditional->getStyle()->getFill()->getStartColor()->getRGB()) {
case '000000':
$colorIdxBg = 0x08;
break;
case 'FFFFFF':
$colorIdxBg = 0x09;
break;
case 'FF0000':
$colorIdxBg = 0x0A;
break;
case '00FF00':
$colorIdxBg = 0x0B;
break;
case '0000FF':
$colorIdxBg = 0x0C;
break;
case 'FFFF00':
$colorIdxBg = 0x0D;
break;
case 'FF00FF':
$colorIdxBg = 0x0E;
break;
case '00FFFF':
$colorIdxBg = 0x0F;
break;
case '800000':
$colorIdxBg = 0x10;
break;
case '008000':
$colorIdxBg = 0x11;
break;
case '000080':
$colorIdxBg = 0x12;
break;
case '808000':
$colorIdxBg = 0x13;
break;
case '800080':
$colorIdxBg = 0x14;
break;
case '008080':
$colorIdxBg = 0x15;
break;
case 'C0C0C0':
$colorIdxBg = 0x16;
break;
case '808080':
$colorIdxBg = 0x17;
break;
case '9999FF':
$colorIdxBg = 0x18;
break;
case '993366':
$colorIdxBg = 0x19;
break;
case 'FFFFCC':
$colorIdxBg = 0x1A;
break;
case 'CCFFFF':
$colorIdxBg = 0x1B;
break;
case '660066':
$colorIdxBg = 0x1C;
break;
case 'FF8080':
$colorIdxBg = 0x1D;
break;
case '0066CC':
$colorIdxBg = 0x1E;
break;
case 'CCCCFF':
$colorIdxBg = 0x1F;
break;
case '000080':
$colorIdxBg = 0x20;
break;
case 'FF00FF':
$colorIdxBg = 0x21;
break;
case 'FFFF00':
$colorIdxBg = 0x22;
break;
case '00FFFF':
$colorIdxBg = 0x23;
break;
case '800080':
$colorIdxBg = 0x24;
break;
case '800000':
$colorIdxBg = 0x25;
break;
case '008080':
$colorIdxBg = 0x26;
break;
case '0000FF':
$colorIdxBg = 0x27;
break;
case '00CCFF':
$colorIdxBg = 0x28;
break;
case 'CCFFFF':
$colorIdxBg = 0x29;
break;
case 'CCFFCC':
$colorIdxBg = 0x2A;
break;
case 'FFFF99':
$colorIdxBg = 0x2B;
break;
case '99CCFF':
$colorIdxBg = 0x2C;
break;
case 'FF99CC':
$colorIdxBg = 0x2D;
break;
case 'CC99FF':
$colorIdxBg = 0x2E;
break;
case 'FFCC99':
$colorIdxBg = 0x2F;
break;
case '3366FF':
$colorIdxBg = 0x30;
break;
case '33CCCC':
$colorIdxBg = 0x31;
break;
case '99CC00':
$colorIdxBg = 0x32;
break;
case 'FFCC00':
$colorIdxBg = 0x33;
break;
case 'FF9900':
$colorIdxBg = 0x34;
break;
case 'FF6600':
$colorIdxBg = 0x35;
break;
case '666699':
$colorIdxBg = 0x36;
break;
case '969696':
$colorIdxBg = 0x37;
break;
case '003366':
$colorIdxBg = 0x38;
break;
case '339966':
$colorIdxBg = 0x39;
break;
case '003300':
$colorIdxBg = 0x3A;
break;
case '333300':
$colorIdxBg = 0x3B;
break;
case '993300':
$colorIdxBg = 0x3C;
break;
case '993366':
$colorIdxBg = 0x3D;
break;
case '333399':
$colorIdxBg = 0x3E;
break;
case '333333':
$colorIdxBg = 0x3F;
break;
default:
$colorIdxBg = 0x41;
break;
}
// Fg Color
switch ($conditional->getStyle()->getFill()->getEndColor()->getRGB()) {
case '000000':
$colorIdxFg = 0x08;
break;
case 'FFFFFF':
$colorIdxFg = 0x09;
break;
case 'FF0000':
$colorIdxFg = 0x0A;
break;
case '00FF00':
$colorIdxFg = 0x0B;
break;
case '0000FF':
$colorIdxFg = 0x0C;
break;
case 'FFFF00':
$colorIdxFg = 0x0D;
break;
case 'FF00FF':
$colorIdxFg = 0x0E;
break;
case '00FFFF':
$colorIdxFg = 0x0F;
break;
case '800000':
$colorIdxFg = 0x10;
break;
case '008000':
$colorIdxFg = 0x11;
break;
case '000080':
$colorIdxFg = 0x12;
break;
case '808000':
$colorIdxFg = 0x13;
break;
case '800080':
$colorIdxFg = 0x14;
break;
case '008080':
$colorIdxFg = 0x15;
break;
case 'C0C0C0':
$colorIdxFg = 0x16;
break;
case '808080':
$colorIdxFg = 0x17;
break;
case '9999FF':
$colorIdxFg = 0x18;
break;
case '993366':
$colorIdxFg = 0x19;
break;
case 'FFFFCC':
$colorIdxFg = 0x1A;
break;
case 'CCFFFF':
$colorIdxFg = 0x1B;
break;
case '660066':
$colorIdxFg = 0x1C;
break;
case 'FF8080':
$colorIdxFg = 0x1D;
break;
case '0066CC':
$colorIdxFg = 0x1E;
break;
case 'CCCCFF':
$colorIdxFg = 0x1F;
break;
case '000080':
$colorIdxFg = 0x20;
break;
case 'FF00FF':
$colorIdxFg = 0x21;
break;
case 'FFFF00':
$colorIdxFg = 0x22;
break;
case '00FFFF':
$colorIdxFg = 0x23;
break;
case '800080':
$colorIdxFg = 0x24;
break;
case '800000':
$colorIdxFg = 0x25;
break;
case '008080':
$colorIdxFg = 0x26;
break;
case '0000FF':
$colorIdxFg = 0x27;
break;
case '00CCFF':
$colorIdxFg = 0x28;
break;
case 'CCFFFF':
$colorIdxFg = 0x29;
break;
case 'CCFFCC':
$colorIdxFg = 0x2A;
break;
case 'FFFF99':
$colorIdxFg = 0x2B;
break;
case '99CCFF':
$colorIdxFg = 0x2C;
break;
case 'FF99CC':
$colorIdxFg = 0x2D;
break;
case 'CC99FF':
$colorIdxFg = 0x2E;
break;
case 'FFCC99':
$colorIdxFg = 0x2F;
break;
case '3366FF':
$colorIdxFg = 0x30;
break;
case '33CCCC':
$colorIdxFg = 0x31;
break;
case '99CC00':
$colorIdxFg = 0x32;
break;
case 'FFCC00':
$colorIdxFg = 0x33;
break;
case 'FF9900':
$colorIdxFg = 0x34;
break;
case 'FF6600':
$colorIdxFg = 0x35;
break;
case '666699':
$colorIdxFg = 0x36;
break;
case '969696':
$colorIdxFg = 0x37;
break;
case '003366':
$colorIdxFg = 0x38;
break;
case '339966':
$colorIdxFg = 0x39;
break;
case '003300':
$colorIdxFg = 0x3A;
break;
case '333300':
$colorIdxFg = 0x3B;
break;
case '993300':
$colorIdxFg = 0x3C;
break;
case '993366':
$colorIdxFg = 0x3D;
break;
case '333399':
$colorIdxFg = 0x3E;
break;
case '333333':
$colorIdxFg = 0x3F;
break;
default:
$colorIdxFg = 0x40;
break;
}
$dataBlockFill = pack('v', $blockFillPatternStyle);
$dataBlockFill .= pack('v', $colorIdxFg | ($colorIdxBg << 7));
}
if ($bFormatProt == 1) {
$dataBlockProtection = 0;
if ($conditional->getStyle()->getProtection()->getLocked() == PHPExcel_Style_Protection::PROTECTION_PROTECTED) {
$dataBlockProtection = 1;
}
if ($conditional->getStyle()->getProtection()->getHidden() == PHPExcel_Style_Protection::PROTECTION_PROTECTED) {
$dataBlockProtection = 1 << 1;
}
}
$data = pack('CCvvVv', $type, $operatorType, $szValue1, $szValue2, $flags, 0x0000);
if ($bFormatFont == 1) { // Block Formatting : OK
$data .= $dataBlockFont;
}
if ($bFormatAlign == 1) {
$data .= $dataBlockAlign;
}
if ($bFormatBorder == 1) {
$data .= $dataBlockBorder;
}
if ($bFormatFill == 1) { // Block Formatting : OK
$data .= $dataBlockFill;
}
if ($bFormatProt == 1) {
$data .= $dataBlockProtection;
}
if (!is_null($operand1)) {
$data .= $operand1;
}
if (!is_null($operand2)) {
$data .= $operand2;
}
$header = pack('vv', $record, strlen($data));
$this->append($header . $data);
}
/**
* Write CFHeader record
*/
private function writeCFHeader()
{
$record = 0x01B0; // Record identifier
$length = 0x0016; // Bytes to follow
$numColumnMin = null;
$numColumnMax = null;
$numRowMin = null;
$numRowMax = null;
$arrConditional = array();
foreach ($this->phpSheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) {
foreach ($conditionalStyles as $conditional) {
if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_EXPRESSION
|| $conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CELLIS) {
if (!in_array($conditional->getHashCode(), $arrConditional)) {
$arrConditional[] = $conditional->getHashCode();
}
// Cells
$arrCoord = PHPExcel_Cell::coordinateFromString($cellCoordinate);
if (!is_numeric($arrCoord[0])) {
$arrCoord[0] = PHPExcel_Cell::columnIndexFromString($arrCoord[0]);
}
if (is_null($numColumnMin) || ($numColumnMin > $arrCoord[0])) {
$numColumnMin = $arrCoord[0];
}
if (is_null($numColumnMax) || ($numColumnMax < $arrCoord[0])) {
$numColumnMax = $arrCoord[0];
}
if (is_null($numRowMin) || ($numRowMin > $arrCoord[1])) {
$numRowMin = $arrCoord[1];
}
if (is_null($numRowMax) || ($numRowMax < $arrCoord[1])) {
$numRowMax = $arrCoord[1];
}
}
}
}
$needRedraw = 1;
$cellRange = pack('vvvv', $numRowMin-1, $numRowMax-1, $numColumnMin-1, $numColumnMax-1);
$header = pack('vv', $record, $length);
$data = pack('vv', count($arrConditional), $needRedraw);
$data .= $cellRange;
$data .= pack('v', 0x0001);
$data .= $cellRange;
$this->append($header . $data);
}
}