/include/PHPExcel/PHPExcel/Reader/Excel5.php
PHP | 6890 lines | 3868 code | 1142 blank | 1880 comment | 497 complexity | 12f267ece14204d8d3d5a593f133790b MD5 | raw file
Possible License(s): Apache-2.0, LGPL-3.0, LGPL-2.1, GPL-2.0, GPL-3.0
Large files files are truncated, but you can click here to view the full file
- <?php
- /**
- * PHPExcel
- *
- * Copyright (c) 2006 - 2012 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_Reader_Excel5
- * @copyright Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
- * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
- * @version 1.7.7, 2012-05-19
- */
- // Original file header of ParseXL (used as the base for this class):
- // --------------------------------------------------------------------------------
- // Adapted from Excel_Spreadsheet_Reader developed by users bizon153,
- // trex005, and mmp11 (SourceForge.net)
- // http://sourceforge.net/projects/phpexcelreader/
- // Primary changes made by canyoncasa (dvc) for ParseXL 1.00 ...
- // Modelled moreso after Perl Excel Parse/Write modules
- // Added Parse_Excel_Spreadsheet object
- // Reads a whole worksheet or tab as row,column array or as
- // associated hash of indexed rows and named column fields
- // Added variables for worksheet (tab) indexes and names
- // Added an object call for loading individual woorksheets
- // Changed default indexing defaults to 0 based arrays
- // Fixed date/time and percent formats
- // Includes patches found at SourceForge...
- // unicode patch by nobody
- // unpack("d") machine depedency patch by matchy
- // boundsheet utf16 patch by bjaenichen
- // Renamed functions for shorter names
- // General code cleanup and rigor, including <80 column width
- // Included a testcase Excel file and PHP example calls
- // Code works for PHP 5.x
- // Primary changes made by canyoncasa (dvc) for ParseXL 1.10 ...
- // http://sourceforge.net/tracker/index.php?func=detail&aid=1466964&group_id=99160&atid=623334
- // Decoding of formula conditions, results, and tokens.
- // Support for user-defined named cells added as an array "namedcells"
- // Patch code for user-defined named cells supports single cells only.
- // NOTE: this patch only works for BIFF8 as BIFF5-7 use a different
- // external sheet reference structure
- /** PHPExcel root directory */
- if (!defined('PHPEXCEL_ROOT')) {
- /**
- * @ignore
- */
- define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
- require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
- }
- /**
- * PHPExcel_Reader_Excel5
- *
- * This class uses {@link http://sourceforge.net/projects/phpexcelreader/parseXL}
- *
- * @category PHPExcel
- * @package PHPExcel_Reader_Excel5
- * @copyright Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
- */
- class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader
- {
- // ParseXL definitions
- const XLS_BIFF8 = 0x0600;
- const XLS_BIFF7 = 0x0500;
- const XLS_WorkbookGlobals = 0x0005;
- const XLS_Worksheet = 0x0010;
- // record identifiers
- const XLS_Type_FORMULA = 0x0006;
- const XLS_Type_EOF = 0x000a;
- const XLS_Type_PROTECT = 0x0012;
- const XLS_Type_OBJECTPROTECT = 0x0063;
- const XLS_Type_SCENPROTECT = 0x00dd;
- const XLS_Type_PASSWORD = 0x0013;
- const XLS_Type_HEADER = 0x0014;
- const XLS_Type_FOOTER = 0x0015;
- const XLS_Type_EXTERNSHEET = 0x0017;
- const XLS_Type_DEFINEDNAME = 0x0018;
- const XLS_Type_VERTICALPAGEBREAKS = 0x001a;
- const XLS_Type_HORIZONTALPAGEBREAKS = 0x001b;
- const XLS_Type_NOTE = 0x001c;
- const XLS_Type_SELECTION = 0x001d;
- const XLS_Type_DATEMODE = 0x0022;
- const XLS_Type_EXTERNNAME = 0x0023;
- const XLS_Type_LEFTMARGIN = 0x0026;
- const XLS_Type_RIGHTMARGIN = 0x0027;
- const XLS_Type_TOPMARGIN = 0x0028;
- const XLS_Type_BOTTOMMARGIN = 0x0029;
- const XLS_Type_PRINTGRIDLINES = 0x002b;
- const XLS_Type_FILEPASS = 0x002f;
- const XLS_Type_FONT = 0x0031;
- const XLS_Type_CONTINUE = 0x003c;
- const XLS_Type_PANE = 0x0041;
- const XLS_Type_CODEPAGE = 0x0042;
- const XLS_Type_DEFCOLWIDTH = 0x0055;
- const XLS_Type_OBJ = 0x005d;
- const XLS_Type_COLINFO = 0x007d;
- const XLS_Type_IMDATA = 0x007f;
- const XLS_Type_SHEETPR = 0x0081;
- const XLS_Type_HCENTER = 0x0083;
- const XLS_Type_VCENTER = 0x0084;
- const XLS_Type_SHEET = 0x0085;
- const XLS_Type_PALETTE = 0x0092;
- const XLS_Type_SCL = 0x00a0;
- const XLS_Type_PAGESETUP = 0x00a1;
- const XLS_Type_MULRK = 0x00bd;
- const XLS_Type_MULBLANK = 0x00be;
- const XLS_Type_DBCELL = 0x00d7;
- const XLS_Type_XF = 0x00e0;
- const XLS_Type_MERGEDCELLS = 0x00e5;
- const XLS_Type_MSODRAWINGGROUP = 0x00eb;
- const XLS_Type_MSODRAWING = 0x00ec;
- const XLS_Type_SST = 0x00fc;
- const XLS_Type_LABELSST = 0x00fd;
- const XLS_Type_EXTSST = 0x00ff;
- const XLS_Type_EXTERNALBOOK = 0x01ae;
- const XLS_Type_DATAVALIDATIONS = 0x01b2;
- const XLS_Type_TXO = 0x01b6;
- const XLS_Type_HYPERLINK = 0x01b8;
- const XLS_Type_DATAVALIDATION = 0x01be;
- const XLS_Type_DIMENSION = 0x0200;
- const XLS_Type_BLANK = 0x0201;
- const XLS_Type_NUMBER = 0x0203;
- const XLS_Type_LABEL = 0x0204;
- const XLS_Type_BOOLERR = 0x0205;
- const XLS_Type_STRING = 0x0207;
- const XLS_Type_ROW = 0x0208;
- const XLS_Type_INDEX = 0x020b;
- const XLS_Type_ARRAY = 0x0221;
- const XLS_Type_DEFAULTROWHEIGHT = 0x0225;
- const XLS_Type_WINDOW2 = 0x023e;
- const XLS_Type_RK = 0x027e;
- const XLS_Type_STYLE = 0x0293;
- const XLS_Type_FORMAT = 0x041e;
- const XLS_Type_SHAREDFMLA = 0x04bc;
- const XLS_Type_BOF = 0x0809;
- const XLS_Type_SHEETPROTECTION = 0x0867;
- const XLS_Type_RANGEPROTECTION = 0x0868;
- const XLS_Type_SHEETLAYOUT = 0x0862;
- const XLS_Type_XFEXT = 0x087d;
- const XLS_Type_UNKNOWN = 0xffff;
- /**
- * Read data only?
- * Identifies whether the Reader should only read data values for cells, and ignore any formatting information;
- * or whether it should read both data and formatting
- *
- * @var boolean
- */
- private $_readDataOnly = false;
- /**
- * Restrict which sheets should be loaded?
- * This property holds an array of worksheet names to be loaded. If null, then all worksheets will be loaded.
- *
- * @var array of string
- */
- private $_loadSheetsOnly = null;
- /**
- * PHPExcel_Reader_IReadFilter instance
- *
- * @var PHPExcel_Reader_IReadFilter
- */
- private $_readFilter = null;
- /**
- * Summary Information stream data.
- *
- * @var string
- */
- private $_summaryInformation;
- /**
- * Extended Summary Information stream data.
- *
- * @var string
- */
- private $_documentSummaryInformation;
- /**
- * User-Defined Properties stream data.
- *
- * @var string
- */
- private $_userDefinedProperties;
- /**
- * Workbook stream data. (Includes workbook globals substream as well as sheet substreams)
- *
- * @var string
- */
- private $_data;
- /**
- * Size in bytes of $this->_data
- *
- * @var int
- */
- private $_dataSize;
- /**
- * Current position in stream
- *
- * @var integer
- */
- private $_pos;
- /**
- * Workbook to be returned by the reader.
- *
- * @var PHPExcel
- */
- private $_phpExcel;
- /**
- * Worksheet that is currently being built by the reader.
- *
- * @var PHPExcel_Worksheet
- */
- private $_phpSheet;
- /**
- * BIFF version
- *
- * @var int
- */
- private $_version;
- /**
- * Codepage set in the Excel file being read. Only important for BIFF5 (Excel 5.0 - Excel 95)
- * For BIFF8 (Excel 97 - Excel 2003) this will always have the value 'UTF-16LE'
- *
- * @var string
- */
- private $_codepage;
- /**
- * Shared formats
- *
- * @var array
- */
- private $_formats;
- /**
- * Shared fonts
- *
- * @var array
- */
- private $_objFonts;
- /**
- * Color palette
- *
- * @var array
- */
- private $_palette;
- /**
- * Worksheets
- *
- * @var array
- */
- private $_sheets;
- /**
- * External books
- *
- * @var array
- */
- private $_externalBooks;
- /**
- * REF structures. Only applies to BIFF8.
- *
- * @var array
- */
- private $_ref;
- /**
- * External names
- *
- * @var array
- */
- private $_externalNames;
- /**
- * Defined names
- *
- * @var array
- */
- private $_definedname;
- /**
- * Shared strings. Only applies to BIFF8.
- *
- * @var array
- */
- private $_sst;
- /**
- * Panes are frozen? (in sheet currently being read). See WINDOW2 record.
- *
- * @var boolean
- */
- private $_frozen;
- /**
- * Fit printout to number of pages? (in sheet currently being read). See SHEETPR record.
- *
- * @var boolean
- */
- private $_isFitToPages;
- /**
- * Objects. One OBJ record contributes with one entry.
- *
- * @var array
- */
- private $_objs;
- /**
- * Text Objects. One TXO record corresponds with one entry.
- *
- * @var array
- */
- private $_textObjects;
- /**
- * Cell Annotations (BIFF8)
- *
- * @var array
- */
- private $_cellNotes;
- /**
- * The combined MSODRAWINGGROUP data
- *
- * @var string
- */
- private $_drawingGroupData;
- /**
- * The combined MSODRAWING data (per sheet)
- *
- * @var string
- */
- private $_drawingData;
- /**
- * Keep track of XF index
- *
- * @var int
- */
- private $_xfIndex;
- /**
- * Mapping of XF index (that is a cell XF) to final index in cellXf collection
- *
- * @var array
- */
- private $_mapCellXfIndex;
- /**
- * Mapping of XF index (that is a style XF) to final index in cellStyleXf collection
- *
- * @var array
- */
- private $_mapCellStyleXfIndex;
- /**
- * The shared formulas in a sheet. One SHAREDFMLA record contributes with one value.
- *
- * @var array
- */
- private $_sharedFormulas;
- /**
- * The shared formula parts in a sheet. One FORMULA record contributes with one value if it
- * refers to a shared formula.
- *
- * @var array
- */
- private $_sharedFormulaParts;
- /**
- * Create a new PHPExcel_Reader_Excel5 instance
- */
- public function __construct() {
- $this->_readFilter = new PHPExcel_Reader_DefaultReadFilter();
- }
- /**
- * Read data only?
- * If this is true, then the Reader will only read data values for cells, it will not read any formatting information.
- * If false (the default) it will read data and formatting.
- *
- * @return boolean
- */
- public function getReadDataOnly()
- {
- return $this->_readDataOnly;
- }
- /**
- * Set read data only
- * Set to true, to advise the Reader only to read data values for cells, and to ignore any formatting information.
- * Set to false (the default) to advise the Reader to read both data and formatting for cells.
- *
- * @param boolean $pValue
- *
- * @return PHPExcel_Reader_Excel5
- */
- public function setReadDataOnly($pValue = false)
- {
- $this->_readDataOnly = $pValue;
- return $this;
- }
- /**
- * Get which sheets to load
- * Returns either an array of worksheet names (the list of worksheets that should be loaded), or a null
- * indicating that all worksheets in the workbook should be loaded.
- *
- * @return mixed
- */
- public function getLoadSheetsOnly()
- {
- return $this->_loadSheetsOnly;
- }
- /**
- * Set which sheets to load
- *
- * @param mixed $value
- * This should be either an array of worksheet names to be loaded, or a string containing a single worksheet name.
- * If NULL, then it tells the Reader to read all worksheets in the workbook
- *
- * @return PHPExcel_Reader_Excel5
- */
- public function setLoadSheetsOnly($value = null)
- {
- $this->_loadSheetsOnly = is_array($value) ?
- $value : array($value);
- return $this;
- }
- /**
- * Set all sheets to load
- * Tells the Reader to load all worksheets from the workbook.
- *
- * @return PHPExcel_Reader_Excel5
- */
- public function setLoadAllSheets()
- {
- $this->_loadSheetsOnly = null;
- return $this;
- }
- /**
- * Read filter
- *
- * @return PHPExcel_Reader_IReadFilter
- */
- public function getReadFilter() {
- return $this->_readFilter;
- }
- /**
- * Set read filter
- *
- * @param PHPExcel_Reader_IReadFilter $pValue
- * @return PHPExcel_Reader_Excel5
- */
- public function setReadFilter(PHPExcel_Reader_IReadFilter $pValue) {
- $this->_readFilter = $pValue;
- return $this;
- }
- /**
- * Can the current PHPExcel_Reader_IReader read the file?
- *
- * @param string $pFileName
- * @return boolean
- * @throws Exception
- */
- public function canRead($pFilename)
- {
- // Check if file exists
- if (!file_exists($pFilename)) {
- throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
- }
- try {
- // Use ParseXL for the hard work.
- $ole = new PHPExcel_Shared_OLERead();
- // get excel data
- $res = $ole->read($pFilename);
- return true;
- } catch (Exception $e) {
- return false;
- }
- }
- /**
- * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
- *
- * @param string $pFilename
- * @throws Exception
- */
- public function listWorksheetNames($pFilename)
- {
- // Check if file exists
- if (!file_exists($pFilename)) {
- throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
- }
- $worksheetNames = array();
- // Read the OLE file
- $this->_loadOLE($pFilename);
- // total byte size of Excel data (workbook global substream + sheet substreams)
- $this->_dataSize = strlen($this->_data);
- $this->_pos = 0;
- $this->_sheets = array();
- // Parse Workbook Global Substream
- while ($this->_pos < $this->_dataSize) {
- $code = self::_GetInt2d($this->_data, $this->_pos);
- switch ($code) {
- case self::XLS_Type_BOF: $this->_readBof(); break;
- case self::XLS_Type_SHEET: $this->_readSheet(); break;
- case self::XLS_Type_EOF: $this->_readDefault(); break 2;
- default: $this->_readDefault(); break;
- }
- }
- foreach ($this->_sheets as $sheet) {
- if ($sheet['sheetType'] != 0x00) {
- // 0x00: Worksheet, 0x02: Chart, 0x06: Visual Basic module
- continue;
- }
- $worksheetNames[] = $sheet['name'];
- }
- return $worksheetNames;
- }
- /**
- * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
- *
- * @param string $pFilename
- * @throws Exception
- */
- public function listWorksheetInfo($pFilename)
- {
- // Check if file exists
- if (!file_exists($pFilename)) {
- throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
- }
- $worksheetInfo = array();
- // Read the OLE file
- $this->_loadOLE($pFilename);
- // total byte size of Excel data (workbook global substream + sheet substreams)
- $this->_dataSize = strlen($this->_data);
- // initialize
- $this->_pos = 0;
- $this->_sheets = array();
- // Parse Workbook Global Substream
- while ($this->_pos < $this->_dataSize) {
- $code = self::_GetInt2d($this->_data, $this->_pos);
- switch ($code) {
- case self::XLS_Type_BOF: $this->_readBof(); break;
- case self::XLS_Type_SHEET: $this->_readSheet(); break;
- case self::XLS_Type_EOF: $this->_readDefault(); break 2;
- default: $this->_readDefault(); break;
- }
- }
- // Parse the individual sheets
- foreach ($this->_sheets as $sheet) {
- if ($sheet['sheetType'] != 0x00) {
- // 0x00: Worksheet
- // 0x02: Chart
- // 0x06: Visual Basic module
- continue;
- }
- $tmpInfo = array();
- $tmpInfo['worksheetName'] = $sheet['name'];
- $tmpInfo['lastColumnLetter'] = 'A';
- $tmpInfo['lastColumnIndex'] = 0;
- $tmpInfo['totalRows'] = 0;
- $tmpInfo['totalColumns'] = 0;
- $this->_pos = $sheet['offset'];
- while ($this->_pos <= $this->_dataSize - 4) {
- $code = self::_GetInt2d($this->_data, $this->_pos);
- switch ($code) {
- case self::XLS_Type_RK:
- case self::XLS_Type_LABELSST:
- case self::XLS_Type_NUMBER:
- case self::XLS_Type_FORMULA:
- case self::XLS_Type_BOOLERR:
- case self::XLS_Type_LABEL:
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
- $recordData = substr($this->_data, $this->_pos + 4, $length);
- // move stream pointer to next record
- $this->_pos += 4 + $length;
- $rowIndex = self::_GetInt2d($recordData, 0) + 1;
- $columnIndex = self::_GetInt2d($recordData, 2);
- $tmpInfo['totalRows'] = max($tmpInfo['totalRows'], $rowIndex);
- $tmpInfo['lastColumnIndex'] = max($tmpInfo['lastColumnIndex'], $columnIndex);
- break;
- case self::XLS_Type_BOF: $this->_readBof(); break;
- case self::XLS_Type_EOF: $this->_readDefault(); break 2;
- default: $this->_readDefault(); break;
- }
- }
- $tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
- $tmpInfo['totalColumns'] = $tmpInfo['lastColumnIndex'] + 1;
- $worksheetInfo[] = $tmpInfo;
- }
- return $worksheetInfo;
- }
- /**
- * Loads PHPExcel from file
- *
- * @param string $pFilename
- * @return PHPExcel
- * @throws Exception
- */
- public function load($pFilename)
- {
- // Read the OLE file
- $this->_loadOLE($pFilename);
- // Initialisations
- $this->_phpExcel = new PHPExcel;
- $this->_phpExcel->removeSheetByIndex(0); // remove 1st sheet
- if (!$this->_readDataOnly) {
- $this->_phpExcel->removeCellStyleXfByIndex(0); // remove the default style
- $this->_phpExcel->removeCellXfByIndex(0); // remove the default style
- }
- // Read the summary information stream (containing meta data)
- $this->_readSummaryInformation();
- // Read the Additional document summary information stream (containing application-specific meta data)
- $this->_readDocumentSummaryInformation();
- // total byte size of Excel data (workbook global substream + sheet substreams)
- $this->_dataSize = strlen($this->_data);
- // initialize
- $this->_pos = 0;
- $this->_codepage = 'CP1252';
- $this->_formats = array();
- $this->_objFonts = array();
- $this->_palette = array();
- $this->_sheets = array();
- $this->_externalBooks = array();
- $this->_ref = array();
- $this->_definedname = array();
- $this->_sst = array();
- $this->_drawingGroupData = '';
- $this->_xfIndex = '';
- $this->_mapCellXfIndex = array();
- $this->_mapCellStyleXfIndex = array();
- // Parse Workbook Global Substream
- while ($this->_pos < $this->_dataSize) {
- $code = self::_GetInt2d($this->_data, $this->_pos);
- switch ($code) {
- case self::XLS_Type_BOF: $this->_readBof(); break;
- case self::XLS_Type_FILEPASS: $this->_readFilepass(); break;
- case self::XLS_Type_CODEPAGE: $this->_readCodepage(); break;
- case self::XLS_Type_DATEMODE: $this->_readDateMode(); break;
- case self::XLS_Type_FONT: $this->_readFont(); break;
- case self::XLS_Type_FORMAT: $this->_readFormat(); break;
- case self::XLS_Type_XF: $this->_readXf(); break;
- case self::XLS_Type_XFEXT: $this->_readXfExt(); break;
- case self::XLS_Type_STYLE: $this->_readStyle(); break;
- case self::XLS_Type_PALETTE: $this->_readPalette(); break;
- case self::XLS_Type_SHEET: $this->_readSheet(); break;
- case self::XLS_Type_EXTERNALBOOK: $this->_readExternalBook(); break;
- case self::XLS_Type_EXTERNNAME: $this->_readExternName(); break;
- case self::XLS_Type_EXTERNSHEET: $this->_readExternSheet(); break;
- case self::XLS_Type_DEFINEDNAME: $this->_readDefinedName(); break;
- case self::XLS_Type_MSODRAWINGGROUP: $this->_readMsoDrawingGroup(); break;
- case self::XLS_Type_SST: $this->_readSst(); break;
- case self::XLS_Type_EOF: $this->_readDefault(); break 2;
- default: $this->_readDefault(); break;
- }
- }
- // Resolve indexed colors for font, fill, and border colors
- // Cannot be resolved already in XF record, because PALETTE record comes afterwards
- if (!$this->_readDataOnly) {
- foreach ($this->_objFonts as $objFont) {
- if (isset($objFont->colorIndex)) {
- $color = self::_readColor($objFont->colorIndex,$this->_palette,$this->_version);
- $objFont->getColor()->setRGB($color['rgb']);
- }
- }
- foreach ($this->_phpExcel->getCellXfCollection() as $objStyle) {
- // fill start and end color
- $fill = $objStyle->getFill();
- if (isset($fill->startcolorIndex)) {
- $startColor = self::_readColor($fill->startcolorIndex,$this->_palette,$this->_version);
- $fill->getStartColor()->setRGB($startColor['rgb']);
- }
- if (isset($fill->endcolorIndex)) {
- $endColor = self::_readColor($fill->endcolorIndex,$this->_palette,$this->_version);
- $fill->getEndColor()->setRGB($endColor['rgb']);
- }
- // border colors
- $top = $objStyle->getBorders()->getTop();
- $right = $objStyle->getBorders()->getRight();
- $bottom = $objStyle->getBorders()->getBottom();
- $left = $objStyle->getBorders()->getLeft();
- $diagonal = $objStyle->getBorders()->getDiagonal();
- if (isset($top->colorIndex)) {
- $borderTopColor = self::_readColor($top->colorIndex,$this->_palette,$this->_version);
- $top->getColor()->setRGB($borderTopColor['rgb']);
- }
- if (isset($right->colorIndex)) {
- $borderRightColor = self::_readColor($right->colorIndex,$this->_palette,$this->_version);
- $right->getColor()->setRGB($borderRightColor['rgb']);
- }
- if (isset($bottom->colorIndex)) {
- $borderBottomColor = self::_readColor($bottom->colorIndex,$this->_palette,$this->_version);
- $bottom->getColor()->setRGB($borderBottomColor['rgb']);
- }
- if (isset($left->colorIndex)) {
- $borderLeftColor = self::_readColor($left->colorIndex,$this->_palette,$this->_version);
- $left->getColor()->setRGB($borderLeftColor['rgb']);
- }
- if (isset($diagonal->colorIndex)) {
- $borderDiagonalColor = self::_readColor($diagonal->colorIndex,$this->_palette,$this->_version);
- $diagonal->getColor()->setRGB($borderDiagonalColor['rgb']);
- }
- }
- }
- // treat MSODRAWINGGROUP records, workbook-level Escher
- if (!$this->_readDataOnly && $this->_drawingGroupData) {
- $escherWorkbook = new PHPExcel_Shared_Escher();
- $reader = new PHPExcel_Reader_Excel5_Escher($escherWorkbook);
- $escherWorkbook = $reader->load($this->_drawingGroupData);
- // debug Escher stream
- //$debug = new Debug_Escher(new PHPExcel_Shared_Escher());
- //$debug->load($this->_drawingGroupData);
- }
- // Parse the individual sheets
- foreach ($this->_sheets as $sheet) {
- if ($sheet['sheetType'] != 0x00) {
- // 0x00: Worksheet, 0x02: Chart, 0x06: Visual Basic module
- continue;
- }
- // check if sheet should be skipped
- if (isset($this->_loadSheetsOnly) && !in_array($sheet['name'], $this->_loadSheetsOnly)) {
- continue;
- }
- // add sheet to PHPExcel object
- $this->_phpSheet = $this->_phpExcel->createSheet();
- // Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in formula
- // cells... during the load, all formulae should be correct, and we're simply bringing the worksheet
- // name in line with the formula, not the reverse
- $this->_phpSheet->setTitle($sheet['name'],false);
- $this->_phpSheet->setSheetState($sheet['sheetState']);
- $this->_pos = $sheet['offset'];
- // Initialize isFitToPages. May change after reading SHEETPR record.
- $this->_isFitToPages = false;
- // Initialize drawingData
- $this->_drawingData = '';
- // Initialize objs
- $this->_objs = array();
- // Initialize shared formula parts
- $this->_sharedFormulaParts = array();
- // Initialize shared formulas
- $this->_sharedFormulas = array();
- // Initialize text objs
- $this->_textObjects = array();
- // Initialize cell annotations
- $this->_cellNotes = array();
- $this->textObjRef = -1;
- while ($this->_pos <= $this->_dataSize - 4) {
- $code = self::_GetInt2d($this->_data, $this->_pos);
- switch ($code) {
- case self::XLS_Type_BOF: $this->_readBof(); break;
- case self::XLS_Type_PRINTGRIDLINES: $this->_readPrintGridlines(); break;
- case self::XLS_Type_DEFAULTROWHEIGHT: $this->_readDefaultRowHeight(); break;
- case self::XLS_Type_SHEETPR: $this->_readSheetPr(); break;
- case self::XLS_Type_HORIZONTALPAGEBREAKS: $this->_readHorizontalPageBreaks(); break;
- case self::XLS_Type_VERTICALPAGEBREAKS: $this->_readVerticalPageBreaks(); break;
- case self::XLS_Type_HEADER: $this->_readHeader(); break;
- case self::XLS_Type_FOOTER: $this->_readFooter(); break;
- case self::XLS_Type_HCENTER: $this->_readHcenter(); break;
- case self::XLS_Type_VCENTER: $this->_readVcenter(); break;
- case self::XLS_Type_LEFTMARGIN: $this->_readLeftMargin(); break;
- case self::XLS_Type_RIGHTMARGIN: $this->_readRightMargin(); break;
- case self::XLS_Type_TOPMARGIN: $this->_readTopMargin(); break;
- case self::XLS_Type_BOTTOMMARGIN: $this->_readBottomMargin(); break;
- case self::XLS_Type_PAGESETUP: $this->_readPageSetup(); break;
- case self::XLS_Type_PROTECT: $this->_readProtect(); break;
- case self::XLS_Type_SCENPROTECT: $this->_readScenProtect(); break;
- case self::XLS_Type_OBJECTPROTECT: $this->_readObjectProtect(); break;
- case self::XLS_Type_PASSWORD: $this->_readPassword(); break;
- case self::XLS_Type_DEFCOLWIDTH: $this->_readDefColWidth(); break;
- case self::XLS_Type_COLINFO: $this->_readColInfo(); break;
- case self::XLS_Type_DIMENSION: $this->_readDefault(); break;
- case self::XLS_Type_ROW: $this->_readRow(); break;
- case self::XLS_Type_DBCELL: $this->_readDefault(); break;
- case self::XLS_Type_RK: $this->_readRk(); break;
- case self::XLS_Type_LABELSST: $this->_readLabelSst(); break;
- case self::XLS_Type_MULRK: $this->_readMulRk(); break;
- case self::XLS_Type_NUMBER: $this->_readNumber(); break;
- case self::XLS_Type_FORMULA: $this->_readFormula(); break;
- case self::XLS_Type_SHAREDFMLA: $this->_readSharedFmla(); break;
- case self::XLS_Type_BOOLERR: $this->_readBoolErr(); break;
- case self::XLS_Type_MULBLANK: $this->_readMulBlank(); break;
- case self::XLS_Type_LABEL: $this->_readLabel(); break;
- case self::XLS_Type_BLANK: $this->_readBlank(); break;
- case self::XLS_Type_MSODRAWING: $this->_readMsoDrawing(); break;
- case self::XLS_Type_OBJ: $this->_readObj(); break;
- case self::XLS_Type_WINDOW2: $this->_readWindow2(); break;
- case self::XLS_Type_SCL: $this->_readScl(); break;
- case self::XLS_Type_PANE: $this->_readPane(); break;
- case self::XLS_Type_SELECTION: $this->_readSelection(); break;
- case self::XLS_Type_MERGEDCELLS: $this->_readMergedCells(); break;
- case self::XLS_Type_HYPERLINK: $this->_readHyperLink(); break;
- case self::XLS_Type_DATAVALIDATIONS: $this->_readDataValidations(); break;
- case self::XLS_Type_DATAVALIDATION: $this->_readDataValidation(); break;
- case self::XLS_Type_SHEETLAYOUT: $this->_readSheetLayout(); break;
- case self::XLS_Type_SHEETPROTECTION: $this->_readSheetProtection(); break;
- case self::XLS_Type_RANGEPROTECTION: $this->_readRangeProtection(); break;
- case self::XLS_Type_NOTE: $this->_readNote(); break;
- //case self::XLS_Type_IMDATA: $this->_readImData(); break;
- case self::XLS_Type_TXO: $this->_readTextObject(); break;
- case self::XLS_Type_CONTINUE: $this->_readContinue(); break;
- case self::XLS_Type_EOF: $this->_readDefault(); break 2;
- default: $this->_readDefault(); break;
- }
- }
- // treat MSODRAWING records, sheet-level Escher
- if (!$this->_readDataOnly && $this->_drawingData) {
- $escherWorksheet = new PHPExcel_Shared_Escher();
- $reader = new PHPExcel_Reader_Excel5_Escher($escherWorksheet);
- $escherWorksheet = $reader->load($this->_drawingData);
- // debug Escher stream
- //$debug = new Debug_Escher(new PHPExcel_Shared_Escher());
- //$debug->load($this->_drawingData);
- // get all spContainers in one long array, so they can be mapped to OBJ records
- $allSpContainers = $escherWorksheet->getDgContainer()->getSpgrContainer()->getAllSpContainers();
- }
- // treat OBJ records
- foreach ($this->_objs as $n => $obj) {
- // echo '<hr /><b>Object</b> reference is ',$n,'<br />';
- // var_dump($obj);
- // echo '<br />';
- // the first shape container never has a corresponding OBJ record, hence $n + 1
- $spContainer = $allSpContainers[$n + 1];
- // we skip all spContainers that are a part of a group shape since we cannot yet handle those
- if ($spContainer->getNestingLevel() > 1) {
- continue;
- }
- // calculate the width and height of the shape
- list($startColumn, $startRow) = PHPExcel_Cell::coordinateFromString($spContainer->getStartCoordinates());
- list($endColumn, $endRow) = PHPExcel_Cell::coordinateFromString($spContainer->getEndCoordinates());
- $startOffsetX = $spContainer->getStartOffsetX();
- $startOffsetY = $spContainer->getStartOffsetY();
- $endOffsetX = $spContainer->getEndOffsetX();
- $endOffsetY = $spContainer->getEndOffsetY();
- $width = PHPExcel_Shared_Excel5::getDistanceX($this->_phpSheet, $startColumn, $startOffsetX, $endColumn, $endOffsetX);
- $height = PHPExcel_Shared_Excel5::getDistanceY($this->_phpSheet, $startRow, $startOffsetY, $endRow, $endOffsetY);
- // calculate offsetX and offsetY of the shape
- $offsetX = $startOffsetX * PHPExcel_Shared_Excel5::sizeCol($this->_phpSheet, $startColumn) / 1024;
- $offsetY = $startOffsetY * PHPExcel_Shared_Excel5::sizeRow($this->_phpSheet, $startRow) / 256;
- switch ($obj['otObjType']) {
- case 0x19:
- // Note
- // echo 'Cell Annotation Object<br />';
- // echo 'Object ID is ',$obj['idObjID'],'<br />';
- //
- if (isset($this->_cellNotes[$obj['idObjID']])) {
- $cellNote = $this->_cellNotes[$obj['idObjID']];
- // echo '_cellNotes[',$obj['idObjID'],']: ';
- // var_dump($cellNote);
- // echo '<br />';
- //
- if (isset($this->_textObjects[$obj['idObjID']])) {
- $textObject = $this->_textObjects[$obj['idObjID']];
- // echo '_textObject: ';
- // var_dump($textObject);
- // echo '<br />';
- //
- $this->_cellNotes[$obj['idObjID']]['objTextData'] = $textObject;
- $text = $textObject['text'];
- }
- // echo $text,'<br />';
- }
- break;
- case 0x08:
- // echo 'Picture Object<br />';
- // picture
- // get index to BSE entry (1-based)
- $BSEindex = $spContainer->getOPT(0x0104);
- $BSECollection = $escherWorkbook->getDggContainer()->getBstoreContainer()->getBSECollection();
- $BSE = $BSECollection[$BSEindex - 1];
- $blipType = $BSE->getBlipType();
- // need check because some blip types are not supported by Escher reader such as EMF
- if ($blip = $BSE->getBlip()) {
- $ih = imagecreatefromstring($blip->getData());
- $drawing = new PHPExcel_Worksheet_MemoryDrawing();
- $drawing->setImageResource($ih);
- // width, height, offsetX, offsetY
- $drawing->setResizeProportional(false);
- $drawing->setWidth($width);
- $drawing->setHeight($height);
- $drawing->setOffsetX($offsetX);
- $drawing->setOffsetY($offsetY);
- switch ($blipType) {
- case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_JPEG:
- $drawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_JPEG);
- $drawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_JPEG);
- break;
- case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_PNG:
- $drawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_PNG);
- $drawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_PNG);
- break;
- }
- $drawing->setWorksheet($this->_phpSheet);
- $drawing->setCoordinates($spContainer->getStartCoordinates());
- }
- break;
- default:
- // other object type
- break;
- }
- }
- // treat SHAREDFMLA records
- if ($this->_version == self::XLS_BIFF8) {
- foreach ($this->_sharedFormulaParts as $cell => $baseCell) {
- list($column, $row) = PHPExcel_Cell::coordinateFromString($cell);
- if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($column, $row, $this->_phpSheet->getTitle()) ) {
- $formula = $this->_getFormulaFromStructure($this->_sharedFormulas[$baseCell], $cell);
- $this->_phpSheet->getCell($cell)->setValueExplicit('=' . $formula, PHPExcel_Cell_DataType::TYPE_FORMULA);
- }
- }
- }
- if (!empty($this->_cellNotes)) {
- foreach($this->_cellNotes as $note => $noteDetails) {
- // echo '<b>Cell annotation ',$note,'</b><br />';
- // var_dump($noteDetails);
- // echo '<br />';
- $cellAddress = str_replace('$','',$noteDetails['cellRef']);
- $this->_phpSheet->getComment( $cellAddress )
- ->setAuthor( $noteDetails['author'] )
- ->setText($this->_parseRichText($noteDetails['objTextData']['text']) );
- }
- }
- }
- // add the named ranges (defined names)
- foreach ($this->_definedname as $definedName) {
- if ($definedName['isBuiltInName']) {
- switch ($definedName['name']) {
- case pack('C', 0x06):
- // print area
- // in general, formula looks like this: Foo!$C$7:$J$66,Bar!$A$1:$IV$2
- $ranges = explode(',', $definedName['formula']); // FIXME: what if sheetname contains comma?
- $extractedRanges = array();
- foreach ($ranges as $range) {
- // $range should look like one of these
- // Foo!$C$7:$J$66
- // Bar!$A$1:$IV$2
- $explodes = explode('!', $range); // FIXME: what if sheetname contains exclamation mark?
- $sheetName = $explodes[0];
- if (count($explodes) == 2) {
- $extractedRanges[] = str_replace('$', '', $explodes[1]); // C7:J66
- }
- }
- if ($docSheet = $this->_phpExcel->getSheetByName($sheetName)) {
- $docSheet->getPageSetup()->setPrintArea(implode(',', $extractedRanges)); // C7:J66,A1:IV2
- }
- break;
- case pack('C', 0x07):
- // print titles (repeating rows)
- // Assuming BIFF8, there are 3 cases
- // 1. repeating rows
- // formula looks like this: Sheet!$A$1:$IV$2
- // rows 1-2 repeat
- // 2. repeating columns
- // formula looks like this: Sheet!$A$1:$B$65536
- // columns A-B repeat
- // 3. both repeating rows and repeating columns
- // formula looks like this: Sheet!$A$1:$B$65536,Sheet!$A$1:$IV$2
- $ranges = explode(',', $definedName['formula']); // FIXME: what if sheetname contains comma?
- foreach ($ranges as $range) {
- // $range should look like this one of these
- // Sheet!$A$1:$B$65536
- // Sheet!$A$1:$IV$2
- $explodes = explode('!', $range);
- if (count($explodes) == 2) {
- if ($docSheet = $this->_phpExcel->getSheetByName($explodes[0])) {
- $extractedRange = $explodes[1];
- $extractedRange = str_replace('$', '', $extractedRange);
- $coordinateStrings = explode(':', $extractedRange);
- if (count($coordinateStrings) == 2) {
- list($firstColumn, $firstRow) = PHPExcel_Cell::coordinateFromString($coordinateStrings[0]);
- list($lastColumn, $lastRow) = PHPExcel_Cell::coordinateFromString($coordinateStrings[1]);
- if ($firstColumn == 'A' and $lastColumn == 'IV') {
- // then we have repeating rows
- $docSheet->getPageSetup()->setRowsToRepeatAtTop(array($firstRow, $lastRow));
- } elseif ($firstRow == 1 and $lastRow == 65536) {
- // then we have repeating columns
- $docSheet->getPageSetup()->setColumnsToRepeatAtLeft(array($firstColumn, $lastColumn));
- }
- }
- }
- }
- }
- break;
- }
- } else {
- // Extract range
- $explodes = explode('!', $definedName['formula']);
- if (count($explodes) == 2) {
- if (($docSheet = $this->_phpExcel->getSheetByName($explodes[0])) ||
- ($docSheet = $this->_phpExcel->getSheetByName(trim($explodes[0],"'")))) {
- $extractedRange = $explodes[1];
- $extractedRange = str_replace('$', '', $extractedRange);
- $localOnly = ($definedName['scope'] == 0) ? false : true;
- $scope = ($definedName['scope'] == 0) ?
- null : $this->_phpExcel->getSheetByName($this->_sheets[$definedName['scope'] - 1]['name']);
- $this->_phpExcel->addNamedRange( new PHPExcel_NamedRange((string)$definedName['name'], $docSheet, $extractedRange, $localOnly, $scope) );
- }
- } else {
- // Named Value
- // TODO Provide support for named values
- }
- }
- }
- return $this->_phpExcel;
- }
- /**
- * Use OLE reader to extract the relevant data streams from the OLE file
- *
- * @param string $pFilename
- */
- private function _loadOLE($pFilename)
- {
- // OLE reader
- $ole = new PHPExcel_Shared_OLERead();
- // get excel data,
- $res = $ole->read($pFilename);
- // Get workbook data: workbook stream + sheet streams
- $this->_data = $ole->getStream($ole->wrkbook);
- // Get summary information data
- $this->_summaryInformation = $ole->getStream($ole->summaryInformation);
- // Get additional document summary information data
- $this->_documentSummaryInformation = $ole->getStream($ole->documentSummaryInformation);
- // Get user-defined property data
- // $this->_userDefinedProperties = $ole->getUserDefinedProperties();
- }
- /**
- * Read summary information
- */
- private function _readSummaryInformation()
- {
- if (!isset($this->_summaryInformation)) {
- return;
- }
- // offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark)
- // offset: 2; size: 2;
- // offset: 4; size: 2; OS version
- // offset: 6; size: 2; OS indicator
- // offset: 8; size: 16
- // offset: 24; size: 4; section count
- $secCount = self::_GetInt4d($this->_summaryInformation, 24);
- // offset: 28; size: 16; first section's class id: e0 85 9f f2 f9 4f 68 10 ab 91 08 00 2b 27 b3 d9
- // offset: 44; size: 4
- $secOffset = self::_GetInt4d($this->_summaryInformation, 44);
- // section header
- // offset: $secOffset; size: 4; section length
- $secLength = self::_GetInt4d($this->_summaryInformation, $secOffset);
- // offset: $secOffset+4; size: 4; property count
- $countProperties = self::_GetInt4d($this->_summaryInformation, $secOffset+4);
- // initialize code page (used to resolve string values)
- $codePage = 'CP1252';
- // offset: ($secOffset+8); size: var
- // loop through property decarations and properties
- for ($i = 0; $i < $countProperties; ++$i) {
- // offset: ($secOffset+8) + (8 * $i); size: 4; property ID
- $id = self::_GetInt4d($this->_summaryInformation, ($secOffset+8) + (8 * $i));
- // Use value of property id as appropriate
- // offset: ($secOffset+12) + (8 * $i); size: 4; offset from beginning of section (48)
- $offset = self::_GetInt4d($this->_summaryInformation, ($secOffset+12) + (8 * $i));
- $type = self::_GetInt4d($this->_summaryInformation, $secOffset + $offset);
- // initialize property value
- $value = null;
- // extract property value based on property type
- switch ($type) {
- case 0x02: // 2 byte signed integer
- $value = self::_GetInt2d($this->_summaryInformation, $secOffset + 4 + $offset);
- break;
- case 0x03: // 4 byte signed integer
- $value = self::_GetInt4d($this->_summaryInformation, $secOffset + 4 + $offset);
- break;
- case 0x13: // 4 byte unsigned integer
- // not needed yet, fix later if necessary
- break;
- case 0x1E: // null-terminated string prepended by dword string length
- $byteLength = self::_GetInt4d($this->_summaryInformation, $secOffset + 4 + $offset);
- $value = substr($this->_summaryInformation, $secOffset + 8 + $offset, $byteLength);
- $value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage);
- $value = rtrim($value);
- break;
- case 0x40: // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
- // PHP-time
- $value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->_summaryInformation, $secOffset + 4 + $offset, 8));
- break;
- case 0x47: // Clipboard format
- // not needed yet, fix later if necessary
- break;
- }
- switch ($id) {
- case 0x01: // Code Page
- $codePage = PHPExcel_Shared_CodePage::NumberToName($value);
- break;
- case 0x02: // Title
- $this->_phpExcel->getProperties()->setTitle($value);
- break;
- case 0x03: // Subject
- $this->_phpExcel->getProperties()->setSubject($value);
- break;
- case 0x04: // Author (Creator)
- $this->_phpExcel->getProperties()->setCreator($value);
- break;
- case 0x05: // Keywords
- $this->_phpExcel->getProperties()->setKeywords($value);
- break;
- case 0x06: // Comments (Description)
- $this->_phpExcel->getProperties()->setDescription($value);
- break;
- case 0x07: // Template
- // Not supported by PHPExcel
- break;
- case 0x08: // Last Saved By (LastModifiedBy)
- $this->_phpExcel->getProperties()->setLastModifiedBy($value);
- break;
- case 0x09: // Revision
- // Not supported by PHPExcel
- break;
- case 0x0A: // Total Editing Time
- // Not supported by PHPExcel
- break;
- case 0x0B: // Last Printed
- // Not supported by PHPExcel
- break;
- case 0x0C: // Created Date/Time
- $this->_phpExcel->getProperties()->setCreated($value);
- break;
- case 0x0D: // Modified Date/Time
- $this->_phpExcel->getProperties()->setModified($value);
- break;
- case 0x0E: // Number of Pages
- // Not supported by PHPExcel
- break;
- case 0x0F: // Number of Words
- // Not supported by PHPExcel
- break;
- case 0x10: // Number of Characters
- // Not supported by PHPExcel
- break;
- case 0x11: // Thumbnail
- // Not supported by PHPExcel
- break;
- case 0x12: // Name of creating application
- // Not supported by PHPExcel
- break;
- case 0x13: // Security
- // Not supported by PHPExcel
- break;
- }
- }
- }
- /**
- * Read additional document summary information
- */
- private function _readDocumentSummaryInformation()
- {
- if (!isset($this->_documentSummaryInformation)) {
- return;
- }
- // offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark)
- // offset: 2; size: 2;
- // offset: 4; size: 2; OS version
- // offset: 6; size: 2; OS indicator
- // offset: 8; size: 16
- // offset: 24; size: 4; section count
- $secCount = self::_GetInt4d($this->_documentSummaryInformation, 24);
- // echo '$secCount = ',$secCount,'<br />';
- // offset: 28; size: 16; first section's class id: 02 d5 cd d5 9c 2e 1b 10 93 97 08 00 2b 2c f9 ae
- // offset: 44; size: 4; first section offset
- $secOffset = self::_GetInt4d($this->_documentSummaryInformation, 44);
- // echo '$secOffset = ',$secOffset,'<br />';
- // section header
- // offset: $secOffset; size: 4; section length
- $secLength = self::_GetInt4d($this->_documentSummaryInformation, $secOffset);
- // echo '$secLength = ',$secLength,'<br />';
- // offset: $secOffset+4; size: 4; property count
- $countProperties = self::_GetInt4d($this->_documentSummaryInformation, $secOffset+4);
- // echo '$countProperties = ',$countProperties,'<br />';
- // initialize code page (used to resolve string values)
- $codePage = 'CP1252';
- // offset: ($secOffset+8); size: var
- // loop through property decarations and properties
- for ($i = 0; $i < $countProperties; ++$i) {
- // echo 'Property ',$i,'<br />';
- // offset: ($secOffset+8) + (8 * $i); size: 4; property ID
- $id = self::_GetInt4d($this->_documentSummaryInformation, ($secOffset+8) + (8 * $i));
- // echo 'ID is ',$id,'<br />';
- // Use value of property id as appropriate
- // offset: 60 + 8 * $i; size: 4; offset from beginning of section (48)
- $offset = self::_GetInt4d($this->_documentSummaryInformation, ($secOffset+12) + (8 * $i));
- $type = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + $offset);
- // echo 'Type is ',$type,', ';
- // initialize property value
- $value = null;
- // extract property value based on property type
- switch ($type) {
- case 0x02: // 2 byte signed integer
- $value = self::_GetInt2d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
- break;
- case 0x03: // 4 byte signed integer
- $value = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
- break;
- case 0x0B: // Boolean
- $value = self::_GetInt2d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
- $value = ($value == 0 ? false : true);
- break;
- case 0x13: // 4 byte unsigned integer
- // not needed yet, fix later if necessary
- break;
- case 0x1E: // null-terminated string prepended by dword string length
- $byteLength = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
- $value = substr($this->_documentSummaryInformation, $secOffset + 8 + $offset, $byteLength);
- $value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage);
- $value = rtrim($value);
- break;
- case 0x40: // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
- // PHP-Time
- $value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->_documentSummaryInformation, $secOffset + 4 + $offset, 8));
- break;
- case 0x47: // Clipboard format
- // not needed yet, fix later if necessary
- break;
- }
- switch ($id) {
- case 0x01: // Code Page
- $codePage = PHPExcel_Shared_CodePage::NumberToName($value);
- break;
- case 0x02: // Category
- $this->_phpExcel->getProperties()->setCategory($value);
- break;
- case 0x03: // Presentation Target
- // Not supported by PHPExcel
- break;
- case 0x04: // Bytes
- // Not supported by PHPExcel
- break;
- case 0x05: // Lines
- // Not supported by PHPExcel
- break;
- case 0x06: // Paragraphs
- // Not supported by PHPExcel
- break;
- case 0x07: // Slides
- // Not supported by PHPExcel
- break;
- case 0x08: // Notes
- // Not supported by PHPExcel
- break;
- case 0x09: // Hidden Slides
- // Not supported by PHPExcel
- break;
- case 0x0A: // MM Clips
- // Not supported by PHPExcel
- break;
- case 0x0B: // Scale Crop
- // Not supported by PHPExcel
- break;
- case 0x0C: // Heading Pairs
- // Not supported by PHPExcel
- break;
- case 0x0D: // Titles of Parts
- // Not supported by PHPExcel
- break;
- case 0x0E: // Manager
- $this->_phpExcel->getProperties()->setManager($value);
- break;
- case 0x0F: // Company
- $this->_phpExcel->getProperties()->setCompany($value);
- break;
- case 0x10: // Links up-to-date
- // Not supported by PHPExcel
- break;
- }
- }
- }
- /**
- * Reads a general type of BIFF record. Does nothing except for moving stream pointer forward to next record.
- */
- private function _readDefault()
- {
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
- // $recordData = substr($this->_data, $this->_pos + 4, $length);
- // move stream pointer to next record
- $this->_pos += 4 + $length;
- }
- /**
- * The NOTE record specifies a comment associated with a particular cell. In Excel 95 (BIFF7) and earlier versions,
- * this record stores a note (cell note). This feature was significantly enhanced in Excel 97.
- */
- private function _readNote()
- {
- // echo '<b>Read Cell Annotation</b><br />';
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
- $recordData = substr($this->_data, $this->_pos + 4, $length);
- // move stream pointer to next record
- $this->_pos += 4 + $length;
- if ($this->_readDataOnly) {
- return;
- }
- $cellAddress = $this->_readBIFF8CellAddress(substr($recordData, 0, 4));
- if ($this->_version == self::XLS_BIFF8) {
- $noteObjID = self::_GetInt2d($recordData, 6);
- $noteAuthor = self::_readUnicodeStringLong(substr($recordData, 8));
- $noteAuthor = $noteAuthor['value'];
- // echo 'Note Address=',$cellAddress,'<br />';
- // echo 'Note Object ID=',$noteObjID,'<br />';
- // echo 'Note Author=',$noteAuthor,'<hr />';
- //
- $this->_cellNotes[$noteObjID] = array('cellRef' => $cellAddress,
- 'objectID' => $noteObjID,
- 'author' => $noteAuthor
- );
- } else {
- $extension = false;
- if ($cellAddress == '$B$65536') {
- // If the address row is -1 and the column is 0, (which translates as $B$65536) then this is a continuation
- // note from the previous cell annotation. We're not yet handling this, so annotations longer than the
- // max 2048 bytes will probably throw a wobbly.
- $row = self::_GetInt2d($recordData, 0);
- $extension = true;
- $cellAddress = array_pop(array_keys($this->_phpSheet->getComments()));
- }
- // echo 'Note Address=',$cellAddress,'<br />';
- $cellAddress = str_replace('$','',$cellAddress);
- $noteLength = self::_GetInt2d($recordData, 4);
- $noteText = trim(substr($recordData, 6));
- // echo 'Note Length=',$noteLength,'<br />';
- // echo 'Note Text=',$noteText,'<br />';
- if ($extension) {
- // Concatenate this extension with the currently set comment for the cell
- $comment = $this->_phpSheet->getComment( $cellAddress );
- $commentText = $comment->getText()->getPlainText();
- $comment->setText($this->_parseRichText($commentText.$noteText) );
- } else {
- // Set comment for the cell
- $this->_phpSheet->getComment( $cellAddress )
- // ->setAuthor( $author )
- ->setText($this->_parseRichText($noteText) );
- }
- }
- }
- /**
- * The TEXT Object record contains the text associated with a cell annotation.
- */
- private function _readTextObject()
- {
- $length = self::_GetInt2d($this->_data, $this->_pos + 2);
- $recordData = substr($this->_data, $this->_pos + 4, $length);
- // move stream pointe…
Large files files are truncated, but you can click here to view the full file