Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php/*** A class for reading Microsoft Excel (97/2003) Spreadsheets.** Version 2.22** Enhanced and maintained by Alex Frenkel < excell2@frenkel-online.com >* Maintained at http://code.google.com/p/php-excel-reader2/** Previosly mantained by Matt Kruse < http://mattkruse.com >* Maintained at http://code.google.com/p/php-excel-reader/** Format parsing and MUCH more contributed by:* Matt Roxburgh < http://www.roxburgh.me.uk >** DOCUMENTATION* =============* http://code.google.com/p/php-excel-reader2/wiki/Documentation** CHANGE LOG* ==========* http://code.google.com/p/php-excel-reader2/wiki/ChangeHistory*** --------------------------------------------------------------------------** Originally developed by Vadim Tkachenko under the name PHPExcelReader.* (http://sourceforge.net/projects/phpexcelreader)* Based on the Java version by Andy Khan (http://www.andykhan.com). Now* maintained by David Sanders. Reads only Biff 7 and Biff 8 formats.** PHP versions 4 and 5** LICENSE: This source file is subject to version 3.0 of the PHP license* that is available through the world-wide-web at the following URI:* http://www.php.net/license/3_0.txt. If you did not receive a copy of* the PHP License and are unable to obtain it through the web, please* send a note to license@php.net so we can mail you a copy immediately.** @category Spreadsheet* @package Spreadsheet_Excel_Reader* @author Vadim Tkachenko <vt@apachephp.com>* @license http://www.php.net/license/3_0.txt PHP License 3.0* @version CVS: $Id: reader.php 19 2007-03-13 12:42:41Z shangxiao $* @link http://pear.php.net/package/Spreadsheet_Excel_Reader* @see OLE, Spreadsheet_Excel_Writer* --------------------------------------------------------------------------*/define ( 'NUM_BIG_BLOCK_DEPOT_BLOCKS_POS', 0x2c );define ( 'SMALL_BLOCK_DEPOT_BLOCK_POS', 0x3c );define ( 'ROOT_START_BLOCK_POS', 0x30 );define ( 'BIG_BLOCK_SIZE', 0x200 );define ( 'SMALL_BLOCK_SIZE', 0x40 );define ( 'EXTENSION_BLOCK_POS', 0x44 );define ( 'NUM_EXTENSION_BLOCK_POS', 0x48 );define ( 'PROPERTY_STORAGE_BLOCK_SIZE', 0x80 );define ( 'BIG_BLOCK_DEPOT_BLOCKS_POS', 0x4c );define ( 'SMALL_BLOCK_THRESHOLD', 0x1000 );// property storage offsetsdefine ( 'SIZE_OF_NAME_POS', 0x40 );define ( 'TYPE_POS', 0x42 );define ( 'START_BLOCK_POS', 0x74 );define ( 'SIZE_POS', 0x78 );define ( 'IDENTIFIER_OLE', pack ( "CCCCCCCC", 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 ) );function GetInt4d($data, $pos) {$value = ord ( $data [$pos] ) | (ord ( $data [$pos + 1] ) << 8) | (ord ( $data [$pos + 2] ) << 16) | (ord ( $data [$pos + 3] ) << 24);if ($value >= 4294967294) {$value = - 2;}return $value;}// http://uk.php.net/manual/en/function.getdate.phpfunction gmgetdate($ts = null) {$k = array ('seconds', 'minutes', 'hours', 'mday', 'wday', 'mon', 'year', 'yday', 'weekday', 'month', 0 );return (array_comb ( $k, explode ( ":", gmdate ( 's:i:G:j:w:n:Y:z:l:F:U', is_null ( $ts ) ? time () : $ts ) ) ));}// Added for PHP4 compatibilityfunction array_comb($array1, $array2) {$out = array ();foreach ( $array1 as $key => $value ) {$out [$value] = $array2 [$key];}return $out;}function v($data, $pos) {return ord ( $data [$pos] ) | ord ( $data [$pos + 1] ) << 8;}class OLERead {var $data = '';function OLERead() {}function read($sFileName) {// check if file exist and is readable (Darko Miljanovic)if (! is_readable ( $sFileName )) {$this->error = 1;return false;}$this->data = @file_get_contents ( $sFileName );if (! $this->data) {$this->error = 1;return false;}if (substr ( $this->data, 0, 8 ) != IDENTIFIER_OLE) {$this->error = 1;return false;}$this->numBigBlockDepotBlocks = GetInt4d ( $this->data, NUM_BIG_BLOCK_DEPOT_BLOCKS_POS );$this->sbdStartBlock = GetInt4d ( $this->data, SMALL_BLOCK_DEPOT_BLOCK_POS );$this->rootStartBlock = GetInt4d ( $this->data, ROOT_START_BLOCK_POS );$this->extensionBlock = GetInt4d ( $this->data, EXTENSION_BLOCK_POS );$this->numExtensionBlocks = GetInt4d ( $this->data, NUM_EXTENSION_BLOCK_POS );$bigBlockDepotBlocks = array ();$pos = BIG_BLOCK_DEPOT_BLOCKS_POS;$bbdBlocks = $this->numBigBlockDepotBlocks;if ($this->numExtensionBlocks != 0) {$bbdBlocks = (BIG_BLOCK_SIZE - BIG_BLOCK_DEPOT_BLOCKS_POS) / 4;}for($i = 0; $i < $bbdBlocks; $i ++) {$bigBlockDepotBlocks [$i] = GetInt4d ( $this->data, $pos );$pos += 4;}for($j = 0; $j < $this->numExtensionBlocks; $j ++) {$pos = ($this->extensionBlock + 1) * BIG_BLOCK_SIZE;$blocksToRead = min ( $this->numBigBlockDepotBlocks - $bbdBlocks, BIG_BLOCK_SIZE / 4 - 1 );for($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; $i ++) {$bigBlockDepotBlocks [$i] = GetInt4d ( $this->data, $pos );$pos += 4;}$bbdBlocks += $blocksToRead;if ($bbdBlocks < $this->numBigBlockDepotBlocks) {$this->extensionBlock = GetInt4d ( $this->data, $pos );}}// readBigBlockDepot$pos = 0;$index = 0;$this->bigBlockChain = array ();for($i = 0; $i < $this->numBigBlockDepotBlocks; $i ++) {$pos = ($bigBlockDepotBlocks [$i] + 1) * BIG_BLOCK_SIZE;//echo "pos = $pos";for($j = 0; $j < BIG_BLOCK_SIZE / 4; $j ++) {$this->bigBlockChain [$index] = GetInt4d ( $this->data, $pos );$pos += 4;$index ++;}}// readSmallBlockDepot();$pos = 0;$index = 0;$sbdBlock = $this->sbdStartBlock;$this->smallBlockChain = array ();while ( $sbdBlock != - 2 ) {$pos = ($sbdBlock + 1) * BIG_BLOCK_SIZE;for($j = 0; $j < BIG_BLOCK_SIZE / 4; $j ++) {$this->smallBlockChain [$index] = GetInt4d ( $this->data, $pos );$pos += 4;$index ++;}$sbdBlock = $this->bigBlockChain [$sbdBlock];}// readData(rootStartBlock)$block = $this->rootStartBlock;$pos = 0;$this->entry = $this->__readData ( $block );$this->__readPropertySets ();}function __readData($bl) {$block = $bl;$pos = 0;$data = '';while ( $block != - 2 ) {$pos = ($block + 1) * BIG_BLOCK_SIZE;$data = $data . substr ( $this->data, $pos, BIG_BLOCK_SIZE );$block = $this->bigBlockChain [$block];}return $data;}function __readPropertySets() {$offset = 0;while ( $offset < strlen ( $this->entry ) ) {$d = substr ( $this->entry, $offset, PROPERTY_STORAGE_BLOCK_SIZE );$nameSize = ord ( $d [SIZE_OF_NAME_POS] ) | (ord ( $d [SIZE_OF_NAME_POS + 1] ) << 8);$type = ord ( $d [TYPE_POS] );$startBlock = GetInt4d ( $d, START_BLOCK_POS );$size = GetInt4d ( $d, SIZE_POS );$name = '';for($i = 0; $i < $nameSize; $i ++) {$name .= $d [$i];}$name = str_replace ( "\x00", "", $name );$this->props [] = array ('name' => $name, 'type' => $type, 'startBlock' => $startBlock, 'size' => $size );if ((strtolower ( $name ) == "workbook") || (strtolower ( $name ) == "book")) {$this->wrkbook = count ( $this->props ) - 1;}if ($name == "Root Entry") {$this->rootentry = count ( $this->props ) - 1;}$offset += PROPERTY_STORAGE_BLOCK_SIZE;}}function getWorkBook() {if ($this->props [$this->wrkbook] ['size'] < SMALL_BLOCK_THRESHOLD) {$rootdata = $this->__readData ( $this->props [$this->rootentry] ['startBlock'] );$streamData = '';$block = $this->props [$this->wrkbook] ['startBlock'];$pos = 0;while ( $block != - 2 ) {$pos = $block * SMALL_BLOCK_SIZE;$streamData .= substr ( $rootdata, $pos, SMALL_BLOCK_SIZE );$block = $this->smallBlockChain [$block];}return $streamData;} else {$numBlocks = $this->props [$this->wrkbook] ['size'] / BIG_BLOCK_SIZE;if ($this->props [$this->wrkbook] ['size'] % BIG_BLOCK_SIZE != 0) {$numBlocks ++;}if ($numBlocks == 0)return '';$streamData = '';$block = $this->props [$this->wrkbook] ['startBlock'];$pos = 0;while ( $block != - 2 ) {$pos = ($block + 1) * BIG_BLOCK_SIZE;$streamData .= substr ( $this->data, $pos, BIG_BLOCK_SIZE );$block = $this->bigBlockChain [$block];}return $streamData;}}}define ( 'SPREADSHEET_EXCEL_READER_BIFF8', 0x600 );define ( 'SPREADSHEET_EXCEL_READER_BIFF7', 0x500 );define ( 'SPREADSHEET_EXCEL_READER_WORKBOOKGLOBALS', 0x5 );define ( 'SPREADSHEET_EXCEL_READER_WORKSHEET', 0x10 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_BOF', 0x809 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_EOF', 0x0a );define ( 'SPREADSHEET_EXCEL_READER_TYPE_BOUNDSHEET', 0x85 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_DIMENSION', 0x200 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_ROW', 0x208 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_DBCELL', 0xd7 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_FILEPASS', 0x2f );define ( 'SPREADSHEET_EXCEL_READER_TYPE_NOTE', 0x1c );define ( 'SPREADSHEET_EXCEL_READER_TYPE_TXO', 0x1b6 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_RK', 0x7e );define ( 'SPREADSHEET_EXCEL_READER_TYPE_RK2', 0x27e );define ( 'SPREADSHEET_EXCEL_READER_TYPE_MULRK', 0xbd );define ( 'SPREADSHEET_EXCEL_READER_TYPE_MULBLANK', 0xbe );define ( 'SPREADSHEET_EXCEL_READER_TYPE_INDEX', 0x20b );define ( 'SPREADSHEET_EXCEL_READER_TYPE_SST', 0xfc );define ( 'SPREADSHEET_EXCEL_READER_TYPE_EXTSST', 0xff );define ( 'SPREADSHEET_EXCEL_READER_TYPE_CONTINUE', 0x3c );define ( 'SPREADSHEET_EXCEL_READER_TYPE_LABEL', 0x204 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_LABELSST', 0xfd );define ( 'SPREADSHEET_EXCEL_READER_TYPE_NUMBER', 0x203 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_NAME', 0x18 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_ARRAY', 0x221 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_STRING', 0x207 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_FORMULA', 0x406 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_FORMULA2', 0x6 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_FORMAT', 0x41e );define ( 'SPREADSHEET_EXCEL_READER_TYPE_XF', 0xe0 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_BOOLERR', 0x205 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_FONT', 0x0031 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_PALETTE', 0x0092 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_UNKNOWN', 0xffff );define ( 'SPREADSHEET_EXCEL_READER_TYPE_NINETEENFOUR', 0x22 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_MERGEDCELLS', 0xE5 );define ( 'SPREADSHEET_EXCEL_READER_UTCOFFSETDAYS', 25569 );define ( 'SPREADSHEET_EXCEL_READER_UTCOFFSETDAYS1904', 24107 );define ( 'SPREADSHEET_EXCEL_READER_MSINADAY', 86400 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_HYPER', 0x01b8 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_COLINFO', 0x7d );define ( 'SPREADSHEET_EXCEL_READER_TYPE_DEFCOLWIDTH', 0x55 );define ( 'SPREADSHEET_EXCEL_READER_TYPE_STANDARDWIDTH', 0x99 );define ( 'SPREADSHEET_EXCEL_READER_DEF_NUM_FORMAT', "%s" );/** Main Class*/class Spreadsheet_Excel_Reader {// MK: Added to make data retrieval easiervar $colnames = array ();var $colindexes = array ();var $standardColWidth = 0;var $defaultColWidth = 0;function myHex($d) {if ($d < 16)return "0" . dechex ( $d );return dechex ( $d );}function dumpHexData($data, $pos, $length) {$info = "";for($i = 0; $i <= $length; $i ++) {$info .= ($i == 0 ? "" : " ") . $this->myHex ( ord ( $data [$pos + $i] ) ) . (ord ( $data [$pos + $i] ) > 31 ? "[" . $data [$pos + $i] . "]" : '');}return $info;}function getCol($col) {if (is_string ( $col )) {$col = strtolower ( $col );if (array_key_exists ( $col, $this->colnames )) {$col = $this->colnames [$col];}}return $col;}// PUBLIC API FUNCTIONS// --------------------function val($row, $col, $sheet = 0) {$col = $this->getCol ( $col );if (array_key_exists ( $row, $this->sheets [$sheet] ['cells'] ) && array_key_exists ( $col, $this->sheets [$sheet] ['cells'] [$row] )) {return $this->sheets [$sheet] ['cells'] [$row] [$col];}return "";}function value($row, $col, $sheet = 0) {return $this->val ( $row, $col, $sheet );}function info($row, $col, $type = '', $sheet = 0) {$col = $this->getCol ( $col );if (array_key_exists ( 'cellsInfo', $this->sheets [$sheet] ) && array_key_exists ( $row, $this->sheets [$sheet] ['cellsInfo'] ) && array_key_exists ( $col, $this->sheets [$sheet] ['cellsInfo'] [$row] ) && array_key_exists ( $type, $this->sheets [$sheet] ['cellsInfo'] [$row] [$col] )) {return $this->sheets [$sheet] ['cellsInfo'] [$row] [$col] [$type];}return "";}function type($row, $col, $sheet = 0) {return $this->info ( $row, $col, 'type', $sheet );}function raw($row, $col, $sheet = 0) {return $this->info ( $row, $col, 'raw', $sheet );}function rowspan($row, $col, $sheet = 0) {$val = $this->info ( $row, $col, 'rowspan', $sheet );if ($val == "") {return 1;}return $val;}function colspan($row, $col, $sheet = 0) {$val = $this->info ( $row, $col, 'colspan', $sheet );if ($val == "") {return 1;}return $val;}function hyperlink($row, $col, $sheet = 0) {$link = $this->sheets [$sheet] ['cellsInfo'] [$row] [$col] ['hyperlink'];if ($link) {return $link ['link'];}return '';}function rowcount($sheet = 0) {return $this->sheets [$sheet] ['numRows'];}function colcount($sheet = 0) {return $this->sheets [$sheet] ['numCols'];}function colwidth($col, $sheet = 0) {// Col width is actually the width of the number 0. So we have to estimate and come closereturn $this->colInfo [$sheet] [$col] ['width'] / 9142 * 200;}function colhidden($col, $sheet = 0) {return ! ! $this->colInfo [$sheet] [$col] ['hidden'];}function rowheight($row, $sheet = 0) {return $this->rowInfo [$sheet] [$row] ['height'];}function rowhidden($row, $sheet = 0) {return ! ! $this->rowInfo [$sheet] [$row] ['hidden'];}// GET THE CSS FOR FORMATTING// ==========================function style($row, $col, $sheet = 0, $properties = '') {$css = "";$font = $this->font ( $row, $col, $sheet );if ($font != "") {$css .= "font-family:$font;";}$align = $this->align ( $row, $col, $sheet );if ($align != "") {$css .= "text-align:$align;";}$height = $this->height ( $row, $col, $sheet );if ($height != "") {$css .= "font-size:$height" . "px;";}$bgcolor = $this->bgColor ( $row, $col, $sheet );if ($bgcolor != "") {$bgcolor = $this->colors [$bgcolor];$css .= "background-color:$bgcolor;";}$color = $this->color ( $row, $col, $sheet );if ($color != "") {$css .= "color:$color;";}$bold = $this->bold ( $row, $col, $sheet );if ($bold) {$css .= "font-weight:bold;";}$italic = $this->italic ( $row, $col, $sheet );if ($italic) {$css .= "font-style:italic;";}$underline = $this->underline ( $row, $col, $sheet );if ($underline) {$css .= "text-decoration:underline;";}// Borders$bLeft = $this->borderLeft ( $row, $col, $sheet );$bRight = $this->borderRight ( $row, $col, $sheet );$bTop = $this->borderTop ( $row, $col, $sheet );$bBottom = $this->borderBottom ( $row, $col, $sheet );$bLeftCol = $this->borderLeftColor ( $row, $col, $sheet );$bRightCol = $this->borderRightColor ( $row, $col, $sheet );$bTopCol = $this->borderTopColor ( $row, $col, $sheet );$bBottomCol = $this->borderBottomColor ( $row, $col, $sheet );// Try to output the minimal required styleif ($bLeft != "" && $bLeft == $bRight && $bRight == $bTop && $bTop == $bBottom) {$css .= "border:" . $this->lineStylesCss [$bLeft] . ";";} else {if ($bLeft != "") {$css .= "border-left:" . $this->lineStylesCss [$bLeft] . ";";}if ($bRight != "") {$css .= "border-right:" . $this->lineStylesCss [$bRight] . ";";}if ($bTop != "") {$css .= "border-top:" . $this->lineStylesCss [$bTop] . ";";}if ($bBottom != "") {$css .= "border-bottom:" . $this->lineStylesCss [$bBottom] . ";";}}// Only output border colors if there is an actual border specifiedif ($bLeft != "" && $bLeftCol != "") {$css .= "border-left-color:" . $bLeftCol . ";";}if ($bRight != "" && $bRightCol != "") {$css .= "border-right-color:" . $bRightCol . ";";}if ($bTop != "" && $bTopCol != "") {$css .= "border-top-color:" . $bTopCol . ";";}if ($bBottom != "" && $bBottomCol != "") {$css .= "border-bottom-color:" . $bBottomCol . ";";}return $css;}// FORMAT PROPERTIES// =================function format($row, $col, $sheet = 0) {return $this->info ( $row, $col, 'format', $sheet );}function formatIndex($row, $col, $sheet = 0) {return $this->info ( $row, $col, 'formatIndex', $sheet );}function formatColor($row, $col, $sheet = 0) {return $this->info ( $row, $col, 'formatColor', $sheet );}// CELL (XF) PROPERTIES// ====================function xfRecord($row, $col, $sheet = 0) {$xfIndex = $this->info ( $row, $col, 'xfIndex', $sheet );if ($xfIndex != "") {return $this->xfRecords [$xfIndex];}return null;}function xfProperty($row, $col, $sheet, $prop) {$xfRecord = $this->xfRecord ( $row, $col, $sheet );if ($xfRecord != null) {return $xfRecord [$prop];}return "";}function align($row, $col, $sheet = 0) {return $this->xfProperty ( $row, $col, $sheet, 'align' );}function bgColor($row, $col, $sheet = 0) {return $this->xfProperty ( $row, $col, $sheet, 'bgColor' );}function borderLeft($row, $col, $sheet = 0) {return $this->xfProperty ( $row, $col, $sheet, 'borderLeft' );}function borderRight($row, $col, $sheet = 0) {return $this->xfProperty ( $row, $col, $sheet, 'borderRight' );}function borderTop($row, $col, $sheet = 0) {return $this->xfProperty ( $row, $col, $sheet, 'borderTop' );}function borderBottom($row, $col, $sheet = 0) {return $this->xfProperty ( $row, $col, $sheet, 'borderBottom' );}function borderLeftColor($row, $col, $sheet = 0) {return $this->colors [$this->xfProperty ( $row, $col, $sheet, 'borderLeftColor' )];}function borderRightColor($row, $col, $sheet = 0) {return $this->colors [$this->xfProperty ( $row, $col, $sheet, 'borderRightColor' )];}function borderTopColor($row, $col, $sheet = 0) {return $this->colors [$this->xfProperty ( $row, $col, $sheet, 'borderTopColor' )];}function borderBottomColor($row, $col, $sheet = 0) {return $this->colors [$this->xfProperty ( $row, $col, $sheet, 'borderBottomColor' )];}// FONT PROPERTIES// ===============function fontRecord($row, $col, $sheet = 0) {$xfRecord = $this->xfRecord ( $row, $col, $sheet );if ($xfRecord != null) {$font = $xfRecord ['fontIndex'];if ($font != null) {return $this->fontRecords [$font];}}return null;}function fontProperty($row, $col, $sheet = 0, $prop) {$font = $this->fontRecord ( $row, $col, $sheet );if ($font != null) {return $font [$prop];}return false;}function fontIndex($row, $col, $sheet = 0) {return $this->xfProperty ( $row, $col, $sheet, 'fontIndex' );}function color($row, $col, $sheet = 0) {$formatColor = $this->formatColor ( $row, $col, $sheet );if ($formatColor != "") {return $formatColor;}$ci = $this->fontProperty ( $row, $col, $sheet, 'color' );return $this->rawColor ( $ci );}function rawColor($ci) {if (($ci != 0x7FFF) && ($ci != '')) {return $this->colors [$ci];}return "";}function bold($row, $col, $sheet = 0) {return $this->fontProperty ( $row, $col, $sheet, 'bold' );}function italic($row, $col, $sheet = 0) {return $this->fontProperty ( $row, $col, $sheet, 'italic' );}function underline($row, $col, $sheet = 0) {return $this->fontProperty ( $row, $col, $sheet, 'under' );}function height($row, $col, $sheet = 0) {return $this->fontProperty ( $row, $col, $sheet, 'height' );}function font($row, $col, $sheet = 0) {return $this->fontProperty ( $row, $col, $sheet, 'font' );}// DUMP AN HTML TABLE OF THE ENTIRE XLS DATA// =========================================function dump($row_numbers = false, $col_letters = false, $sheet = 0, $table_class = 'excel') {$out = "<table class=\"$table_class\" cellspacing=0>";if ($col_letters) {$out .= "<thead>\n\t<tr>";if ($row_numbers) {$out .= "\n\t\t<th> </th>";}for($i = 1; $i <= $this->colcount ( $sheet ); $i ++) {$style = "width:" . ($this->colwidth ( $i, $sheet ) * 1) . "px;";if ($this->colhidden ( $i, $sheet )) {$style .= "display:none;";}$out .= "\n\t\t<th style=\"$style\">" . strtoupper ( $this->colindexes [$i] ) . "</th>";}$out .= "</tr></thead>\n";}$out .= "<tbody>\n";for($row = 1; $row <= $this->rowcount ( $sheet ); $row ++) {$rowheight = $this->rowheight ( $row, $sheet );$style = "height:" . ($rowheight * (4 / 3)) . "px;";if ($this->rowhidden ( $row, $sheet )) {$style .= "display:none;";}$out .= "\n\t<tr style=\"$style\">";if ($row_numbers) {$out .= "\n\t\t<th>$row</th>";}for($col = 1; $col <= $this->colcount ( $sheet ); $col ++) {// Account for Rowspans/Colspans$rowspan = $this->rowspan ( $row, $col, $sheet );$colspan = $this->colspan ( $row, $col, $sheet );for($i = 0; $i < $rowspan; $i ++) {for($j = 0; $j < $colspan; $j ++) {if ($i > 0 || $j > 0) {$this->sheets [$sheet] ['cellsInfo'] [$row + $i] [$col + $j] ['dontprint'] = 1;}}}if (! $this->sheets [$sheet] ['cellsInfo'] [$row] [$col] ['dontprint']) {$style = $this->style ( $row, $col, $sheet );if ($this->colhidden ( $col, $sheet )) {$style .= "display:none;";}$out .= "\n\t\t<td style=\"$style\"" . ($colspan > 1 ? " colspan=$colspan" : "") . ($rowspan > 1 ? " rowspan=$rowspan" : "") . ">";$val = $this->val ( $row, $col, $sheet );if ($val == '') {$val = " ";} else {$val = htmlentities ( $val, ENT_COMPAT, $this->_defaultEncoding );$link = $this->hyperlink ( $row, $col, $sheet );if ($link != '') {$val = "<a href=\"$link\">$val</a>";}}$out .= "<nobr>" . nl2br ( $val ) . "</nobr>";$out .= "</td>";}}$out .= "</tr>\n";}$out .= "</tbody></table>";return $out;}// --------------// END PUBLIC APIvar $boundsheets = array ();var $formatRecords = array ();var $fontRecords = array ();var $xfRecords = array ();var $colInfo = array ();var $rowInfo = array ();var $sst = array ();var $sheets = array ();var $data;var $_ole;var $_defaultEncoding = "UTF-8";var $_defaultFormat = SPREADSHEET_EXCEL_READER_DEF_NUM_FORMAT;var $_columnsFormat = array ();var $_rowoffset = 1;var $_coloffset = 1;/*** List of default date formats used by Excel*/var $dateFormats = array (0xe => "m/d/Y", 0xf => "M-d-Y", 0x10 => "d-M", 0x11 => "M-Y", 0x12 => "h:i a", 0x13 => "h:i:s a", 0x14 => "H:i", 0x15 => "H:i:s", 0x16 => "d/m/Y H:i", 0x2d => "i:s", 0x2e => "H:i:s", 0x2f => "i:s.S" );/*** Default number formats used by Excel*/var $numberFormats = array (0x1 => "0", 0x2 => "0.00", 0x3 => "#,##0", 0x4 => "#,##0.00", 0x5 => "\$#,##0;(\$#,##0)", 0x6 => "\$#,##0;[Red](\$#,##0)", 0x7 => "\$#,##0.00;(\$#,##0.00)", 0x8 => "\$#,##0.00;[Red](\$#,##0.00)", 0x9 => "0%", 0xa => "0.00%", 0xb => "0.00E+00", 0x25 => "#,##0;(#,##0)", 0x26 => "#,##0;[Red](#,##0)", 0x27 => "#,##0.00;(#,##0.00)", 0x28 => "#,##0.00;[Red](#,##0.00)", 0x29 => "#,##0;(#,##0)", // Not exactly0x2a => "\$#,##0;(\$#,##0)", // Not exactly0x2b => "#,##0.00;(#,##0.00)", // Not exactly0x2c => "\$#,##0.00;(\$#,##0.00)", // Not exactly0x30 => "##0.0E+0" );var $colors = Array (0x00 => "#000000", 0x01 => "#FFFFFF", 0x02 => "#FF0000", 0x03 => "#00FF00", 0x04 => "#0000FF", 0x05 => "#FFFF00", 0x06 => "#FF00FF", 0x07 => "#00FFFF", 0x08 => "#000000", 0x09 => "#FFFFFF", 0x0A => "#FF0000", 0x0B => "#00FF00", 0x0C => "#0000FF", 0x0D => "#FFFF00", 0x0E => "#FF00FF", 0x0F => "#00FFFF", 0x10 => "#800000", 0x11 => "#008000", 0x12 => "#000080", 0x13 => "#808000", 0x14 => "#800080", 0x15 => "#008080", 0x16 => "#C0C0C0", 0x17 => "#808080", 0x18 => "#9999FF", 0x19 => "#993366", 0x1A => "#FFFFCC", 0x1B => "#CCFFFF", 0x1C => "#660066", 0x1D => "#FF8080", 0x1E => "#0066CC", 0x1F => "#CCCCFF", 0x20 => "#000080", 0x21 => "#FF00FF", 0x22 => "#FFFF00", 0x23 => "#00FFFF", 0x24 => "#800080", 0x25 => "#800000", 0x26 => "#008080", 0x27 => "#0000FF", 0x28 => "#00CCFF", 0x29 => "#CCFFFF", 0x2A => "#CCFFCC", 0x2B => "#FFFF99", 0x2C => "#99CCFF", 0x2D => "#FF99CC", 0x2E => "#CC99FF", 0x2F => "#FFCC99", 0x30 => "#3366FF", 0x31 => "#33CCCC", 0x32 => "#99CC00", 0x33 => "#FFCC00", 0x34 => "#FF9900", 0x35 => "#FF6600", 0x36 => "#666699", 0x37 => "#969696", 0x38 => "#003366", 0x39 => "#339966", 0x3A => "#003300", 0x3B => "#333300", 0x3C => "#993300", 0x3D => "#993366", 0x3E => "#333399", 0x3F => "#333333", 0x40 => "#000000", 0x41 => "#FFFFFF",0x43 => "#000000", 0x4D => "#000000", 0x4E => "#FFFFFF", 0x4F => "#000000", 0x50 => "#FFFFFF", 0x51 => "#000000",0x7FFF => "#000000" );var $lineStyles = array (0x00 => "", 0x01 => "Thin", 0x02 => "Medium", 0x03 => "Dashed", 0x04 => "Dotted", 0x05 => "Thick", 0x06 => "Double", 0x07 => "Hair", 0x08 => "Medium dashed", 0x09 => "Thin dash-dotted", 0x0A => "Medium dash-dotted", 0x0B => "Thin dash-dot-dotted", 0x0C => "Medium dash-dot-dotted", 0x0D => "Slanted medium dash-dotted" );var $lineStylesCss = array ("Thin" => "1px solid", "Medium" => "2px solid", "Dashed" => "1px dashed", "Dotted" => "1px dotted", "Thick" => "3px solid", "Double" => "double", "Hair" => "1px solid", "Medium dashed" => "2px dashed", "Thin dash-dotted" => "1px dashed", "Medium dash-dotted" => "2px dashed", "Thin dash-dot-dotted" => "1px dashed", "Medium dash-dot-dotted" => "2px dashed", "Slanted medium dash-dotte" => "2px dashed" );function read16bitstring($data, $start) {$len = 0;while ( ord ( $data [$start + $len] ) + ord ( $data [$start + $len + 1] ) > 0 )$len ++;return substr ( $data, $start, $len );}// ADDED by Matt Kruse for better formattingfunction _format_value($format, $num, $f) {// 49==TEXT format// http://code.google.com/p/php-excel-reader/issues/detail?id=7if ((! $f && $format == "%s") || ($f == 49) || ($format == "GENERAL")) {return array ('string' => $num, 'formatColor' => null );}// Custom pattern can be POSITIVE;NEGATIVE;ZERO// The "text" option as 4th parameter is not handled$parts = explode ( ";", $format );$pattern = $parts [0];// Negative patternif (count ( $parts ) > 2 && $num == 0) {$pattern = $parts [2];}// Zero patternif (count ( $parts ) > 1 && $num < 0) {$pattern = $parts [1];$num = abs ( $num );}$color = "";$matches = array ();$color_regex = "/^\[(BLACK|BLUE|CYAN|GREEN|MAGENTA|RED|WHITE|YELLOW)\]/i";if (preg_match ( $color_regex, $pattern, $matches )) {$color = strtolower ( $matches [1] );$pattern = preg_replace ( $color_regex, "", $pattern );}// In Excel formats, "_" is used to add spacing, which we can't do in HTML$pattern = preg_replace ( "/_./", "", $pattern );// Some non-number characters are escaped with \, which we don't need$pattern = preg_replace ( "/\\\/", "", $pattern );// Some non-number strings are quoted, so we'll get rid of the quotes$pattern = preg_replace ( "/\"/", "", $pattern );// TEMPORARY - Convert # to 0$pattern = preg_replace ( "/\#/", "0", $pattern );// Find out if we need comma formatting$has_commas = preg_match ( "/,/", $pattern );if ($has_commas) {$pattern = preg_replace ( "/,/", "", $pattern );}// Handle Percentagesif (preg_match ( "/\d(\%)([^\%]|$)/", $pattern, $matches )) {$num = $num * 100;$pattern = preg_replace ( "/(\d)(\%)([^\%]|$)/", "$1%$3", $pattern );}// Handle the number itself$number_regex = "/(\d+)(\.?)(\d*)/";if (preg_match ( $number_regex, $pattern, $matches )) {$left = $matches [1];$dec = $matches [2];$right = $matches [3];if ($has_commas) {$formatted = number_format ( $num, strlen ( $right ) );} else {$sprintf_pattern = "%1." . strlen ( $right ) . "f";$formatted = sprintf ( $sprintf_pattern, $num );}$pattern = preg_replace ( $number_regex, $formatted, $pattern );}return array ('string' => $pattern, 'formatColor' => $color );}/*** Constructor** Some basic initialisation*/function Spreadsheet_Excel_Reader($file = '', $store_extended_info = true, $outputEncoding = '') {$this->_ole = new OLERead ( );$this->setUTFEncoder ( 'iconv' );if ($outputEncoding != '') {$this->setOutputEncoding ( $outputEncoding );}for($i = 1; $i < 245; $i ++) {$name = strtolower ( ((($i - 1) / 26 >= 1) ? chr ( ($i - 1) / 26 + 64 ) : '') . chr ( ($i - 1) % 26 + 65 ) );$this->colnames [$name] = $i;$this->colindexes [$i] = $name;}$this->store_extended_info = $store_extended_info;if ($file != "") {$this->read ( $file );}}/*** Set the encoding method*/function setOutputEncoding($encoding) {$this->_defaultEncoding = $encoding;}/*** $encoder = 'iconv' or 'mb'* set iconv if you would like use 'iconv' for encode UTF-16LE to your encoding* set mb if you would like use 'mb_convert_encoding' for encode UTF-16LE to your encoding*/function setUTFEncoder($encoder = 'iconv') {$this->_encoderFunction = '';if ($encoder == 'iconv') {$this->_encoderFunction = function_exists ( 'iconv' ) ? 'iconv' : '';} elseif ($encoder == 'mb') {$this->_encoderFunction = function_exists ( 'mb_convert_encoding' ) ? 'mb_convert_encoding' : '';}}function setRowColOffset($iOffset) {$this->_rowoffset = $iOffset;$this->_coloffset = $iOffset;}/*** Set the default number format*/function setDefaultFormat($sFormat) {$this->_defaultFormat = $sFormat;}/*** Force a column to use a certain format*/function setColumnFormat($column, $sFormat) {$this->_columnsFormat [$column] = $sFormat;}/*** Read the spreadsheet file using OLE, then parse*/function read($sFileName) {$res = $this->_ole->read ( $sFileName );// oops, something goes wrong (Darko Miljanovic)if ($res === false) {// check error codeif ($this->_ole->error == 1) {// bad filedie ( 'The filename ' . $sFileName . ' is not readable' );}// check other error codes here (eg bad fileformat, etc...)}$this->data = $this->_ole->getWorkBook ();$this->_parse ();}/*** Parse a workbook** @access private* @return bool*/function _parse() {$pos = 0;$data = $this->data;$code = v ( $data, $pos );$length = v ( $data, $pos + 2 );$version = v ( $data, $pos + 4 );$substreamType = v ( $data, $pos + 6 );$this->version = $version;if (($version != SPREADSHEET_EXCEL_READER_BIFF8) && ($version != SPREADSHEET_EXCEL_READER_BIFF7)) {return false;}if ($substreamType != SPREADSHEET_EXCEL_READER_WORKBOOKGLOBALS) {return false;}$pos += $length + 4;$code = v ( $data, $pos );$length = v ( $data, $pos + 2 );while ( $code != SPREADSHEET_EXCEL_READER_TYPE_EOF ) {switch ($code) {case SPREADSHEET_EXCEL_READER_TYPE_SST :$spos = $pos + 4;$limitpos = $spos + $length;$uniqueStrings = $this->_GetInt4d ( $data, $spos + 4 );$spos += 8;for($i = 0; $i < $uniqueStrings; $i ++) {// Read in the number of charactersif ($spos == $limitpos) {$opcode = v ( $data, $spos );$conlength = v ( $data, $spos + 2 );if ($opcode != 0x3c) {return - 1;}$spos += 4;$limitpos = $spos + $conlength;}$numChars = ord ( $data [$spos] ) | (ord ( $data [$spos + 1] ) << 8);$spos += 2;$optionFlags = ord ( $data [$spos] );$spos ++;$asciiEncoding = (($optionFlags & 0x01) == 0);$extendedString = (($optionFlags & 0x04) != 0);// See if string contains formatting information$richString = (($optionFlags & 0x08) != 0);if ($richString) {// Read in the crun$formattingRuns = v ( $data, $spos );$spos += 2;}if ($extendedString) {// Read in cchExtRst$extendedRunLength = $this->_GetInt4d ( $data, $spos );$spos += 4;}$len = ($asciiEncoding) ? $numChars : $numChars * 2;if ($spos + $len < $limitpos) {$retstr = substr ( $data, $spos, $len );$spos += $len;} else {// found countinue$retstr = substr ( $data, $spos, $limitpos - $spos );$bytesRead = $limitpos - $spos;$charsLeft = $numChars - (($asciiEncoding) ? $bytesRead : ($bytesRead / 2));$spos = $limitpos;while ( $charsLeft > 0 ) {$opcode = v ( $data, $spos );$conlength = v ( $data, $spos + 2 );if ($opcode != 0x3c) {return - 1;}$spos += 4;$limitpos = $spos + $conlength;$option = ord ( $data [$spos] );$spos += 1;if ($asciiEncoding && ($option == 0)) {$len = min ( $charsLeft, $limitpos - $spos ); // min($charsLeft, $conlength);$retstr .= substr ( $data, $spos, $len );$charsLeft -= $len;$asciiEncoding = true;} elseif (! $asciiEncoding && ($option != 0)) {$len = min ( $charsLeft * 2, $limitpos - $spos ); // min($charsLeft, $conlength);$retstr .= substr ( $data, $spos, $len );$charsLeft -= $len / 2;$asciiEncoding = false;} elseif (! $asciiEncoding && ($option == 0)) {// Bummer - the string starts off as Unicode, but after the// continuation it is in straightforward ASCII encoding$len = min ( $charsLeft, $limitpos - $spos ); // min($charsLeft, $conlength);for($j = 0; $j < $len; $j ++) {$retstr .= $data [$spos + $j] . chr ( 0 );}$charsLeft -= $len;$asciiEncoding = false;} else {$newstr = '';for($j = 0; $j < strlen ( $retstr ); $j ++) {$newstr = $retstr [$j] . chr ( 0 );}$retstr = $newstr;$len = min ( $charsLeft * 2, $limitpos - $spos ); // min($charsLeft, $conlength);$retstr .= substr ( $data, $spos, $len );$charsLeft -= $len / 2;$asciiEncoding = false;}$spos += $len;}}if ($asciiEncoding)$retstr = preg_replace ( "/(.)/s", "$1\0", $retstr );$retstr = $this->_encodeUTF16 ( $retstr );if ($richString) {$spos += 4 * $formattingRuns;}// For extended strings, skip over the extended string dataif ($extendedString) {$spos += $extendedRunLength;}$this->sst [] = $retstr;}break;case SPREADSHEET_EXCEL_READER_TYPE_FILEPASS :return false;break;case SPREADSHEET_EXCEL_READER_TYPE_NAME :break;case SPREADSHEET_EXCEL_READER_TYPE_FORMAT :$indexCode = v ( $data, $pos + 4 );if ($version == SPREADSHEET_EXCEL_READER_BIFF8) {$numchars = v ( $data, $pos + 6 );if (ord ( $data [$pos + 8] ) == 0) {$formatString = substr ( $data, $pos + 9, $numchars );} else {$formatString = substr ( $data, $pos + 9, $numchars * 2 );}} else {$numchars = ord ( $data [$pos + 6] );$formatString = substr ( $data, $pos + 7, $numchars * 2 );}$this->formatRecords [$indexCode] = $formatString;break;case SPREADSHEET_EXCEL_READER_TYPE_FONT :$height = v ( $data, $pos + 4 );$option = v ( $data, $pos + 6 );$color = v ( $data, $pos + 8 );$weight = v ( $data, $pos + 10 );$under = ord ( $data [$pos + 14] );$font = "";// Font name$numchars = ord ( $data [$pos + 18] );if ((ord ( $data [$pos + 19] ) & 1) == 0) {$font = substr ( $data, $pos + 20, $numchars );} else {$font = substr ( $data, $pos + 20, $numchars * 2 );$font = $this->_encodeUTF16 ( $font );}$this->fontRecords [] = array ('height' => $height / 20, 'italic' => ! ! ($option & 2), 'color' => $color, 'under' => ! ($under == 0), 'bold' => ($weight == 700), 'font' => $font, 'raw' => $this->dumpHexData ( $data, $pos + 3, $length ) );break;case SPREADSHEET_EXCEL_READER_TYPE_PALETTE :$colors = ord ( $data [$pos + 4] ) | ord ( $data [$pos + 5] ) << 8;for($coli = 0; $coli < $colors; $coli ++) {$colOff = $pos + 2 + ($coli * 4);$colr = ord ( $data [$colOff] );$colg = ord ( $data [$colOff + 1] );$colb = ord ( $data [$colOff + 2] );$this->colors [0x07 + $coli] = '#' . $this->myhex ( $colr ) . $this->myhex ( $colg ) . $this->myhex ( $colb );}break;case SPREADSHEET_EXCEL_READER_TYPE_XF :$fontIndexCode = (ord ( $data [$pos + 4] ) | ord ( $data [$pos + 5] ) << 8) - 1;$fontIndexCode = max ( 0, $fontIndexCode );$indexCode = ord ( $data [$pos + 6] ) | ord ( $data [$pos + 7] ) << 8;$alignbit = ord ( $data [$pos + 10] ) & 3;$bgi = (ord ( $data [$pos + 22] ) | ord ( $data [$pos + 23] ) << 8) & 0x3FFF;$bgcolor = ($bgi & 0x7F);// $bgcolor = ($bgi & 0x3f80) >> 7;$align = "";if ($alignbit == 3) {$align = "right";}if ($alignbit == 2) {$align = "center";}$fillPattern = (ord ( $data [$pos + 21] ) & 0xFC) >> 2;if ($fillPattern == 0) {$bgcolor = "";}$xf = array ();$xf ['formatIndex'] = $indexCode;$xf ['align'] = $align;$xf ['fontIndex'] = $fontIndexCode;$xf ['bgColor'] = $bgcolor;$xf ['fillPattern'] = $fillPattern;$border = ord ( $data [$pos + 14] ) | (ord ( $data [$pos + 15] ) << 8) | (ord ( $data [$pos + 16] ) << 16) | (ord ( $data [$pos + 17] ) << 24);$xf ['borderLeft'] = $this->lineStyles [($border & 0xF)];$xf ['borderRight'] = $this->lineStyles [($border & 0xF0) >> 4];$xf ['borderTop'] = $this->lineStyles [($border & 0xF00) >> 8];$xf ['borderBottom'] = $this->lineStyles [($border & 0xF000) >> 12];$xf ['borderLeftColor'] = ($border & 0x7F0000) >> 16;$xf ['borderRightColor'] = ($border & 0x3F800000) >> 23;$border = (ord ( $data [$pos + 18] ) | ord ( $data [$pos + 19] ) << 8);$xf ['borderTopColor'] = ($border & 0x7F);$xf ['borderBottomColor'] = ($border & 0x3F80) >> 7;if (array_key_exists ( $indexCode, $this->dateFormats )) {$xf ['type'] = 'date';$xf ['format'] = $this->dateFormats [$indexCode];if ($align == '') {$xf ['align'] = 'right';}} elseif (array_key_exists ( $indexCode, $this->numberFormats )) {$xf ['type'] = 'number';$xf ['format'] = $this->numberFormats [$indexCode];if ($align == '') {$xf ['align'] = 'right';}} else {$isdate = FALSE;$formatstr = '';if ($indexCode > 0) {if (isset ( $this->formatRecords [$indexCode] ))$formatstr = $this->formatRecords [$indexCode];if ($formatstr != "") {$tmp = preg_replace ( "/\;.*/", "", $formatstr );$tmp = preg_replace ( "/^\[[^\]]*\]/", "", $tmp );if (preg_match ( "/[^hmsday\/\-:\s\\\,AMP]/i", $tmp ) == 0) { // found day and time format$isdate = TRUE;$formatstr = $tmp;$formatstr = str_replace ( array ('AM/PM', 'mmmm', 'mmm' ), array ('a', 'F', 'M' ), $formatstr );// m/mm are used for both minutes and months - oh SNAP!// This mess tries to fix for that.// 'm' == minutes only if following h/hh or preceding s/ss$formatstr = preg_replace ( "/(h:?)mm?/", "$1i", $formatstr );$formatstr = preg_replace ( "/mm?(:?s)/", "i$1", $formatstr );// A single 'm' = n in PHP$formatstr = preg_replace ( "/(^|[^m])m([^m]|$)/", '$1n$2', $formatstr );$formatstr = preg_replace ( "/(^|[^m])m([^m]|$)/", '$1n$2', $formatstr );// else it's months$formatstr = str_replace ( 'mm', 'm', $formatstr );// Convert single 'd' to 'j'$formatstr = preg_replace ( "/(^|[^d])d([^d]|$)/", '$1j$2', $formatstr );$formatstr = str_replace ( array ('dddd', 'ddd', 'dd', 'yyyy', 'yy', 'hh', 'h' ), array ('l', 'D', 'd', 'Y', 'y', 'H', 'g' ), $formatstr );$formatstr = preg_replace ( "/ss?/", 's', $formatstr );}}}if ($isdate) {$xf ['type'] = 'date';$xf ['format'] = $formatstr;if ($align == '') {$xf ['align'] = 'right';}} else {// If the format string has a 0 or # in it, we'll assume it's a numberif (preg_match ( "/[0#]/", $formatstr )) {$xf ['type'] = 'number';if ($align == '') {$xf ['align'] = 'right';}} else {$xf ['type'] = 'other';}$xf ['format'] = $formatstr;$xf ['code'] = $indexCode;}}$this->xfRecords [] = $xf;break;case SPREADSHEET_EXCEL_READER_TYPE_NINETEENFOUR :$this->nineteenFour = (ord ( $data [$pos + 4] ) == 1);break;case SPREADSHEET_EXCEL_READER_TYPE_BOUNDSHEET :$rec_offset = $this->_GetInt4d ( $data, $pos + 4 );$rec_typeFlag = ord ( $data [$pos + 8] );$rec_visibilityFlag = ord ( $data [$pos + 9] );$rec_length = ord ( $data [$pos + 10] );if ($version == SPREADSHEET_EXCEL_READER_BIFF8) {$chartype = ord ( $data [$pos + 11] );if ($chartype == 0) {$rec_name = substr ( $data, $pos + 12, $rec_length );} else {$rec_name = $this->_encodeUTF16 ( substr ( $data, $pos + 12, $rec_length * 2 ) );}} elseif ($version == SPREADSHEET_EXCEL_READER_BIFF7) {$rec_name = substr ( $data, $pos + 11, $rec_length );}$this->boundsheets [] = array ('name' => $rec_name, 'offset' => $rec_offset );break;}$pos += $length + 4;$code = ord ( $data [$pos] ) | ord ( $data [$pos + 1] ) << 8;$length = ord ( $data [$pos + 2] ) | ord ( $data [$pos + 3] ) << 8;}foreach ( $this->boundsheets as $key => $val ) {$this->sn = $key;$this->_parsesheet ( $val ['offset'] );}return true;}/*** Parse a worksheet*/function _parsesheet($spos) {$cont = true;$data = $this->data;// read BOF$code = ord ( $data [$spos] ) | ord ( $data [$spos + 1] ) << 8;$length = ord ( $data [$spos + 2] ) | ord ( $data [$spos + 3] ) << 8;$version = ord ( $data [$spos + 4] ) | ord ( $data [$spos + 5] ) << 8;$substreamType = ord ( $data [$spos + 6] ) | ord ( $data [$spos + 7] ) << 8;if (($version != SPREADSHEET_EXCEL_READER_BIFF8) && ($version != SPREADSHEET_EXCEL_READER_BIFF7)) {return - 1;}if ($substreamType != SPREADSHEET_EXCEL_READER_WORKSHEET) {return - 2;}$spos += $length + 4;while ( $cont ) {$lowcode = ord ( $data [$spos] );if ($lowcode == SPREADSHEET_EXCEL_READER_TYPE_EOF)break;$code = $lowcode | ord ( $data [$spos + 1] ) << 8;$length = ord ( $data [$spos + 2] ) | ord ( $data [$spos + 3] ) << 8;$spos += 4;$this->sheets [$this->sn] ['maxrow'] = $this->_rowoffset - 1;$this->sheets [$this->sn] ['maxcol'] = $this->_coloffset - 1;unset ( $this->rectype );switch ($code) {case SPREADSHEET_EXCEL_READER_TYPE_DIMENSION :if (! isset ( $this->numRows )) {if (($length == 10) || ($version == SPREADSHEET_EXCEL_READER_BIFF7)) {$this->sheets [$this->sn] ['numRows'] = ord ( $data [$spos + 2] ) | ord ( $data [$spos + 3] ) << 8;$this->sheets [$this->sn] ['numCols'] = ord ( $data [$spos + 6] ) | ord ( $data [$spos + 7] ) << 8;} else {$this->sheets [$this->sn] ['numRows'] = ord ( $data [$spos + 4] ) | ord ( $data [$spos + 5] ) << 8;$this->sheets [$this->sn] ['numCols'] = ord ( $data [$spos + 10] ) | ord ( $data [$spos + 11] ) << 8;}}break;case SPREADSHEET_EXCEL_READER_TYPE_MERGEDCELLS :$cellRanges = ord ( $data [$spos] ) | ord ( $data [$spos + 1] ) << 8;for($i = 0; $i < $cellRanges; $i ++) {$fr = ord ( $data [$spos + 8 * $i + 2] ) | ord ( $data [$spos + 8 * $i + 3] ) << 8;$lr = ord ( $data [$spos + 8 * $i + 4] ) | ord ( $data [$spos + 8 * $i + 5] ) << 8;$fc = ord ( $data [$spos + 8 * $i + 6] ) | ord ( $data [$spos + 8 * $i + 7] ) << 8;$lc = ord ( $data [$spos + 8 * $i + 8] ) | ord ( $data [$spos + 8 * $i + 9] ) << 8;if ($lr - $fr > 0) {$this->sheets [$this->sn] ['cellsInfo'] [$fr + 1] [$fc + 1] ['rowspan'] = $lr - $fr + 1;}if ($lc - $fc > 0) {$this->sheets [$this->sn] ['cellsInfo'] [$fr + 1] [$fc + 1] ['colspan'] = $lc - $fc + 1;}}break;case SPREADSHEET_EXCEL_READER_TYPE_RK :case SPREADSHEET_EXCEL_READER_TYPE_RK2 :$row = ord ( $data [$spos] ) | ord ( $data [$spos + 1] ) << 8;$column = ord ( $data [$spos + 2] ) | ord ( $data [$spos + 3] ) << 8;$rknum = $this->_GetInt4d ( $data, $spos + 6 );$numValue = $this->_GetIEEE754 ( $rknum );$info = $this->_getCellDetails ( $spos, $numValue, $column );$this->addcell ( $row, $column, $info ['string'], $info );break;case SPREADSHEET_EXCEL_READER_TYPE_LABELSST :$row = ord ( $data [$spos] ) | ord ( $data [$spos + 1] ) << 8;$column = ord ( $data [$spos + 2] ) | ord ( $data [$spos + 3] ) << 8;$xfindex = ord ( $data [$spos + 4] ) | ord ( $data [$spos + 5] ) << 8;$index = $this->_GetInt4d ( $data, $spos + 6 );$this->addcell ( $row, $column, $this->sst [$index], array ('xfIndex' => $xfindex ) );break;case SPREADSHEET_EXCEL_READER_TYPE_MULRK :$row = ord ( $data [$spos] ) | ord ( $data [$spos + 1] ) << 8;$colFirst = ord ( $data [$spos + 2] ) | ord ( $data [$spos + 3] ) << 8;$colLast = ord ( $data [$spos + $length - 2] ) | ord ( $data [$spos + $length - 1] ) << 8;$columns = $colLast - $colFirst + 1;$tmppos = $spos + 4;for($i = 0; $i < $columns; $i ++) {$numValue = $this->_GetIEEE754 ( $this->_GetInt4d ( $data, $tmppos + 2 ) );$info = $this->_getCellDetails ( $tmppos - 4, $numValue, $colFirst + $i + 1 );$tmppos += 6;$this->addcell ( $row, $colFirst + $i, $info ['string'], $info );}break;case SPREADSHEET_EXCEL_READER_TYPE_NUMBER :$row = ord ( $data [$spos] ) | ord ( $data [$spos + 1] ) << 8;$column = ord ( $data [$spos + 2] ) | ord ( $data [$spos + 3] ) << 8;$tmp = unpack ( "ddouble", substr ( $data, $spos + 6, 8 ) ); // It machine machine dependentif ($this->isDate ( $spos )) {$numValue = $tmp ['double'];} else {$numValue = $this->createNumber ( $spos );}$info = $this->_getCellDetails ( $spos, $numValue, $column );$this->addcell ( $row, $column, $info ['string'], $info );break;case SPREADSHEET_EXCEL_READER_TYPE_FORMULA :case SPREADSHEET_EXCEL_READER_TYPE_FORMULA2 :$row = ord ( $data [$spos] ) | ord ( $data [$spos + 1] ) << 8;$column = ord ( $data [$spos + 2] ) | ord ( $data [$spos + 3] ) << 8;if ((ord ( $data [$spos + 6] ) == 0) && (ord ( $data [$spos + 12] ) == 255) && (ord ( $data [$spos + 13] ) == 255)) {//String formula. Result follows in a STRING record// This row/col are stored to be referenced in that record// http://code.google.com/p/php-excel-reader/issues/detail?id=4$previousRow = $row;$previousCol = $column;} elseif ((ord ( $data [$spos + 6] ) == 1) && (ord ( $data [$spos + 12] ) == 255) && (ord ( $data [$spos + 13] ) == 255)) {//Boolean formula. Result is in +2; 0=false,1=true// http://code.google.com/p/php-excel-reader/issues/detail?id=4if (ord ( $this->data [$spos + 8] ) == 1) {$this->addcell ( $row, $column, "TRUE" );} else {$this->addcell ( $row, $column, "FALSE" );}} elseif ((ord ( $data [$spos + 6] ) == 2) && (ord ( $data [$spos + 12] ) == 255) && (ord ( $data [$spos + 13] ) == 255)) {//Error formula. Error code is in +2;} elseif ((ord ( $data [$spos + 6] ) == 3) && (ord ( $data [$spos + 12] ) == 255) && (ord ( $data [$spos + 13] ) == 255)) {//Formula result is a null string.$this->addcell ( $row, $column, '' );} else {// result is a number, so first 14 bytes are just like a _NUMBER record$tmp = unpack ( "ddouble", substr ( $data, $spos + 6, 8 ) ); // It machine machine dependentif ($this->isDate ( $spos )) {$numValue = $tmp ['double'];} else {$numValue = $this->createNumber ( $spos );}$info = $this->_getCellDetails ( $spos, $numValue, $column );$this->addcell ( $row, $column, $info ['string'], $info );}break;case SPREADSHEET_EXCEL_READER_TYPE_BOOLERR :$row = ord ( $data [$spos] ) | ord ( $data [$spos + 1] ) << 8;$column = ord ( $data [$spos + 2] ) | ord ( $data [$spos + 3] ) << 8;$string = ord ( $data [$spos + 6] );$this->addcell ( $row, $column, $string );break;case SPREADSHEET_EXCEL_READER_TYPE_STRING :// http://code.google.com/p/php-excel-reader/issues/detail?id=4if ($version == SPREADSHEET_EXCEL_READER_BIFF8) {// Unicode 16 string, like an SST record$xpos = $spos;$numChars = ord ( $data [$xpos] ) | (ord ( $data [$xpos + 1] ) << 8);$xpos += 2;$optionFlags = ord ( $data [$xpos] );$xpos ++;$asciiEncoding = (($optionFlags & 0x01) == 0);$extendedString = (($optionFlags & 0x04) != 0);// See if string contains formatting information$richString = (($optionFlags & 0x08) != 0);if ($richString) {// Read in the crun$formattingRuns = ord ( $data [$xpos] ) | (ord ( $data [$xpos + 1] ) << 8);$xpos += 2;}if ($extendedString) {// Read in cchExtRst$extendedRunLength = $this->_GetInt4d ( $this->data, $xpos );$xpos += 4;}$len = ($asciiEncoding) ? $numChars : $numChars * 2;$retstr = substr ( $data, $xpos, $len );$xpos += $len;if ($asciiEncoding)$retstr = preg_replace ( "/(.)/s", "$1\0", $retstr );$retstr = $this->_encodeUTF16 ( $retstr );} elseif ($version == SPREADSHEET_EXCEL_READER_BIFF7) {// Simple byte string$xpos = $spos;$numChars = ord ( $data [$xpos] ) | (ord ( $data [$xpos + 1] ) << 8);$xpos += 2;$retstr = substr ( $data, $xpos, $numChars );}$this->addcell ( $previousRow, $previousCol, $retstr );break;case SPREADSHEET_EXCEL_READER_TYPE_ROW :$row = ord ( $data [$spos] ) | ord ( $data [$spos + 1] ) << 8;$rowInfo = ord ( $data [$spos + 6] ) | ((ord ( $data [$spos + 7] ) << 8) & 0x7FFF);if (($rowInfo & 0x8000) > 0) {$rowHeight = - 1;} else {$rowHeight = $rowInfo & 0x7FFF;}$rowHidden = (ord ( $data [$spos + 12] ) & 0x20) >> 5;$this->rowInfo [$this->sn] [$row + 1] = Array ('height' => $rowHeight / 20, 'hidden' => $rowHidden );break;case SPREADSHEET_EXCEL_READER_TYPE_DBCELL :break;case SPREADSHEET_EXCEL_READER_TYPE_MULBLANK :$row = ord ( $data [$spos] ) | ord ( $data [$spos + 1] ) << 8;$column = ord ( $data [$spos + 2] ) | ord ( $data [$spos + 3] ) << 8;$cols = ($length / 2) - 3;for($c = 0; $c < $cols; $c ++) {$xfindex = ord ( $data [$spos + 4 + ($c * 2)] ) | ord ( $data [$spos + 5 + ($c * 2)] ) << 8;$this->addcell ( $row, $column + $c, "", array ('xfIndex' => $xfindex ) );}break;case SPREADSHEET_EXCEL_READER_TYPE_LABEL :$row = ord ( $data [$spos] ) | ord ( $data [$spos + 1] ) << 8;$column = ord ( $data [$spos + 2] ) | ord ( $data [$spos + 3] ) << 8;$this->addcell ( $row, $column, substr ( $data, $spos + 8, ord ( $data [$spos + 6] ) | ord ( $data [$spos + 7] ) << 8 ) );break;case SPREADSHEET_EXCEL_READER_TYPE_EOF :$cont = false;break;case SPREADSHEET_EXCEL_READER_TYPE_HYPER :// Only handle hyperlinks to a URL$row = ord ( $this->data [$spos] ) | ord ( $this->data [$spos + 1] ) << 8;$row2 = ord ( $this->data [$spos + 2] ) | ord ( $this->data [$spos + 3] ) << 8;$column = ord ( $this->data [$spos + 4] ) | ord ( $this->data [$spos + 5] ) << 8;$column2 = ord ( $this->data [$spos + 6] ) | ord ( $this->data [$spos + 7] ) << 8;$linkdata = Array ();$flags = ord ( $this->data [$spos + 28] );$udesc = "";$ulink = "";$uloc = 32;$linkdata ['flags'] = $flags;if (($flags & 1) > 0) { // is a type we understand// is there a description ?if (($flags & 0x14) == 0x14) { // has a description$uloc += 4;$descLen = ord ( $this->data [$spos + 32] ) | ord ( $this->data [$spos + 33] ) << 8;$udesc = substr ( $this->data, $spos + $uloc, $descLen * 2 );$uloc += 2 * $descLen;}$ulink = $this->read16bitstring ( $this->data, $spos + $uloc + 20 );if ($udesc == "") {$udesc = $ulink;}}$linkdata ['desc'] = $udesc;$linkdata ['link'] = $this->_encodeUTF16 ( $ulink );for($r = $row; $r <= $row2; $r ++) {for($c = $column; $c <= $column2; $c ++) {$this->sheets [$this->sn] ['cellsInfo'] [$r + 1] [$c + 1] ['hyperlink'] = $linkdata;}}break;case SPREADSHEET_EXCEL_READER_TYPE_DEFCOLWIDTH :$this->defaultColWidth = ord ( $data [$spos + 4] ) | ord ( $data [$spos + 5] ) << 8;break;case SPREADSHEET_EXCEL_READER_TYPE_STANDARDWIDTH :$this->standardColWidth = ord ( $data [$spos + 4] ) | ord ( $data [$spos + 5] ) << 8;break;case SPREADSHEET_EXCEL_READER_TYPE_COLINFO :$colfrom = ord ( $data [$spos + 0] ) | ord ( $data [$spos + 1] ) << 8;$colto = ord ( $data [$spos + 2] ) | ord ( $data [$spos + 3] ) << 8;$cw = ord ( $data [$spos + 4] ) | ord ( $data [$spos + 5] ) << 8;$cxf = ord ( $data [$spos + 6] ) | ord ( $data [$spos + 7] ) << 8;$co = ord ( $data [$spos + 8] );for($coli = $colfrom; $coli <= $colto; $coli ++) {$this->colInfo [$this->sn] [$coli + 1] = Array ('width' => $cw, 'xf' => $cxf, 'hidden' => ($co & 0x01), 'collapsed' => ($co & 0x1000) >> 12 );}break;default :break;}$spos += $length;}if (! isset ( $this->sheets [$this->sn] ['numRows'] ))$this->sheets [$this->sn] ['numRows'] = $this->sheets [$this->sn] ['maxrow'];if (! isset ( $this->sheets [$this->sn] ['numCols'] ))$this->sheets [$this->sn] ['numCols'] = $this->sheets [$this->sn] ['maxcol'];}function isDate($spos) {$xfindex = ord ( $this->data [$spos + 4] ) | ord ( $this->data [$spos + 5] ) << 8;return ($this->xfRecords [$xfindex] ['type'] == 'date');}// Get the details for a particular cellfunction _getCellDetails($spos, $numValue, $column) {$xfindex = ord ( $this->data [$spos + 4] ) | ord ( $this->data [$spos + 5] ) << 8;$xfrecord = $this->xfRecords [$xfindex];$type = $xfrecord ['type'];$format = $xfrecord ['format'];$formatIndex = $xfrecord ['formatIndex'];$fontIndex = $xfrecord ['fontIndex'];$formatColor = "";$rectype = '';$string = '';$raw = '';if (isset ( $this->_columnsFormat [$column + 1] )) {$format = $this->_columnsFormat [$column + 1];}if ($type == 'date') {// See http://groups.google.com/group/php-excel-reader-discuss/browse_frm/thread/9c3f9790d12d8e10/f2045c2369ac79de$rectype = 'date';// Convert numeric value into a date$utcDays = floor ( $numValue - ($this->nineteenFour ? SPREADSHEET_EXCEL_READER_UTCOFFSETDAYS1904 : SPREADSHEET_EXCEL_READER_UTCOFFSETDAYS) );$utcValue = ($utcDays) * SPREADSHEET_EXCEL_READER_MSINADAY;$dateinfo = gmgetdate ( $utcValue );$raw = $numValue;$fractionalDay = $numValue - floor ( $numValue ) + .0000001; // The .0000001 is to fix for php/excel fractional diffs$totalseconds = floor ( SPREADSHEET_EXCEL_READER_MSINADAY * $fractionalDay );$secs = $totalseconds % 60;$totalseconds -= $secs;$hours = floor ( $totalseconds / (60 * 60) );$mins = floor ( $totalseconds / 60 ) % 60;$string = date ( $format, mktime ( $hours, $mins, $secs, $dateinfo ["mon"], $dateinfo ["mday"], $dateinfo ["year"] ) );} else if ($type == 'number') {$rectype = 'number';$formatted = $this->_format_value ( $format, $numValue, $formatIndex );$string = $formatted ['string'];$formatColor = $formatted ['formatColor'];$raw = $numValue;} else {if ($format == "") {$format = $this->_defaultFormat;}$rectype = 'unknown';$formatted = $this->_format_value ( $format, $numValue, $formatIndex );$string = $formatted ['string'];$formatColor = $formatted ['formatColor'];$raw = $numValue;}return array ('string' => $string, 'raw' => $raw, 'rectype' => $rectype, 'format' => $format, 'formatIndex' => $formatIndex, 'fontIndex' => $fontIndex, 'formatColor' => $formatColor, 'xfIndex' => $xfindex );}function createNumber($spos) {$rknumhigh = $this->_GetInt4d ( $this->data, $spos + 10 );$rknumlow = $this->_GetInt4d ( $this->data, $spos + 6 );$sign = ($rknumhigh & 0x80000000) >> 31;$exp = ($rknumhigh & 0x7ff00000) >> 20;$mantissa = (0x100000 | ($rknumhigh & 0x000fffff));$mantissalow1 = ($rknumlow & 0x80000000) >> 31;$mantissalow2 = ($rknumlow & 0x7fffffff);$value = $mantissa / pow ( 2, (20 - ($exp - 1023)) );if ($mantissalow1 != 0)$value += 1 / pow ( 2, (21 - ($exp - 1023)) );$value += $mantissalow2 / pow ( 2, (52 - ($exp - 1023)) );if ($sign) {$value = - 1 * $value;}return $value;}function addcell($row, $col, $string, $info = null) {$this->sheets [$this->sn] ['maxrow'] = max ( $this->sheets [$this->sn] ['maxrow'], $row + $this->_rowoffset );$this->sheets [$this->sn] ['maxcol'] = max ( $this->sheets [$this->sn] ['maxcol'], $col + $this->_coloffset );$this->sheets [$this->sn] ['cells'] [$row + $this->_rowoffset] [$col + $this->_coloffset] = $string;if ($this->store_extended_info && $info) {foreach ( $info as $key => $val ) {$this->sheets [$this->sn] ['cellsInfo'] [$row + $this->_rowoffset] [$col + $this->_coloffset] [$key] = $val;}}}function _GetIEEE754($rknum) {if (($rknum & 0x02) != 0) {$value = $rknum >> 2;} else {//mmp// I got my info on IEEE754 encoding from// http://research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html// The RK format calls for using only the most significant 30 bits of the// 64 bit floating point value. The other 34 bits are assumed to be 0// So, we use the upper 30 bits of $rknum as follows...$sign = ($rknum & 0x80000000) >> 31;$exp = ($rknum & 0x7ff00000) >> 20;$mantissa = (0x100000 | ($rknum & 0x000ffffc));$value = $mantissa / pow ( 2, (20 - ($exp - 1023)) );if ($sign) {$value = - 1 * $value;}//end of changes by mmp}if (($rknum & 0x01) != 0) {$value /= 100;}return $value;}function _encodeUTF16($string) {$result = $string;if ($this->_defaultEncoding) {switch ($this->_encoderFunction) {case 'iconv' :$result = iconv ( 'UTF-16LE', $this->_defaultEncoding, $string );break;case 'mb_convert_encoding' :$result = mb_convert_encoding ( $string, $this->_defaultEncoding, 'UTF-16LE' );break;}}return $result;}function _GetInt4d($data, $pos) {$value = ord ( $data [$pos] ) | (ord ( $data [$pos + 1] ) << 8) | (ord ( $data [$pos + 2] ) << 16) | (ord ( $data [$pos + 3] ) << 24);if ($value >= 4294967294) {$value = - 2;}return $value;}}?>