| 452 | david | 1 | <?php
 | 
        
           |  |  | 2 | /**
 | 
        
           |  |  | 3 |  * A class for reading Microsoft Excel (97/2003) Spreadsheets.
 | 
        
           |  |  | 4 |  *
 | 
        
           |  |  | 5 |  * Version 2.21
 | 
        
           |  |  | 6 |  *
 | 
        
           |  |  | 7 |  * Enhanced and maintained by Matt Kruse < http://mattkruse.com >
 | 
        
           |  |  | 8 |  * Maintained at http://code.google.com/p/php-excel-reader/
 | 
        
           |  |  | 9 |  *
 | 
        
           |  |  | 10 |  * Format parsing and MUCH more contributed by:
 | 
        
           |  |  | 11 |  *    Matt Roxburgh < http://www.roxburgh.me.uk >
 | 
        
           |  |  | 12 |  *
 | 
        
           |  |  | 13 |  * DOCUMENTATION
 | 
        
           |  |  | 14 |  * =============
 | 
        
           |  |  | 15 |  *   http://code.google.com/p/php-excel-reader/wiki/Documentation
 | 
        
           |  |  | 16 |  *
 | 
        
           |  |  | 17 |  * CHANGE LOG
 | 
        
           |  |  | 18 |  * ==========
 | 
        
           |  |  | 19 |  *   http://code.google.com/p/php-excel-reader/wiki/ChangeHistory
 | 
        
           |  |  | 20 |  *
 | 
        
           |  |  | 21 |  * DISCUSSION/SUPPORT
 | 
        
           |  |  | 22 |  * ==================
 | 
        
           |  |  | 23 |  *   http://groups.google.com/group/php-excel-reader-discuss/topics
 | 
        
           |  |  | 24 |  *
 | 
        
           |  |  | 25 |  * --------------------------------------------------------------------------
 | 
        
           |  |  | 26 |  *
 | 
        
           |  |  | 27 |  * Originally developed by Vadim Tkachenko under the name PHPExcelReader.
 | 
        
           |  |  | 28 |  * (http://sourceforge.net/projects/phpexcelreader)
 | 
        
           |  |  | 29 |  * Based on the Java version by Andy Khan (http://www.andykhan.com).  Now
 | 
        
           |  |  | 30 |  * maintained by David Sanders.  Reads only Biff 7 and Biff 8 formats.
 | 
        
           |  |  | 31 |  *
 | 
        
           |  |  | 32 |  * PHP versions 4 and 5
 | 
        
           |  |  | 33 |  *
 | 
        
           |  |  | 34 |  * LICENSE: This source file is subject to version 3.0 of the PHP license
 | 
        
           |  |  | 35 |  * that is available through the world-wide-web at the following URI:
 | 
        
           |  |  | 36 |  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
 | 
        
           |  |  | 37 |  * the PHP License and are unable to obtain it through the web, please
 | 
        
           |  |  | 38 |  * send a note to license@php.net so we can mail you a copy immediately.
 | 
        
           |  |  | 39 |  *
 | 
        
           |  |  | 40 |  * @category   Spreadsheet
 | 
        
           |  |  | 41 |  * @package	Spreadsheet_Excel_Reader
 | 
        
           |  |  | 42 |  * @author	 Vadim Tkachenko <vt@apachephp.com>
 | 
        
           |  |  | 43 |  * @license	http://www.php.net/license/3_0.txt  PHP License 3.0
 | 
        
           |  |  | 44 |  * @version	CVS: $Id: reader.php 19 2007-03-13 12:42:41Z shangxiao $
 | 
        
           |  |  | 45 |  * @link	   http://pear.php.net/package/Spreadsheet_Excel_Reader
 | 
        
           |  |  | 46 |  * @see		OLE, Spreadsheet_Excel_Writer
 | 
        
           |  |  | 47 |  * --------------------------------------------------------------------------
 | 
        
           |  |  | 48 |  */
 | 
        
           |  |  | 49 |   | 
        
           |  |  | 50 |   | 
        
           |  |  | 51 | define('NUM_BIG_BLOCK_DEPOT_BLOCKS_POS', 0x2c);
 | 
        
           |  |  | 52 | define('SMALL_BLOCK_DEPOT_BLOCK_POS', 0x3c);
 | 
        
           |  |  | 53 | define('ROOT_START_BLOCK_POS', 0x30);
 | 
        
           |  |  | 54 | define('BIG_BLOCK_SIZE', 0x200);
 | 
        
           |  |  | 55 | define('SMALL_BLOCK_SIZE', 0x40);
 | 
        
           |  |  | 56 | define('EXTENSION_BLOCK_POS', 0x44);
 | 
        
           |  |  | 57 | define('NUM_EXTENSION_BLOCK_POS', 0x48);
 | 
        
           |  |  | 58 | define('PROPERTY_STORAGE_BLOCK_SIZE', 0x80);
 | 
        
           |  |  | 59 | define('BIG_BLOCK_DEPOT_BLOCKS_POS', 0x4c);
 | 
        
           |  |  | 60 | define('SMALL_BLOCK_THRESHOLD', 0x1000);
 | 
        
           |  |  | 61 | // property storage offsets
 | 
        
           |  |  | 62 | define('SIZE_OF_NAME_POS', 0x40);
 | 
        
           |  |  | 63 | define('TYPE_POS', 0x42);
 | 
        
           |  |  | 64 | define('START_BLOCK_POS', 0x74);
 | 
        
           |  |  | 65 | define('SIZE_POS', 0x78);
 | 
        
           |  |  | 66 | define('IDENTIFIER_OLE', pack("CCCCCCCC",0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1));
 | 
        
           |  |  | 67 |   | 
        
           |  |  | 68 |   | 
        
           |  |  | 69 | function GetInt4d($data, $pos) {
 | 
        
           |  |  | 70 | 	$value = ord($data[$pos]) | (ord($data[$pos+1])	<< 8) | (ord($data[$pos+2]) << 16) | (ord($data[$pos+3]) << 24);
 | 
        
           |  |  | 71 | 	if ($value>=4294967294) {
 | 
        
           |  |  | 72 | 		$value=-2;
 | 
        
           |  |  | 73 | 	}
 | 
        
           |  |  | 74 | 	return $value;
 | 
        
           |  |  | 75 | }
 | 
        
           |  |  | 76 |   | 
        
           |  |  | 77 | // http://uk.php.net/manual/en/function.getdate.php
 | 
        
           |  |  | 78 | function gmgetdate($ts = null){
 | 
        
           |  |  | 79 | 	$k = array('seconds','minutes','hours','mday','wday','mon','year','yday','weekday','month',0);
 | 
        
           | 996 | aurelien | 80 | 	return(array_comb($k,explode(":",gmdate('s:i:G:j:w:n:Y:z:l:F:U',is_null($ts)?time():$ts))));
 | 
        
           | 452 | david | 81 | 	}
 | 
        
           |  |  | 82 |   | 
        
           |  |  | 83 | // Added for PHP4 compatibility
 | 
        
           |  |  | 84 | function array_comb($array1, $array2) {
 | 
        
           |  |  | 85 | 	$out = array();
 | 
        
           |  |  | 86 | 	foreach ($array1 as $key => $value) {
 | 
        
           |  |  | 87 | 		$out[$value] = $array2[$key];
 | 
        
           |  |  | 88 | 	}
 | 
        
           |  |  | 89 | 	return $out;
 | 
        
           |  |  | 90 | }
 | 
        
           |  |  | 91 |   | 
        
           |  |  | 92 | function v($data,$pos) {
 | 
        
           |  |  | 93 | 	return ord($data[$pos]) | ord($data[$pos+1])<<8;
 | 
        
           |  |  | 94 | }
 | 
        
           |  |  | 95 |   | 
        
           |  |  | 96 | class OLERead {
 | 
        
           |  |  | 97 | 	var $data = '';
 | 
        
           |  |  | 98 | 	function OLERead(){	}
 | 
        
           |  |  | 99 |   | 
        
           |  |  | 100 | 	function read($sFileName){
 | 
        
           |  |  | 101 | 		// check if file exist and is readable (Darko Miljanovic)
 | 
        
           |  |  | 102 | 		if(!is_readable($sFileName)) {
 | 
        
           |  |  | 103 | 			$this->error = 1;
 | 
        
           |  |  | 104 | 			return false;
 | 
        
           |  |  | 105 | 		}
 | 
        
           |  |  | 106 | 		$this->data = @file_get_contents($sFileName);
 | 
        
           |  |  | 107 | 		if (!$this->data) {
 | 
        
           |  |  | 108 | 			$this->error = 1;
 | 
        
           |  |  | 109 | 			return false;
 | 
        
           |  |  | 110 |    		}
 | 
        
           |  |  | 111 |    		if (substr($this->data, 0, 8) != IDENTIFIER_OLE) {
 | 
        
           |  |  | 112 | 			$this->error = 1;
 | 
        
           |  |  | 113 | 			return false;
 | 
        
           |  |  | 114 |    		}
 | 
        
           |  |  | 115 | 		$this->numBigBlockDepotBlocks = GetInt4d($this->data, NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);
 | 
        
           |  |  | 116 | 		$this->sbdStartBlock = GetInt4d($this->data, SMALL_BLOCK_DEPOT_BLOCK_POS);
 | 
        
           |  |  | 117 | 		$this->rootStartBlock = GetInt4d($this->data, ROOT_START_BLOCK_POS);
 | 
        
           |  |  | 118 | 		$this->extensionBlock = GetInt4d($this->data, EXTENSION_BLOCK_POS);
 | 
        
           |  |  | 119 | 		$this->numExtensionBlocks = GetInt4d($this->data, NUM_EXTENSION_BLOCK_POS);
 | 
        
           |  |  | 120 |   | 
        
           |  |  | 121 | 		$bigBlockDepotBlocks = array();
 | 
        
           |  |  | 122 | 		$pos = BIG_BLOCK_DEPOT_BLOCKS_POS;
 | 
        
           |  |  | 123 | 		$bbdBlocks = $this->numBigBlockDepotBlocks;
 | 
        
           |  |  | 124 | 		if ($this->numExtensionBlocks != 0) {
 | 
        
           |  |  | 125 | 			$bbdBlocks = (BIG_BLOCK_SIZE - BIG_BLOCK_DEPOT_BLOCKS_POS)/4;
 | 
        
           |  |  | 126 | 		}
 | 
        
           |  |  | 127 |   | 
        
           |  |  | 128 | 		for ($i = 0; $i < $bbdBlocks; $i++) {
 | 
        
           |  |  | 129 | 			$bigBlockDepotBlocks[$i] = GetInt4d($this->data, $pos);
 | 
        
           |  |  | 130 | 			$pos += 4;
 | 
        
           |  |  | 131 | 		}
 | 
        
           |  |  | 132 |   | 
        
           |  |  | 133 |   | 
        
           |  |  | 134 | 		for ($j = 0; $j < $this->numExtensionBlocks; $j++) {
 | 
        
           |  |  | 135 | 			$pos = ($this->extensionBlock + 1) * BIG_BLOCK_SIZE;
 | 
        
           |  |  | 136 | 			$blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, BIG_BLOCK_SIZE / 4 - 1);
 | 
        
           |  |  | 137 |   | 
        
           |  |  | 138 | 			for ($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; $i++) {
 | 
        
           |  |  | 139 | 				$bigBlockDepotBlocks[$i] = GetInt4d($this->data, $pos);
 | 
        
           |  |  | 140 | 				$pos += 4;
 | 
        
           |  |  | 141 | 			}
 | 
        
           |  |  | 142 |   | 
        
           |  |  | 143 | 			$bbdBlocks += $blocksToRead;
 | 
        
           |  |  | 144 | 			if ($bbdBlocks < $this->numBigBlockDepotBlocks) {
 | 
        
           |  |  | 145 | 				$this->extensionBlock = GetInt4d($this->data, $pos);
 | 
        
           |  |  | 146 | 			}
 | 
        
           |  |  | 147 | 		}
 | 
        
           |  |  | 148 |   | 
        
           |  |  | 149 | 		// readBigBlockDepot
 | 
        
           |  |  | 150 | 		$pos = 0;
 | 
        
           |  |  | 151 | 		$index = 0;
 | 
        
           |  |  | 152 | 		$this->bigBlockChain = array();
 | 
        
           |  |  | 153 |   | 
        
           |  |  | 154 | 		for ($i = 0; $i < $this->numBigBlockDepotBlocks; $i++) {
 | 
        
           |  |  | 155 | 			$pos = ($bigBlockDepotBlocks[$i] + 1) * BIG_BLOCK_SIZE;
 | 
        
           |  |  | 156 | 			//echo "pos = $pos";
 | 
        
           |  |  | 157 | 			for ($j = 0 ; $j < BIG_BLOCK_SIZE / 4; $j++) {
 | 
        
           |  |  | 158 | 				$this->bigBlockChain[$index] = GetInt4d($this->data, $pos);
 | 
        
           |  |  | 159 | 				$pos += 4 ;
 | 
        
           |  |  | 160 | 				$index++;
 | 
        
           |  |  | 161 | 			}
 | 
        
           |  |  | 162 | 		}
 | 
        
           |  |  | 163 |   | 
        
           |  |  | 164 | 		// readSmallBlockDepot();
 | 
        
           |  |  | 165 | 		$pos = 0;
 | 
        
           |  |  | 166 | 		$index = 0;
 | 
        
           |  |  | 167 | 		$sbdBlock = $this->sbdStartBlock;
 | 
        
           |  |  | 168 | 		$this->smallBlockChain = array();
 | 
        
           |  |  | 169 |   | 
        
           |  |  | 170 | 		while ($sbdBlock != -2) {
 | 
        
           |  |  | 171 | 		  $pos = ($sbdBlock + 1) * BIG_BLOCK_SIZE;
 | 
        
           |  |  | 172 | 		  for ($j = 0; $j < BIG_BLOCK_SIZE / 4; $j++) {
 | 
        
           |  |  | 173 | 			$this->smallBlockChain[$index] = GetInt4d($this->data, $pos);
 | 
        
           |  |  | 174 | 			$pos += 4;
 | 
        
           |  |  | 175 | 			$index++;
 | 
        
           |  |  | 176 | 		  }
 | 
        
           |  |  | 177 | 		  $sbdBlock = $this->bigBlockChain[$sbdBlock];
 | 
        
           |  |  | 178 | 		}
 | 
        
           |  |  | 179 |   | 
        
           |  |  | 180 |   | 
        
           |  |  | 181 | 		// readData(rootStartBlock)
 | 
        
           |  |  | 182 | 		$block = $this->rootStartBlock;
 | 
        
           |  |  | 183 | 		$pos = 0;
 | 
        
           |  |  | 184 | 		$this->entry = $this->__readData($block);
 | 
        
           |  |  | 185 | 		$this->__readPropertySets();
 | 
        
           |  |  | 186 | 	}
 | 
        
           |  |  | 187 |   | 
        
           |  |  | 188 | 	function __readData($bl) {
 | 
        
           |  |  | 189 | 		$block = $bl;
 | 
        
           |  |  | 190 | 		$pos = 0;
 | 
        
           |  |  | 191 | 		$data = '';
 | 
        
           |  |  | 192 | 		while ($block != -2)  {
 | 
        
           |  |  | 193 | 			$pos = ($block + 1) * BIG_BLOCK_SIZE;
 | 
        
           |  |  | 194 | 			$data = $data.substr($this->data, $pos, BIG_BLOCK_SIZE);
 | 
        
           |  |  | 195 | 			$block = $this->bigBlockChain[$block];
 | 
        
           |  |  | 196 | 		}
 | 
        
           |  |  | 197 | 		return $data;
 | 
        
           |  |  | 198 | 	 }
 | 
        
           |  |  | 199 |   | 
        
           |  |  | 200 | 	function __readPropertySets(){
 | 
        
           |  |  | 201 | 		$offset = 0;
 | 
        
           |  |  | 202 | 		while ($offset < strlen($this->entry)) {
 | 
        
           |  |  | 203 | 			$d = substr($this->entry, $offset, PROPERTY_STORAGE_BLOCK_SIZE);
 | 
        
           |  |  | 204 | 			$nameSize = ord($d[SIZE_OF_NAME_POS]) | (ord($d[SIZE_OF_NAME_POS+1]) << 8);
 | 
        
           |  |  | 205 | 			$type = ord($d[TYPE_POS]);
 | 
        
           |  |  | 206 | 			$startBlock = GetInt4d($d, START_BLOCK_POS);
 | 
        
           |  |  | 207 | 			$size = GetInt4d($d, SIZE_POS);
 | 
        
           |  |  | 208 | 			$name = '';
 | 
        
           |  |  | 209 | 			for ($i = 0; $i < $nameSize ; $i++) {
 | 
        
           |  |  | 210 | 				$name .= $d[$i];
 | 
        
           |  |  | 211 | 			}
 | 
        
           |  |  | 212 | 			$name = str_replace("\x00", "", $name);
 | 
        
           |  |  | 213 | 			$this->props[] = array (
 | 
        
           |  |  | 214 | 				'name' => $name,
 | 
        
           |  |  | 215 | 				'type' => $type,
 | 
        
           |  |  | 216 | 				'startBlock' => $startBlock,
 | 
        
           |  |  | 217 | 				'size' => $size);
 | 
        
           |  |  | 218 | 			if ((strtolower($name) == "workbook") || ( strtolower($name) == "book")) {
 | 
        
           |  |  | 219 | 				$this->wrkbook = count($this->props) - 1;
 | 
        
           |  |  | 220 | 			}
 | 
        
           |  |  | 221 | 			if ($name == "Root Entry") {
 | 
        
           |  |  | 222 | 				$this->rootentry = count($this->props) - 1;
 | 
        
           |  |  | 223 | 			}
 | 
        
           |  |  | 224 | 			$offset += PROPERTY_STORAGE_BLOCK_SIZE;
 | 
        
           |  |  | 225 | 		}
 | 
        
           |  |  | 226 |   | 
        
           |  |  | 227 | 	}
 | 
        
           |  |  | 228 |   | 
        
           |  |  | 229 |   | 
        
           |  |  | 230 | 	function getWorkBook(){
 | 
        
           |  |  | 231 | 		if ($this->props[$this->wrkbook]['size'] < SMALL_BLOCK_THRESHOLD){
 | 
        
           |  |  | 232 | 			$rootdata = $this->__readData($this->props[$this->rootentry]['startBlock']);
 | 
        
           |  |  | 233 | 			$streamData = '';
 | 
        
           |  |  | 234 | 			$block = $this->props[$this->wrkbook]['startBlock'];
 | 
        
           |  |  | 235 | 			$pos = 0;
 | 
        
           |  |  | 236 | 			while ($block != -2) {
 | 
        
           |  |  | 237 | 	  			  $pos = $block * SMALL_BLOCK_SIZE;
 | 
        
           |  |  | 238 | 				  $streamData .= substr($rootdata, $pos, SMALL_BLOCK_SIZE);
 | 
        
           |  |  | 239 | 				  $block = $this->smallBlockChain[$block];
 | 
        
           |  |  | 240 | 			}
 | 
        
           |  |  | 241 | 			return $streamData;
 | 
        
           |  |  | 242 | 		}else{
 | 
        
           |  |  | 243 | 			$numBlocks = $this->props[$this->wrkbook]['size'] / BIG_BLOCK_SIZE;
 | 
        
           |  |  | 244 | 			if ($this->props[$this->wrkbook]['size'] % BIG_BLOCK_SIZE != 0) {
 | 
        
           |  |  | 245 | 				$numBlocks++;
 | 
        
           |  |  | 246 | 			}
 | 
        
           |  |  | 247 |   | 
        
           |  |  | 248 | 			if ($numBlocks == 0) return '';
 | 
        
           |  |  | 249 | 			$streamData = '';
 | 
        
           |  |  | 250 | 			$block = $this->props[$this->wrkbook]['startBlock'];
 | 
        
           |  |  | 251 | 			$pos = 0;
 | 
        
           |  |  | 252 | 			while ($block != -2) {
 | 
        
           |  |  | 253 | 			  $pos = ($block + 1) * BIG_BLOCK_SIZE;
 | 
        
           |  |  | 254 | 			  $streamData .= substr($this->data, $pos, BIG_BLOCK_SIZE);
 | 
        
           |  |  | 255 | 			  $block = $this->bigBlockChain[$block];
 | 
        
           |  |  | 256 | 			}
 | 
        
           |  |  | 257 | 			return $streamData;
 | 
        
           |  |  | 258 | 		}
 | 
        
           |  |  | 259 | 	}
 | 
        
           |  |  | 260 |   | 
        
           |  |  | 261 | }
 | 
        
           |  |  | 262 |   | 
        
           |  |  | 263 | define('SPREADSHEET_EXCEL_READER_BIFF8',			 0x600);
 | 
        
           |  |  | 264 | define('SPREADSHEET_EXCEL_READER_BIFF7',			 0x500);
 | 
        
           |  |  | 265 | define('SPREADSHEET_EXCEL_READER_WORKBOOKGLOBALS',   0x5);
 | 
        
           |  |  | 266 | define('SPREADSHEET_EXCEL_READER_WORKSHEET',		 0x10);
 | 
        
           |  |  | 267 | define('SPREADSHEET_EXCEL_READER_TYPE_BOF',		  0x809);
 | 
        
           |  |  | 268 | define('SPREADSHEET_EXCEL_READER_TYPE_EOF',		  0x0a);
 | 
        
           |  |  | 269 | define('SPREADSHEET_EXCEL_READER_TYPE_BOUNDSHEET',   0x85);
 | 
        
           |  |  | 270 | define('SPREADSHEET_EXCEL_READER_TYPE_DIMENSION',	0x200);
 | 
        
           |  |  | 271 | define('SPREADSHEET_EXCEL_READER_TYPE_ROW',		  0x208);
 | 
        
           |  |  | 272 | define('SPREADSHEET_EXCEL_READER_TYPE_DBCELL',	   0xd7);
 | 
        
           |  |  | 273 | define('SPREADSHEET_EXCEL_READER_TYPE_FILEPASS',	 0x2f);
 | 
        
           |  |  | 274 | define('SPREADSHEET_EXCEL_READER_TYPE_NOTE',		 0x1c);
 | 
        
           |  |  | 275 | define('SPREADSHEET_EXCEL_READER_TYPE_TXO',		  0x1b6);
 | 
        
           |  |  | 276 | define('SPREADSHEET_EXCEL_READER_TYPE_RK',		   0x7e);
 | 
        
           |  |  | 277 | define('SPREADSHEET_EXCEL_READER_TYPE_RK2',		  0x27e);
 | 
        
           |  |  | 278 | define('SPREADSHEET_EXCEL_READER_TYPE_MULRK',		0xbd);
 | 
        
           |  |  | 279 | define('SPREADSHEET_EXCEL_READER_TYPE_MULBLANK',	 0xbe);
 | 
        
           |  |  | 280 | define('SPREADSHEET_EXCEL_READER_TYPE_INDEX',		0x20b);
 | 
        
           |  |  | 281 | define('SPREADSHEET_EXCEL_READER_TYPE_SST',		  0xfc);
 | 
        
           |  |  | 282 | define('SPREADSHEET_EXCEL_READER_TYPE_EXTSST',	   0xff);
 | 
        
           |  |  | 283 | define('SPREADSHEET_EXCEL_READER_TYPE_CONTINUE',	 0x3c);
 | 
        
           |  |  | 284 | define('SPREADSHEET_EXCEL_READER_TYPE_LABEL',		0x204);
 | 
        
           |  |  | 285 | define('SPREADSHEET_EXCEL_READER_TYPE_LABELSST',	 0xfd);
 | 
        
           |  |  | 286 | define('SPREADSHEET_EXCEL_READER_TYPE_NUMBER',	   0x203);
 | 
        
           |  |  | 287 | define('SPREADSHEET_EXCEL_READER_TYPE_NAME',		 0x18);
 | 
        
           |  |  | 288 | define('SPREADSHEET_EXCEL_READER_TYPE_ARRAY',		0x221);
 | 
        
           |  |  | 289 | define('SPREADSHEET_EXCEL_READER_TYPE_STRING',	   0x207);
 | 
        
           |  |  | 290 | define('SPREADSHEET_EXCEL_READER_TYPE_FORMULA',	  0x406);
 | 
        
           |  |  | 291 | define('SPREADSHEET_EXCEL_READER_TYPE_FORMULA2',	 0x6);
 | 
        
           |  |  | 292 | define('SPREADSHEET_EXCEL_READER_TYPE_FORMAT',	   0x41e);
 | 
        
           |  |  | 293 | define('SPREADSHEET_EXCEL_READER_TYPE_XF',		   0xe0);
 | 
        
           |  |  | 294 | define('SPREADSHEET_EXCEL_READER_TYPE_BOOLERR',	  0x205);
 | 
        
           |  |  | 295 | define('SPREADSHEET_EXCEL_READER_TYPE_FONT',	  0x0031);
 | 
        
           |  |  | 296 | define('SPREADSHEET_EXCEL_READER_TYPE_PALETTE',	  0x0092);
 | 
        
           |  |  | 297 | define('SPREADSHEET_EXCEL_READER_TYPE_UNKNOWN',	  0xffff);
 | 
        
           |  |  | 298 | define('SPREADSHEET_EXCEL_READER_TYPE_NINETEENFOUR', 0x22);
 | 
        
           |  |  | 299 | define('SPREADSHEET_EXCEL_READER_TYPE_MERGEDCELLS',  0xE5);
 | 
        
           |  |  | 300 | define('SPREADSHEET_EXCEL_READER_UTCOFFSETDAYS' ,	25569);
 | 
        
           |  |  | 301 | define('SPREADSHEET_EXCEL_READER_UTCOFFSETDAYS1904', 24107);
 | 
        
           |  |  | 302 | define('SPREADSHEET_EXCEL_READER_MSINADAY',		  86400);
 | 
        
           |  |  | 303 | define('SPREADSHEET_EXCEL_READER_TYPE_HYPER',	     0x01b8);
 | 
        
           |  |  | 304 | define('SPREADSHEET_EXCEL_READER_TYPE_COLINFO',	     0x7d);
 | 
        
           |  |  | 305 | define('SPREADSHEET_EXCEL_READER_TYPE_DEFCOLWIDTH',  0x55);
 | 
        
           |  |  | 306 | define('SPREADSHEET_EXCEL_READER_TYPE_STANDARDWIDTH', 0x99);
 | 
        
           |  |  | 307 | define('SPREADSHEET_EXCEL_READER_DEF_NUM_FORMAT',	"%s");
 | 
        
           |  |  | 308 |   | 
        
           |  |  | 309 |   | 
        
           |  |  | 310 | /*
 | 
        
           |  |  | 311 | * Main Class
 | 
        
           |  |  | 312 | */
 | 
        
           |  |  | 313 | class Spreadsheet_Excel_Reader {
 | 
        
           |  |  | 314 |   | 
        
           |  |  | 315 | 	// MK: Added to make data retrieval easier
 | 
        
           |  |  | 316 | 	var $colnames = array();
 | 
        
           |  |  | 317 | 	var $colindexes = array();
 | 
        
           |  |  | 318 | 	var $standardColWidth = 0;
 | 
        
           |  |  | 319 | 	var $defaultColWidth = 0;
 | 
        
           |  |  | 320 |   | 
        
           |  |  | 321 | 	function myHex($d) {
 | 
        
           |  |  | 322 | 		if ($d < 16) return "0" . dechex($d);
 | 
        
           |  |  | 323 | 		return dechex($d);
 | 
        
           |  |  | 324 | 	}
 | 
        
           |  |  | 325 |   | 
        
           |  |  | 326 | 	function dumpHexData($data, $pos, $length) {
 | 
        
           |  |  | 327 | 		$info = "";
 | 
        
           |  |  | 328 | 		for ($i = 0; $i <= $length; $i++) {
 | 
        
           |  |  | 329 | 			$info .= ($i==0?"":" ") . $this->myHex(ord($data[$pos + $i])) . (ord($data[$pos + $i])>31? "[" . $data[$pos + $i] . "]":'');
 | 
        
           |  |  | 330 | 		}
 | 
        
           |  |  | 331 | 		return $info;
 | 
        
           |  |  | 332 | 	}
 | 
        
           |  |  | 333 |   | 
        
           |  |  | 334 | 	function getCol($col) {
 | 
        
           |  |  | 335 | 		if (is_string($col)) {
 | 
        
           |  |  | 336 | 			$col = strtolower($col);
 | 
        
           |  |  | 337 | 			if (array_key_exists($col,$this->colnames)) {
 | 
        
           |  |  | 338 | 				$col = $this->colnames[$col];
 | 
        
           |  |  | 339 | 			}
 | 
        
           |  |  | 340 | 		}
 | 
        
           |  |  | 341 | 		return $col;
 | 
        
           |  |  | 342 | 	}
 | 
        
           |  |  | 343 |   | 
        
           |  |  | 344 | 	// PUBLIC API FUNCTIONS
 | 
        
           |  |  | 345 | 	// --------------------
 | 
        
           |  |  | 346 |   | 
        
           |  |  | 347 | 	function val($row,$col,$sheet=0) {
 | 
        
           |  |  | 348 | 		$col = $this->getCol($col);
 | 
        
           |  |  | 349 | 		if (array_key_exists($row,$this->sheets[$sheet]['cells']) && array_key_exists($col,$this->sheets[$sheet]['cells'][$row])) {
 | 
        
           |  |  | 350 | 			return $this->sheets[$sheet]['cells'][$row][$col];
 | 
        
           |  |  | 351 | 		}
 | 
        
           |  |  | 352 | 		return "";
 | 
        
           |  |  | 353 | 	}
 | 
        
           |  |  | 354 | 	function value($row,$col,$sheet=0) {
 | 
        
           |  |  | 355 | 		return $this->val($row,$col,$sheet);
 | 
        
           |  |  | 356 | 	}
 | 
        
           |  |  | 357 | 	function info($row,$col,$type='',$sheet=0) {
 | 
        
           |  |  | 358 | 		$col = $this->getCol($col);
 | 
        
           |  |  | 359 | 		if (array_key_exists('cellsInfo',$this->sheets[$sheet])
 | 
        
           |  |  | 360 | 				&& array_key_exists($row,$this->sheets[$sheet]['cellsInfo'])
 | 
        
           |  |  | 361 | 				&& array_key_exists($col,$this->sheets[$sheet]['cellsInfo'][$row])
 | 
        
           |  |  | 362 | 				&& array_key_exists($type,$this->sheets[$sheet]['cellsInfo'][$row][$col])) {
 | 
        
           |  |  | 363 | 			return $this->sheets[$sheet]['cellsInfo'][$row][$col][$type];
 | 
        
           |  |  | 364 | 		}
 | 
        
           |  |  | 365 | 		return "";
 | 
        
           |  |  | 366 | 	}
 | 
        
           |  |  | 367 | 	function type($row,$col,$sheet=0) {
 | 
        
           |  |  | 368 | 		return $this->info($row,$col,'type',$sheet);
 | 
        
           |  |  | 369 | 	}
 | 
        
           |  |  | 370 | 	function raw($row,$col,$sheet=0) {
 | 
        
           |  |  | 371 | 		return $this->info($row,$col,'raw',$sheet);
 | 
        
           |  |  | 372 | 	}
 | 
        
           |  |  | 373 | 	function rowspan($row,$col,$sheet=0) {
 | 
        
           |  |  | 374 | 		$val = $this->info($row,$col,'rowspan',$sheet);
 | 
        
           |  |  | 375 | 		if ($val=="") { return 1; }
 | 
        
           |  |  | 376 | 		return $val;
 | 
        
           |  |  | 377 | 	}
 | 
        
           |  |  | 378 | 	function colspan($row,$col,$sheet=0) {
 | 
        
           |  |  | 379 | 		$val = $this->info($row,$col,'colspan',$sheet);
 | 
        
           |  |  | 380 | 		if ($val=="") { return 1; }
 | 
        
           |  |  | 381 | 		return $val;
 | 
        
           |  |  | 382 | 	}
 | 
        
           |  |  | 383 | 	function hyperlink($row,$col,$sheet=0) {
 | 
        
           |  |  | 384 | 		$link = $this->sheets[$sheet]['cellsInfo'][$row][$col]['hyperlink'];
 | 
        
           |  |  | 385 | 		if ($link) {
 | 
        
           |  |  | 386 | 			return $link['link'];
 | 
        
           |  |  | 387 | 		}
 | 
        
           |  |  | 388 | 		return '';
 | 
        
           |  |  | 389 | 	}
 | 
        
           |  |  | 390 | 	function rowcount($sheet=0) {
 | 
        
           |  |  | 391 | 		return $this->sheets[$sheet]['numRows'];
 | 
        
           |  |  | 392 | 	}
 | 
        
           |  |  | 393 | 	function colcount($sheet=0) {
 | 
        
           |  |  | 394 | 		return $this->sheets[$sheet]['numCols'];
 | 
        
           |  |  | 395 | 	}
 | 
        
           |  |  | 396 | 	function colwidth($col,$sheet=0) {
 | 
        
           |  |  | 397 | 		// Col width is actually the width of the number 0. So we have to estimate and come close
 | 
        
           |  |  | 398 | 		return $this->colInfo[$sheet][$col]['width']/9142*200;
 | 
        
           |  |  | 399 | 	}
 | 
        
           |  |  | 400 | 	function colhidden($col,$sheet=0) {
 | 
        
           |  |  | 401 | 		return !!$this->colInfo[$sheet][$col]['hidden'];
 | 
        
           |  |  | 402 | 	}
 | 
        
           |  |  | 403 | 	function rowheight($row,$sheet=0) {
 | 
        
           |  |  | 404 | 		return $this->rowInfo[$sheet][$row]['height'];
 | 
        
           |  |  | 405 | 	}
 | 
        
           |  |  | 406 | 	function rowhidden($row,$sheet=0) {
 | 
        
           |  |  | 407 | 		return !!$this->rowInfo[$sheet][$row]['hidden'];
 | 
        
           |  |  | 408 | 	}
 | 
        
           |  |  | 409 |   | 
        
           |  |  | 410 | 	// GET THE CSS FOR FORMATTING
 | 
        
           |  |  | 411 | 	// ==========================
 | 
        
           |  |  | 412 | 	function style($row,$col,$sheet=0,$properties='') {
 | 
        
           |  |  | 413 | 		$css = "";
 | 
        
           |  |  | 414 | 		$font=$this->font($row,$col,$sheet);
 | 
        
           |  |  | 415 | 		if ($font!="") {
 | 
        
           |  |  | 416 | 			$css .= "font-family:$font;";
 | 
        
           |  |  | 417 | 		}
 | 
        
           |  |  | 418 | 		$align=$this->align($row,$col,$sheet);
 | 
        
           |  |  | 419 | 		if ($align!="") {
 | 
        
           |  |  | 420 | 			$css .= "text-align:$align;";
 | 
        
           |  |  | 421 | 		}
 | 
        
           |  |  | 422 | 		$height=$this->height($row,$col,$sheet);
 | 
        
           |  |  | 423 | 		if ($height!="") {
 | 
        
           |  |  | 424 | 			$css .= "font-size:$height"."px;";
 | 
        
           |  |  | 425 | 		}
 | 
        
           |  |  | 426 | 		$bgcolor=$this->bgColor($row,$col,$sheet);
 | 
        
           |  |  | 427 | 		if ($bgcolor!="") {
 | 
        
           |  |  | 428 | 			$bgcolor = $this->colors[$bgcolor];
 | 
        
           |  |  | 429 | 			$css .= "background-color:$bgcolor;";
 | 
        
           |  |  | 430 | 		}
 | 
        
           |  |  | 431 | 		$color=$this->color($row,$col,$sheet);
 | 
        
           |  |  | 432 | 		if ($color!="") {
 | 
        
           |  |  | 433 | 			$css .= "color:$color;";
 | 
        
           |  |  | 434 | 		}
 | 
        
           |  |  | 435 | 		$bold=$this->bold($row,$col,$sheet);
 | 
        
           |  |  | 436 | 		if ($bold) {
 | 
        
           |  |  | 437 | 			$css .= "font-weight:bold;";
 | 
        
           |  |  | 438 | 		}
 | 
        
           |  |  | 439 | 		$italic=$this->italic($row,$col,$sheet);
 | 
        
           |  |  | 440 | 		if ($italic) {
 | 
        
           |  |  | 441 | 			$css .= "font-style:italic;";
 | 
        
           |  |  | 442 | 		}
 | 
        
           |  |  | 443 | 		$underline=$this->underline($row,$col,$sheet);
 | 
        
           |  |  | 444 | 		if ($underline) {
 | 
        
           |  |  | 445 | 			$css .= "text-decoration:underline;";
 | 
        
           |  |  | 446 | 		}
 | 
        
           |  |  | 447 | 		// Borders
 | 
        
           |  |  | 448 | 		$bLeft = $this->borderLeft($row,$col,$sheet);
 | 
        
           |  |  | 449 | 		$bRight = $this->borderRight($row,$col,$sheet);
 | 
        
           |  |  | 450 | 		$bTop = $this->borderTop($row,$col,$sheet);
 | 
        
           |  |  | 451 | 		$bBottom = $this->borderBottom($row,$col,$sheet);
 | 
        
           |  |  | 452 | 		$bLeftCol = $this->borderLeftColor($row,$col,$sheet);
 | 
        
           |  |  | 453 | 		$bRightCol = $this->borderRightColor($row,$col,$sheet);
 | 
        
           |  |  | 454 | 		$bTopCol = $this->borderTopColor($row,$col,$sheet);
 | 
        
           |  |  | 455 | 		$bBottomCol = $this->borderBottomColor($row,$col,$sheet);
 | 
        
           |  |  | 456 | 		// Try to output the minimal required style
 | 
        
           |  |  | 457 | 		if ($bLeft!="" && $bLeft==$bRight && $bRight==$bTop && $bTop==$bBottom) {
 | 
        
           |  |  | 458 | 			$css .= "border:" . $this->lineStylesCss[$bLeft] .";";
 | 
        
           |  |  | 459 | 		}
 | 
        
           |  |  | 460 | 		else {
 | 
        
           |  |  | 461 | 			if ($bLeft!="") { $css .= "border-left:" . $this->lineStylesCss[$bLeft] .";"; }
 | 
        
           |  |  | 462 | 			if ($bRight!="") { $css .= "border-right:" . $this->lineStylesCss[$bRight] .";"; }
 | 
        
           |  |  | 463 | 			if ($bTop!="") { $css .= "border-top:" . $this->lineStylesCss[$bTop] .";"; }
 | 
        
           |  |  | 464 | 			if ($bBottom!="") { $css .= "border-bottom:" . $this->lineStylesCss[$bBottom] .";"; }
 | 
        
           |  |  | 465 | 		}
 | 
        
           |  |  | 466 | 		// Only output border colors if there is an actual border specified
 | 
        
           |  |  | 467 | 		if ($bLeft!="" && $bLeftCol!="") { $css .= "border-left-color:" . $bLeftCol .";"; }
 | 
        
           |  |  | 468 | 		if ($bRight!="" && $bRightCol!="") { $css .= "border-right-color:" . $bRightCol .";"; }
 | 
        
           |  |  | 469 | 		if ($bTop!="" && $bTopCol!="") { $css .= "border-top-color:" . $bTopCol . ";"; }
 | 
        
           |  |  | 470 | 		if ($bBottom!="" && $bBottomCol!="") { $css .= "border-bottom-color:" . $bBottomCol .";"; }
 | 
        
           |  |  | 471 |   | 
        
           |  |  | 472 | 		return $css;
 | 
        
           |  |  | 473 | 	}
 | 
        
           |  |  | 474 |   | 
        
           |  |  | 475 | 	// FORMAT PROPERTIES
 | 
        
           |  |  | 476 | 	// =================
 | 
        
           |  |  | 477 | 	function format($row,$col,$sheet=0) {
 | 
        
           |  |  | 478 | 		return $this->info($row,$col,'format',$sheet);
 | 
        
           |  |  | 479 | 	}
 | 
        
           |  |  | 480 | 	function formatIndex($row,$col,$sheet=0) {
 | 
        
           |  |  | 481 | 		return $this->info($row,$col,'formatIndex',$sheet);
 | 
        
           |  |  | 482 | 	}
 | 
        
           |  |  | 483 | 	function formatColor($row,$col,$sheet=0) {
 | 
        
           |  |  | 484 | 		return $this->info($row,$col,'formatColor',$sheet);
 | 
        
           |  |  | 485 | 	}
 | 
        
           |  |  | 486 |   | 
        
           |  |  | 487 | 	// CELL (XF) PROPERTIES
 | 
        
           |  |  | 488 | 	// ====================
 | 
        
           |  |  | 489 | 	function xfRecord($row,$col,$sheet=0) {
 | 
        
           |  |  | 490 | 		$xfIndex = $this->info($row,$col,'xfIndex',$sheet);
 | 
        
           |  |  | 491 | 		if ($xfIndex!="") {
 | 
        
           |  |  | 492 | 			return $this->xfRecords[$xfIndex];
 | 
        
           |  |  | 493 | 		}
 | 
        
           |  |  | 494 | 		return null;
 | 
        
           |  |  | 495 | 	}
 | 
        
           |  |  | 496 | 	function xfProperty($row,$col,$sheet,$prop) {
 | 
        
           |  |  | 497 | 		$xfRecord = $this->xfRecord($row,$col,$sheet);
 | 
        
           |  |  | 498 | 		if ($xfRecord!=null) {
 | 
        
           |  |  | 499 | 			return $xfRecord[$prop];
 | 
        
           |  |  | 500 | 		}
 | 
        
           |  |  | 501 | 		return "";
 | 
        
           |  |  | 502 | 	}
 | 
        
           |  |  | 503 | 	function align($row,$col,$sheet=0) {
 | 
        
           |  |  | 504 | 		return $this->xfProperty($row,$col,$sheet,'align');
 | 
        
           |  |  | 505 | 	}
 | 
        
           |  |  | 506 | 	function bgColor($row,$col,$sheet=0) {
 | 
        
           |  |  | 507 | 		return $this->xfProperty($row,$col,$sheet,'bgColor');
 | 
        
           |  |  | 508 | 	}
 | 
        
           |  |  | 509 | 	function borderLeft($row,$col,$sheet=0) {
 | 
        
           |  |  | 510 | 		return $this->xfProperty($row,$col,$sheet,'borderLeft');
 | 
        
           |  |  | 511 | 	}
 | 
        
           |  |  | 512 | 	function borderRight($row,$col,$sheet=0) {
 | 
        
           |  |  | 513 | 		return $this->xfProperty($row,$col,$sheet,'borderRight');
 | 
        
           |  |  | 514 | 	}
 | 
        
           |  |  | 515 | 	function borderTop($row,$col,$sheet=0) {
 | 
        
           |  |  | 516 | 		return $this->xfProperty($row,$col,$sheet,'borderTop');
 | 
        
           |  |  | 517 | 	}
 | 
        
           |  |  | 518 | 	function borderBottom($row,$col,$sheet=0) {
 | 
        
           |  |  | 519 | 		return $this->xfProperty($row,$col,$sheet,'borderBottom');
 | 
        
           |  |  | 520 | 	}
 | 
        
           |  |  | 521 | 	function borderLeftColor($row,$col,$sheet=0) {
 | 
        
           |  |  | 522 | 		return $this->colors[$this->xfProperty($row,$col,$sheet,'borderLeftColor')];
 | 
        
           |  |  | 523 | 	}
 | 
        
           |  |  | 524 | 	function borderRightColor($row,$col,$sheet=0) {
 | 
        
           |  |  | 525 | 		return $this->colors[$this->xfProperty($row,$col,$sheet,'borderRightColor')];
 | 
        
           |  |  | 526 | 	}
 | 
        
           |  |  | 527 | 	function borderTopColor($row,$col,$sheet=0) {
 | 
        
           |  |  | 528 | 		return $this->colors[$this->xfProperty($row,$col,$sheet,'borderTopColor')];
 | 
        
           |  |  | 529 | 	}
 | 
        
           |  |  | 530 | 	function borderBottomColor($row,$col,$sheet=0) {
 | 
        
           |  |  | 531 | 		return $this->colors[$this->xfProperty($row,$col,$sheet,'borderBottomColor')];
 | 
        
           |  |  | 532 | 	}
 | 
        
           |  |  | 533 |   | 
        
           |  |  | 534 | 	// FONT PROPERTIES
 | 
        
           |  |  | 535 | 	// ===============
 | 
        
           |  |  | 536 | 	function fontRecord($row,$col,$sheet=0) {
 | 
        
           |  |  | 537 | 	    $xfRecord = $this->xfRecord($row,$col,$sheet);
 | 
        
           |  |  | 538 | 		if ($xfRecord!=null) {
 | 
        
           |  |  | 539 | 			$font = $xfRecord['fontIndex'];
 | 
        
           |  |  | 540 | 			if ($font!=null) {
 | 
        
           |  |  | 541 | 				return $this->fontRecords[$font];
 | 
        
           |  |  | 542 | 			}
 | 
        
           |  |  | 543 | 		}
 | 
        
           |  |  | 544 | 		return null;
 | 
        
           |  |  | 545 | 	}
 | 
        
           |  |  | 546 | 	function fontProperty($row,$col,$sheet=0,$prop) {
 | 
        
           |  |  | 547 | 		$font = $this->fontRecord($row,$col,$sheet);
 | 
        
           |  |  | 548 | 		if ($font!=null) {
 | 
        
           |  |  | 549 | 			return $font[$prop];
 | 
        
           |  |  | 550 | 		}
 | 
        
           |  |  | 551 | 		return false;
 | 
        
           |  |  | 552 | 	}
 | 
        
           |  |  | 553 | 	function fontIndex($row,$col,$sheet=0) {
 | 
        
           |  |  | 554 | 		return $this->xfProperty($row,$col,$sheet,'fontIndex');
 | 
        
           |  |  | 555 | 	}
 | 
        
           |  |  | 556 | 	function color($row,$col,$sheet=0) {
 | 
        
           |  |  | 557 | 		$formatColor = $this->formatColor($row,$col,$sheet);
 | 
        
           |  |  | 558 | 		if ($formatColor!="") {
 | 
        
           |  |  | 559 | 			return $formatColor;
 | 
        
           |  |  | 560 | 		}
 | 
        
           |  |  | 561 | 		$ci = $this->fontProperty($row,$col,$sheet,'color');
 | 
        
           |  |  | 562 |                 return $this->rawColor($ci);
 | 
        
           |  |  | 563 |         }
 | 
        
           |  |  | 564 |         function rawColor($ci) {
 | 
        
           |  |  | 565 | 		if (($ci <> 0x7FFF) && ($ci <> '')) {
 | 
        
           |  |  | 566 | 			return $this->colors[$ci];
 | 
        
           |  |  | 567 | 		}
 | 
        
           |  |  | 568 | 		return "";
 | 
        
           |  |  | 569 | 	}
 | 
        
           |  |  | 570 | 	function bold($row,$col,$sheet=0) {
 | 
        
           |  |  | 571 | 		return $this->fontProperty($row,$col,$sheet,'bold');
 | 
        
           |  |  | 572 | 	}
 | 
        
           |  |  | 573 | 	function italic($row,$col,$sheet=0) {
 | 
        
           |  |  | 574 | 		return $this->fontProperty($row,$col,$sheet,'italic');
 | 
        
           |  |  | 575 | 	}
 | 
        
           |  |  | 576 | 	function underline($row,$col,$sheet=0) {
 | 
        
           |  |  | 577 | 		return $this->fontProperty($row,$col,$sheet,'under');
 | 
        
           |  |  | 578 | 	}
 | 
        
           |  |  | 579 | 	function height($row,$col,$sheet=0) {
 | 
        
           |  |  | 580 | 		return $this->fontProperty($row,$col,$sheet,'height');
 | 
        
           |  |  | 581 | 	}
 | 
        
           |  |  | 582 | 	function font($row,$col,$sheet=0) {
 | 
        
           |  |  | 583 | 		return $this->fontProperty($row,$col,$sheet,'font');
 | 
        
           |  |  | 584 | 	}
 | 
        
           |  |  | 585 |   | 
        
           |  |  | 586 | 	// DUMP AN HTML TABLE OF THE ENTIRE XLS DATA
 | 
        
           |  |  | 587 | 	// =========================================
 | 
        
           |  |  | 588 | 	function dump($row_numbers=false,$col_letters=false,$sheet=0,$table_class='excel') {
 | 
        
           |  |  | 589 | 		$out = "<table class=\"$table_class\" cellspacing=0>";
 | 
        
           |  |  | 590 | 		if ($col_letters) {
 | 
        
           |  |  | 591 | 			$out .= "<thead>\n\t<tr>";
 | 
        
           |  |  | 592 | 			if ($row_numbers) {
 | 
        
           |  |  | 593 | 				$out .= "\n\t\t<th> </th>";
 | 
        
           |  |  | 594 | 			}
 | 
        
           |  |  | 595 | 			for($i=1;$i<=$this->colcount($sheet);$i++) {
 | 
        
           |  |  | 596 | 				$style = "width:" . ($this->colwidth($i,$sheet)*1) . "px;";
 | 
        
           |  |  | 597 | 				if ($this->colhidden($i,$sheet)) {
 | 
        
           |  |  | 598 | 					$style .= "display:none;";
 | 
        
           |  |  | 599 | 				}
 | 
        
           |  |  | 600 | 				$out .= "\n\t\t<th style=\"$style\">" . strtoupper($this->colindexes[$i]) . "</th>";
 | 
        
           |  |  | 601 | 			}
 | 
        
           |  |  | 602 | 			$out .= "</tr></thead>\n";
 | 
        
           |  |  | 603 | 		}
 | 
        
           |  |  | 604 |   | 
        
           |  |  | 605 | 		$out .= "<tbody>\n";
 | 
        
           |  |  | 606 | 		for($row=1;$row<=$this->rowcount($sheet);$row++) {
 | 
        
           |  |  | 607 | 			$rowheight = $this->rowheight($row,$sheet);
 | 
        
           |  |  | 608 | 			$style = "height:" . ($rowheight*(4/3)) . "px;";
 | 
        
           |  |  | 609 | 			if ($this->rowhidden($row,$sheet)) {
 | 
        
           |  |  | 610 | 				$style .= "display:none;";
 | 
        
           |  |  | 611 | 			}
 | 
        
           |  |  | 612 | 			$out .= "\n\t<tr style=\"$style\">";
 | 
        
           |  |  | 613 | 			if ($row_numbers) {
 | 
        
           |  |  | 614 | 				$out .= "\n\t\t<th>$row</th>";
 | 
        
           |  |  | 615 | 			}
 | 
        
           |  |  | 616 | 			for($col=1;$col<=$this->colcount($sheet);$col++) {
 | 
        
           |  |  | 617 | 				// Account for Rowspans/Colspans
 | 
        
           |  |  | 618 | 				$rowspan = $this->rowspan($row,$col,$sheet);
 | 
        
           |  |  | 619 | 				$colspan = $this->colspan($row,$col,$sheet);
 | 
        
           |  |  | 620 | 				for($i=0;$i<$rowspan;$i++) {
 | 
        
           |  |  | 621 | 					for($j=0;$j<$colspan;$j++) {
 | 
        
           |  |  | 622 | 						if ($i>0 || $j>0) {
 | 
        
           |  |  | 623 | 							$this->sheets[$sheet]['cellsInfo'][$row+$i][$col+$j]['dontprint']=1;
 | 
        
           |  |  | 624 | 						}
 | 
        
           |  |  | 625 | 					}
 | 
        
           |  |  | 626 | 				}
 | 
        
           |  |  | 627 | 				if(!$this->sheets[$sheet]['cellsInfo'][$row][$col]['dontprint']) {
 | 
        
           |  |  | 628 | 					$style = $this->style($row,$col,$sheet);
 | 
        
           |  |  | 629 | 					if ($this->colhidden($col,$sheet)) {
 | 
        
           |  |  | 630 | 						$style .= "display:none;";
 | 
        
           |  |  | 631 | 					}
 | 
        
           |  |  | 632 | 					$out .= "\n\t\t<td style=\"$style\"" . ($colspan > 1?" colspan=$colspan":"") . ($rowspan > 1?" rowspan=$rowspan":"") . ">";
 | 
        
           |  |  | 633 | 					$val = $this->val($row,$col,$sheet);
 | 
        
           |  |  | 634 | 					if ($val=='') { $val=" "; }
 | 
        
           |  |  | 635 | 					else {
 | 
        
           |  |  | 636 | 						$val = htmlentities($val);
 | 
        
           |  |  | 637 | 						$link = $this->hyperlink($row,$col,$sheet);
 | 
        
           |  |  | 638 | 						if ($link!='') {
 | 
        
           |  |  | 639 | 							$val = "<a href=\"$link\">$val</a>";
 | 
        
           |  |  | 640 | 						}
 | 
        
           |  |  | 641 | 					}
 | 
        
           |  |  | 642 | 					$out .= "<nobr>".nl2br($val)."</nobr>";
 | 
        
           |  |  | 643 | 					$out .= "</td>";
 | 
        
           |  |  | 644 | 				}
 | 
        
           |  |  | 645 | 			}
 | 
        
           |  |  | 646 | 			$out .= "</tr>\n";
 | 
        
           |  |  | 647 | 		}
 | 
        
           |  |  | 648 | 		$out .= "</tbody></table>";
 | 
        
           |  |  | 649 | 		return $out;
 | 
        
           |  |  | 650 | 	}
 | 
        
           |  |  | 651 |   | 
        
           |  |  | 652 | 	// --------------
 | 
        
           |  |  | 653 | 	// END PUBLIC API
 | 
        
           |  |  | 654 |   | 
        
           |  |  | 655 |   | 
        
           |  |  | 656 | 	var $boundsheets = array();
 | 
        
           |  |  | 657 | 	var $formatRecords = array();
 | 
        
           |  |  | 658 | 	var $fontRecords = array();
 | 
        
           |  |  | 659 | 	var $xfRecords = array();
 | 
        
           |  |  | 660 | 	var $colInfo = array();
 | 
        
           |  |  | 661 |    	var $rowInfo = array();
 | 
        
           |  |  | 662 |   | 
        
           |  |  | 663 | 	var $sst = array();
 | 
        
           |  |  | 664 | 	var $sheets = array();
 | 
        
           |  |  | 665 |   | 
        
           |  |  | 666 | 	var $data;
 | 
        
           |  |  | 667 | 	var $_ole;
 | 
        
           |  |  | 668 | 	var $_defaultEncoding = "UTF-8";
 | 
        
           |  |  | 669 | 	var $_defaultFormat = SPREADSHEET_EXCEL_READER_DEF_NUM_FORMAT;
 | 
        
           |  |  | 670 | 	var $_columnsFormat = array();
 | 
        
           |  |  | 671 | 	var $_rowoffset = 1;
 | 
        
           |  |  | 672 | 	var $_coloffset = 1;
 | 
        
           |  |  | 673 |   | 
        
           |  |  | 674 | 	/**
 | 
        
           |  |  | 675 | 	 * List of default date formats used by Excel
 | 
        
           |  |  | 676 | 	 */
 | 
        
           |  |  | 677 | 	var $dateFormats = array (
 | 
        
           |  |  | 678 | 		0xe => "m/d/Y",
 | 
        
           |  |  | 679 | 		0xf => "M-d-Y",
 | 
        
           |  |  | 680 | 		0x10 => "d-M",
 | 
        
           |  |  | 681 | 		0x11 => "M-Y",
 | 
        
           |  |  | 682 | 		0x12 => "h:i a",
 | 
        
           |  |  | 683 | 		0x13 => "h:i:s a",
 | 
        
           |  |  | 684 | 		0x14 => "H:i",
 | 
        
           |  |  | 685 | 		0x15 => "H:i:s",
 | 
        
           |  |  | 686 | 		0x16 => "d/m/Y H:i",
 | 
        
           |  |  | 687 | 		0x2d => "i:s",
 | 
        
           |  |  | 688 | 		0x2e => "H:i:s",
 | 
        
           |  |  | 689 | 		0x2f => "i:s.S"
 | 
        
           |  |  | 690 | 	);
 | 
        
           |  |  | 691 |   | 
        
           |  |  | 692 | 	/**
 | 
        
           |  |  | 693 | 	 * Default number formats used by Excel
 | 
        
           |  |  | 694 | 	 */
 | 
        
           |  |  | 695 | 	var $numberFormats = array(
 | 
        
           |  |  | 696 | 		0x1 => "0",
 | 
        
           |  |  | 697 | 		0x2 => "0.00",
 | 
        
           |  |  | 698 | 		0x3 => "#,##0",
 | 
        
           |  |  | 699 | 		0x4 => "#,##0.00",
 | 
        
           |  |  | 700 | 		0x5 => "\$#,##0;(\$#,##0)",
 | 
        
           |  |  | 701 | 		0x6 => "\$#,##0;[Red](\$#,##0)",
 | 
        
           |  |  | 702 | 		0x7 => "\$#,##0.00;(\$#,##0.00)",
 | 
        
           |  |  | 703 | 		0x8 => "\$#,##0.00;[Red](\$#,##0.00)",
 | 
        
           |  |  | 704 | 		0x9 => "0%",
 | 
        
           |  |  | 705 | 		0xa => "0.00%",
 | 
        
           |  |  | 706 | 		0xb => "0.00E+00",
 | 
        
           |  |  | 707 | 		0x25 => "#,##0;(#,##0)",
 | 
        
           |  |  | 708 | 		0x26 => "#,##0;[Red](#,##0)",
 | 
        
           |  |  | 709 | 		0x27 => "#,##0.00;(#,##0.00)",
 | 
        
           |  |  | 710 | 		0x28 => "#,##0.00;[Red](#,##0.00)",
 | 
        
           |  |  | 711 | 		0x29 => "#,##0;(#,##0)",  // Not exactly
 | 
        
           |  |  | 712 | 		0x2a => "\$#,##0;(\$#,##0)",  // Not exactly
 | 
        
           |  |  | 713 | 		0x2b => "#,##0.00;(#,##0.00)",  // Not exactly
 | 
        
           |  |  | 714 | 		0x2c => "\$#,##0.00;(\$#,##0.00)",  // Not exactly
 | 
        
           |  |  | 715 | 		0x30 => "##0.0E+0"
 | 
        
           |  |  | 716 | 	);
 | 
        
           |  |  | 717 |   | 
        
           |  |  | 718 |     var $colors = Array(
 | 
        
           |  |  | 719 |         0x00 => "#000000",
 | 
        
           |  |  | 720 |         0x01 => "#FFFFFF",
 | 
        
           |  |  | 721 |         0x02 => "#FF0000",
 | 
        
           |  |  | 722 |         0x03 => "#00FF00",
 | 
        
           |  |  | 723 |         0x04 => "#0000FF",
 | 
        
           |  |  | 724 |         0x05 => "#FFFF00",
 | 
        
           |  |  | 725 |         0x06 => "#FF00FF",
 | 
        
           |  |  | 726 |         0x07 => "#00FFFF",
 | 
        
           |  |  | 727 |         0x08 => "#000000",
 | 
        
           |  |  | 728 |         0x09 => "#FFFFFF",
 | 
        
           |  |  | 729 |         0x0A => "#FF0000",
 | 
        
           |  |  | 730 |         0x0B => "#00FF00",
 | 
        
           |  |  | 731 |         0x0C => "#0000FF",
 | 
        
           |  |  | 732 |         0x0D => "#FFFF00",
 | 
        
           |  |  | 733 |         0x0E => "#FF00FF",
 | 
        
           |  |  | 734 |         0x0F => "#00FFFF",
 | 
        
           |  |  | 735 |         0x10 => "#800000",
 | 
        
           |  |  | 736 |         0x11 => "#008000",
 | 
        
           |  |  | 737 |         0x12 => "#000080",
 | 
        
           |  |  | 738 |         0x13 => "#808000",
 | 
        
           |  |  | 739 |         0x14 => "#800080",
 | 
        
           |  |  | 740 |         0x15 => "#008080",
 | 
        
           |  |  | 741 |         0x16 => "#C0C0C0",
 | 
        
           |  |  | 742 |         0x17 => "#808080",
 | 
        
           |  |  | 743 |         0x18 => "#9999FF",
 | 
        
           |  |  | 744 |         0x19 => "#993366",
 | 
        
           |  |  | 745 |         0x1A => "#FFFFCC",
 | 
        
           |  |  | 746 |         0x1B => "#CCFFFF",
 | 
        
           |  |  | 747 |         0x1C => "#660066",
 | 
        
           |  |  | 748 |         0x1D => "#FF8080",
 | 
        
           |  |  | 749 |         0x1E => "#0066CC",
 | 
        
           |  |  | 750 |         0x1F => "#CCCCFF",
 | 
        
           |  |  | 751 |         0x20 => "#000080",
 | 
        
           |  |  | 752 |         0x21 => "#FF00FF",
 | 
        
           |  |  | 753 |         0x22 => "#FFFF00",
 | 
        
           |  |  | 754 |         0x23 => "#00FFFF",
 | 
        
           |  |  | 755 |         0x24 => "#800080",
 | 
        
           |  |  | 756 |         0x25 => "#800000",
 | 
        
           |  |  | 757 |         0x26 => "#008080",
 | 
        
           |  |  | 758 |         0x27 => "#0000FF",
 | 
        
           |  |  | 759 |         0x28 => "#00CCFF",
 | 
        
           |  |  | 760 |         0x29 => "#CCFFFF",
 | 
        
           |  |  | 761 |         0x2A => "#CCFFCC",
 | 
        
           |  |  | 762 |         0x2B => "#FFFF99",
 | 
        
           |  |  | 763 |         0x2C => "#99CCFF",
 | 
        
           |  |  | 764 |         0x2D => "#FF99CC",
 | 
        
           |  |  | 765 |         0x2E => "#CC99FF",
 | 
        
           |  |  | 766 |         0x2F => "#FFCC99",
 | 
        
           |  |  | 767 |         0x30 => "#3366FF",
 | 
        
           |  |  | 768 |         0x31 => "#33CCCC",
 | 
        
           |  |  | 769 |         0x32 => "#99CC00",
 | 
        
           |  |  | 770 |         0x33 => "#FFCC00",
 | 
        
           |  |  | 771 |         0x34 => "#FF9900",
 | 
        
           |  |  | 772 |         0x35 => "#FF6600",
 | 
        
           |  |  | 773 |         0x36 => "#666699",
 | 
        
           |  |  | 774 |         0x37 => "#969696",
 | 
        
           |  |  | 775 |         0x38 => "#003366",
 | 
        
           |  |  | 776 |         0x39 => "#339966",
 | 
        
           |  |  | 777 |         0x3A => "#003300",
 | 
        
           |  |  | 778 |         0x3B => "#333300",
 | 
        
           |  |  | 779 |         0x3C => "#993300",
 | 
        
           |  |  | 780 |         0x3D => "#993366",
 | 
        
           |  |  | 781 |         0x3E => "#333399",
 | 
        
           |  |  | 782 |         0x3F => "#333333",
 | 
        
           |  |  | 783 |         0x40 => "#000000",
 | 
        
           |  |  | 784 |         0x41 => "#FFFFFF",
 | 
        
           |  |  | 785 |   | 
        
           |  |  | 786 |         0x43 => "#000000",
 | 
        
           |  |  | 787 |         0x4D => "#000000",
 | 
        
           |  |  | 788 |         0x4E => "#FFFFFF",
 | 
        
           |  |  | 789 |         0x4F => "#000000",
 | 
        
           |  |  | 790 |         0x50 => "#FFFFFF",
 | 
        
           |  |  | 791 |         0x51 => "#000000",
 | 
        
           |  |  | 792 |   | 
        
           |  |  | 793 |         0x7FFF => "#000000"
 | 
        
           |  |  | 794 |     );
 | 
        
           |  |  | 795 |   | 
        
           |  |  | 796 | 	var $lineStyles = array(
 | 
        
           |  |  | 797 | 		0x00 => "",
 | 
        
           |  |  | 798 | 		0x01 => "Thin",
 | 
        
           |  |  | 799 | 		0x02 => "Medium",
 | 
        
           |  |  | 800 | 		0x03 => "Dashed",
 | 
        
           |  |  | 801 | 		0x04 => "Dotted",
 | 
        
           |  |  | 802 | 		0x05 => "Thick",
 | 
        
           |  |  | 803 | 		0x06 => "Double",
 | 
        
           |  |  | 804 | 		0x07 => "Hair",
 | 
        
           |  |  | 805 | 		0x08 => "Medium dashed",
 | 
        
           |  |  | 806 | 		0x09 => "Thin dash-dotted",
 | 
        
           |  |  | 807 | 		0x0A => "Medium dash-dotted",
 | 
        
           |  |  | 808 | 		0x0B => "Thin dash-dot-dotted",
 | 
        
           |  |  | 809 | 		0x0C => "Medium dash-dot-dotted",
 | 
        
           |  |  | 810 | 		0x0D => "Slanted medium dash-dotted"
 | 
        
           |  |  | 811 | 	);
 | 
        
           |  |  | 812 |   | 
        
           |  |  | 813 | 	var $lineStylesCss = array(
 | 
        
           |  |  | 814 | 		"Thin" => "1px solid",
 | 
        
           |  |  | 815 | 		"Medium" => "2px solid",
 | 
        
           |  |  | 816 | 		"Dashed" => "1px dashed",
 | 
        
           |  |  | 817 | 		"Dotted" => "1px dotted",
 | 
        
           |  |  | 818 | 		"Thick" => "3px solid",
 | 
        
           |  |  | 819 | 		"Double" => "double",
 | 
        
           |  |  | 820 | 		"Hair" => "1px solid",
 | 
        
           |  |  | 821 | 		"Medium dashed" => "2px dashed",
 | 
        
           |  |  | 822 | 		"Thin dash-dotted" => "1px dashed",
 | 
        
           |  |  | 823 | 		"Medium dash-dotted" => "2px dashed",
 | 
        
           |  |  | 824 | 		"Thin dash-dot-dotted" => "1px dashed",
 | 
        
           |  |  | 825 | 		"Medium dash-dot-dotted" => "2px dashed",
 | 
        
           |  |  | 826 | 		"Slanted medium dash-dotte" => "2px dashed"
 | 
        
           |  |  | 827 | 	);
 | 
        
           |  |  | 828 |   | 
        
           |  |  | 829 | 	function read16bitstring($data, $start) {
 | 
        
           |  |  | 830 | 		$len = 0;
 | 
        
           |  |  | 831 | 		while (ord($data[$start + $len]) + ord($data[$start + $len + 1]) > 0) $len++;
 | 
        
           |  |  | 832 | 		return substr($data, $start, $len);
 | 
        
           |  |  | 833 | 	}
 | 
        
           |  |  | 834 |   | 
        
           |  |  | 835 | 	// ADDED by Matt Kruse for better formatting
 | 
        
           |  |  | 836 | 	function _format_value($format,$num,$f) {
 | 
        
           |  |  | 837 | 		// 49==TEXT format
 | 
        
           |  |  | 838 | 		// http://code.google.com/p/php-excel-reader/issues/detail?id=7
 | 
        
           |  |  | 839 | 		if ( (!$f && $format=="%s") || ($f==49) || ($format=="GENERAL") ) {
 | 
        
           |  |  | 840 | 			return array('string'=>$num, 'formatColor'=>null);
 | 
        
           |  |  | 841 | 		}
 | 
        
           |  |  | 842 |   | 
        
           |  |  | 843 | 		// Custom pattern can be POSITIVE;NEGATIVE;ZERO
 | 
        
           |  |  | 844 | 		// The "text" option as 4th parameter is not handled
 | 
        
           | 996 | aurelien | 845 | 		$parts = explode(";",$format);
 | 
        
           | 452 | david | 846 | 		$pattern = $parts[0];
 | 
        
           |  |  | 847 | 		// Negative pattern
 | 
        
           |  |  | 848 | 		if (count($parts)>2 && $num==0) {
 | 
        
           |  |  | 849 | 			$pattern = $parts[2];
 | 
        
           |  |  | 850 | 		}
 | 
        
           |  |  | 851 | 		// Zero pattern
 | 
        
           |  |  | 852 | 		if (count($parts)>1 && $num<0) {
 | 
        
           |  |  | 853 | 			$pattern = $parts[1];
 | 
        
           |  |  | 854 | 			$num = abs($num);
 | 
        
           |  |  | 855 | 		}
 | 
        
           |  |  | 856 |   | 
        
           |  |  | 857 | 		$color = "";
 | 
        
           |  |  | 858 | 		$matches = array();
 | 
        
           |  |  | 859 | 		$color_regex = "/^\[(BLACK|BLUE|CYAN|GREEN|MAGENTA|RED|WHITE|YELLOW)\]/i";
 | 
        
           |  |  | 860 | 		if (preg_match($color_regex,$pattern,$matches)) {
 | 
        
           |  |  | 861 | 			$color = strtolower($matches[1]);
 | 
        
           |  |  | 862 | 			$pattern = preg_replace($color_regex,"",$pattern);
 | 
        
           |  |  | 863 | 		}
 | 
        
           |  |  | 864 |   | 
        
           |  |  | 865 | 		// In Excel formats, "_" is used to add spacing, which we can't do in HTML
 | 
        
           |  |  | 866 | 		$pattern = preg_replace("/_./","",$pattern);
 | 
        
           |  |  | 867 |   | 
        
           |  |  | 868 | 		// Some non-number characters are escaped with \, which we don't need
 | 
        
           |  |  | 869 | 		$pattern = preg_replace("/\\\/","",$pattern);
 | 
        
           |  |  | 870 |   | 
        
           |  |  | 871 | 		// Some non-number strings are quoted, so we'll get rid of the quotes
 | 
        
           |  |  | 872 | 		$pattern = preg_replace("/\"/","",$pattern);
 | 
        
           |  |  | 873 |   | 
        
           |  |  | 874 | 		// TEMPORARY - Convert # to 0
 | 
        
           |  |  | 875 | 		$pattern = preg_replace("/\#/","0",$pattern);
 | 
        
           |  |  | 876 |   | 
        
           |  |  | 877 | 		// Find out if we need comma formatting
 | 
        
           |  |  | 878 | 		$has_commas = preg_match("/,/",$pattern);
 | 
        
           |  |  | 879 | 		if ($has_commas) {
 | 
        
           |  |  | 880 | 			$pattern = preg_replace("/,/","",$pattern);
 | 
        
           |  |  | 881 | 		}
 | 
        
           |  |  | 882 |   | 
        
           |  |  | 883 | 		// Handle Percentages
 | 
        
           |  |  | 884 | 		if (preg_match("/\d(\%)([^\%]|$)/",$pattern,$matches)) {
 | 
        
           |  |  | 885 | 			$num = $num * 100;
 | 
        
           |  |  | 886 | 			$pattern = preg_replace("/(\d)(\%)([^\%]|$)/","$1%$3",$pattern);
 | 
        
           |  |  | 887 | 		}
 | 
        
           |  |  | 888 |   | 
        
           |  |  | 889 | 		// Handle the number itself
 | 
        
           |  |  | 890 | 		$number_regex = "/(\d+)(\.?)(\d*)/";
 | 
        
           |  |  | 891 | 		if (preg_match($number_regex,$pattern,$matches)) {
 | 
        
           |  |  | 892 | 			$left = $matches[1];
 | 
        
           |  |  | 893 | 			$dec = $matches[2];
 | 
        
           |  |  | 894 | 			$right = $matches[3];
 | 
        
           |  |  | 895 | 			if ($has_commas) {
 | 
        
           |  |  | 896 | 				$formatted = number_format($num,strlen($right));
 | 
        
           |  |  | 897 | 			}
 | 
        
           |  |  | 898 | 			else {
 | 
        
           |  |  | 899 | 				$sprintf_pattern = "%1.".strlen($right)."f";
 | 
        
           |  |  | 900 | 				$formatted = sprintf($sprintf_pattern, $num);
 | 
        
           |  |  | 901 | 			}
 | 
        
           |  |  | 902 | 			$pattern = preg_replace($number_regex, $formatted, $pattern);
 | 
        
           |  |  | 903 | 		}
 | 
        
           |  |  | 904 |   | 
        
           |  |  | 905 | 		return array(
 | 
        
           |  |  | 906 | 			'string'=>$pattern,
 | 
        
           |  |  | 907 | 			'formatColor'=>$color
 | 
        
           |  |  | 908 | 		);
 | 
        
           |  |  | 909 | 	}
 | 
        
           |  |  | 910 |   | 
        
           |  |  | 911 | 	/**
 | 
        
           |  |  | 912 | 	 * Constructor
 | 
        
           |  |  | 913 | 	 *
 | 
        
           |  |  | 914 | 	 * Some basic initialisation
 | 
        
           |  |  | 915 | 	 */
 | 
        
           |  |  | 916 | 	function Spreadsheet_Excel_Reader($file='',$store_extended_info=true,$outputEncoding='') {
 | 
        
           | 1603 | raphael | 917 | 		$this->_ole = new OLERead();
 | 
        
           | 452 | david | 918 | 		$this->setUTFEncoder('iconv');
 | 
        
           |  |  | 919 | 		if ($outputEncoding != '') {
 | 
        
           |  |  | 920 | 			$this->setOutputEncoding($outputEncoding);
 | 
        
           |  |  | 921 | 		}
 | 
        
           |  |  | 922 | 		for ($i=1; $i<245; $i++) {
 | 
        
           |  |  | 923 | 			$name = strtolower(( (($i-1)/26>=1)?chr(($i-1)/26+64):'') . chr(($i-1)%26+65));
 | 
        
           |  |  | 924 | 			$this->colnames[$name] = $i;
 | 
        
           |  |  | 925 | 			$this->colindexes[$i] = $name;
 | 
        
           |  |  | 926 | 		}
 | 
        
           |  |  | 927 | 		$this->store_extended_info = $store_extended_info;
 | 
        
           |  |  | 928 | 		if ($file!="") {
 | 
        
           |  |  | 929 | 			$this->read($file);
 | 
        
           |  |  | 930 | 		}
 | 
        
           |  |  | 931 | 	}
 | 
        
           |  |  | 932 |   | 
        
           |  |  | 933 | 	/**
 | 
        
           |  |  | 934 | 	 * Set the encoding method
 | 
        
           |  |  | 935 | 	 */
 | 
        
           |  |  | 936 | 	function setOutputEncoding($encoding) {
 | 
        
           |  |  | 937 | 		$this->_defaultEncoding = $encoding;
 | 
        
           |  |  | 938 | 	}
 | 
        
           |  |  | 939 |   | 
        
           |  |  | 940 | 	/**
 | 
        
           |  |  | 941 | 	 *  $encoder = 'iconv' or 'mb'
 | 
        
           |  |  | 942 | 	 *  set iconv if you would like use 'iconv' for encode UTF-16LE to your encoding
 | 
        
           |  |  | 943 | 	 *  set mb if you would like use 'mb_convert_encoding' for encode UTF-16LE to your encoding
 | 
        
           |  |  | 944 | 	 */
 | 
        
           |  |  | 945 | 	function setUTFEncoder($encoder = 'iconv') {
 | 
        
           |  |  | 946 | 		$this->_encoderFunction = '';
 | 
        
           |  |  | 947 | 		if ($encoder == 'iconv') {
 | 
        
           |  |  | 948 | 			$this->_encoderFunction = function_exists('iconv') ? 'iconv' : '';
 | 
        
           |  |  | 949 | 		} elseif ($encoder == 'mb') {
 | 
        
           |  |  | 950 | 			$this->_encoderFunction = function_exists('mb_convert_encoding') ? 'mb_convert_encoding' : '';
 | 
        
           |  |  | 951 | 		}
 | 
        
           |  |  | 952 | 	}
 | 
        
           |  |  | 953 |   | 
        
           |  |  | 954 | 	function setRowColOffset($iOffset) {
 | 
        
           |  |  | 955 | 		$this->_rowoffset = $iOffset;
 | 
        
           |  |  | 956 | 		$this->_coloffset = $iOffset;
 | 
        
           |  |  | 957 | 	}
 | 
        
           |  |  | 958 |   | 
        
           |  |  | 959 | 	/**
 | 
        
           |  |  | 960 | 	 * Set the default number format
 | 
        
           |  |  | 961 | 	 */
 | 
        
           |  |  | 962 | 	function setDefaultFormat($sFormat) {
 | 
        
           |  |  | 963 | 		$this->_defaultFormat = $sFormat;
 | 
        
           |  |  | 964 | 	}
 | 
        
           |  |  | 965 |   | 
        
           |  |  | 966 | 	/**
 | 
        
           |  |  | 967 | 	 * Force a column to use a certain format
 | 
        
           |  |  | 968 | 	 */
 | 
        
           |  |  | 969 | 	function setColumnFormat($column, $sFormat) {
 | 
        
           |  |  | 970 | 		$this->_columnsFormat[$column] = $sFormat;
 | 
        
           |  |  | 971 | 	}
 | 
        
           |  |  | 972 |   | 
        
           |  |  | 973 | 	/**
 | 
        
           |  |  | 974 | 	 * Read the spreadsheet file using OLE, then parse
 | 
        
           |  |  | 975 | 	 */
 | 
        
           |  |  | 976 | 	function read($sFileName) {
 | 
        
           |  |  | 977 | 		$res = $this->_ole->read($sFileName);
 | 
        
           |  |  | 978 |   | 
        
           |  |  | 979 | 		// oops, something goes wrong (Darko Miljanovic)
 | 
        
           |  |  | 980 | 		if($res === false) {
 | 
        
           |  |  | 981 | 			// check error code
 | 
        
           |  |  | 982 | 			if($this->_ole->error == 1) {
 | 
        
           |  |  | 983 | 				// bad file
 | 
        
           |  |  | 984 | 				die('The filename ' . $sFileName . ' is not readable');
 | 
        
           |  |  | 985 | 			}
 | 
        
           |  |  | 986 | 			// check other error codes here (eg bad fileformat, etc...)
 | 
        
           |  |  | 987 | 		}
 | 
        
           |  |  | 988 | 		$this->data = $this->_ole->getWorkBook();
 | 
        
           |  |  | 989 | 		$this->_parse();
 | 
        
           |  |  | 990 | 	}
 | 
        
           |  |  | 991 |   | 
        
           |  |  | 992 | 	/**
 | 
        
           |  |  | 993 | 	 * Parse a workbook
 | 
        
           |  |  | 994 | 	 *
 | 
        
           |  |  | 995 | 	 * @access private
 | 
        
           |  |  | 996 | 	 * @return bool
 | 
        
           |  |  | 997 | 	 */
 | 
        
           |  |  | 998 | 	function _parse() {
 | 
        
           |  |  | 999 | 		$pos = 0;
 | 
        
           |  |  | 1000 | 		$data = $this->data;
 | 
        
           |  |  | 1001 |   | 
        
           |  |  | 1002 | 		$code = v($data,$pos);
 | 
        
           |  |  | 1003 | 		$length = v($data,$pos+2);
 | 
        
           |  |  | 1004 | 		$version = v($data,$pos+4);
 | 
        
           |  |  | 1005 | 		$substreamType = v($data,$pos+6);
 | 
        
           |  |  | 1006 |   | 
        
           |  |  | 1007 | 		$this->version = $version;
 | 
        
           |  |  | 1008 |   | 
        
           |  |  | 1009 | 		if (($version != SPREADSHEET_EXCEL_READER_BIFF8) &&
 | 
        
           |  |  | 1010 | 			($version != SPREADSHEET_EXCEL_READER_BIFF7)) {
 | 
        
           |  |  | 1011 | 			return false;
 | 
        
           |  |  | 1012 | 		}
 | 
        
           |  |  | 1013 |   | 
        
           |  |  | 1014 | 		if ($substreamType != SPREADSHEET_EXCEL_READER_WORKBOOKGLOBALS){
 | 
        
           |  |  | 1015 | 			return false;
 | 
        
           |  |  | 1016 | 		}
 | 
        
           |  |  | 1017 |   | 
        
           |  |  | 1018 | 		$pos += $length + 4;
 | 
        
           |  |  | 1019 |   | 
        
           |  |  | 1020 | 		$code = v($data,$pos);
 | 
        
           |  |  | 1021 | 		$length = v($data,$pos+2);
 | 
        
           |  |  | 1022 |   | 
        
           |  |  | 1023 | 		while ($code != SPREADSHEET_EXCEL_READER_TYPE_EOF) {
 | 
        
           |  |  | 1024 | 			switch ($code) {
 | 
        
           |  |  | 1025 | 				case SPREADSHEET_EXCEL_READER_TYPE_SST:
 | 
        
           |  |  | 1026 | 					$spos = $pos + 4;
 | 
        
           |  |  | 1027 | 					$limitpos = $spos + $length;
 | 
        
           |  |  | 1028 | 					$uniqueStrings = $this->_GetInt4d($data, $spos+4);
 | 
        
           |  |  | 1029 | 					$spos += 8;
 | 
        
           |  |  | 1030 | 					for ($i = 0; $i < $uniqueStrings; $i++) {
 | 
        
           |  |  | 1031 | 						// Read in the number of characters
 | 
        
           |  |  | 1032 | 						if ($spos == $limitpos) {
 | 
        
           |  |  | 1033 | 							$opcode = v($data,$spos);
 | 
        
           |  |  | 1034 | 							$conlength = v($data,$spos+2);
 | 
        
           |  |  | 1035 | 							if ($opcode != 0x3c) {
 | 
        
           |  |  | 1036 | 								return -1;
 | 
        
           |  |  | 1037 | 							}
 | 
        
           |  |  | 1038 | 							$spos += 4;
 | 
        
           |  |  | 1039 | 							$limitpos = $spos + $conlength;
 | 
        
           |  |  | 1040 | 						}
 | 
        
           |  |  | 1041 | 						$numChars = ord($data[$spos]) | (ord($data[$spos+1]) << 8);
 | 
        
           |  |  | 1042 | 						$spos += 2;
 | 
        
           |  |  | 1043 | 						$optionFlags = ord($data[$spos]);
 | 
        
           |  |  | 1044 | 						$spos++;
 | 
        
           |  |  | 1045 | 						$asciiEncoding = (($optionFlags & 0x01) == 0) ;
 | 
        
           |  |  | 1046 | 						$extendedString = ( ($optionFlags & 0x04) != 0);
 | 
        
           |  |  | 1047 |   | 
        
           |  |  | 1048 | 						// See if string contains formatting information
 | 
        
           |  |  | 1049 | 						$richString = ( ($optionFlags & 0x08) != 0);
 | 
        
           |  |  | 1050 |   | 
        
           |  |  | 1051 | 						if ($richString) {
 | 
        
           |  |  | 1052 | 							// Read in the crun
 | 
        
           |  |  | 1053 | 							$formattingRuns = v($data,$spos);
 | 
        
           |  |  | 1054 | 							$spos += 2;
 | 
        
           |  |  | 1055 | 						}
 | 
        
           |  |  | 1056 |   | 
        
           |  |  | 1057 | 						if ($extendedString) {
 | 
        
           |  |  | 1058 | 							// Read in cchExtRst
 | 
        
           |  |  | 1059 | 							$extendedRunLength = $this->_GetInt4d($data, $spos);
 | 
        
           |  |  | 1060 | 							$spos += 4;
 | 
        
           |  |  | 1061 | 						}
 | 
        
           |  |  | 1062 |   | 
        
           |  |  | 1063 | 						$len = ($asciiEncoding)? $numChars : $numChars*2;
 | 
        
           |  |  | 1064 | 						if ($spos + $len < $limitpos) {
 | 
        
           |  |  | 1065 | 							$retstr = substr($data, $spos, $len);
 | 
        
           |  |  | 1066 | 							$spos += $len;
 | 
        
           |  |  | 1067 | 						}
 | 
        
           |  |  | 1068 | 						else{
 | 
        
           |  |  | 1069 | 							// found countinue
 | 
        
           |  |  | 1070 | 							$retstr = substr($data, $spos, $limitpos - $spos);
 | 
        
           |  |  | 1071 | 							$bytesRead = $limitpos - $spos;
 | 
        
           |  |  | 1072 | 							$charsLeft = $numChars - (($asciiEncoding) ? $bytesRead : ($bytesRead / 2));
 | 
        
           |  |  | 1073 | 							$spos = $limitpos;
 | 
        
           |  |  | 1074 |   | 
        
           |  |  | 1075 | 							while ($charsLeft > 0){
 | 
        
           |  |  | 1076 | 								$opcode = v($data,$spos);
 | 
        
           |  |  | 1077 | 								$conlength = v($data,$spos+2);
 | 
        
           |  |  | 1078 | 								if ($opcode != 0x3c) {
 | 
        
           |  |  | 1079 | 									return -1;
 | 
        
           |  |  | 1080 | 								}
 | 
        
           |  |  | 1081 | 								$spos += 4;
 | 
        
           |  |  | 1082 | 								$limitpos = $spos + $conlength;
 | 
        
           |  |  | 1083 | 								$option = ord($data[$spos]);
 | 
        
           |  |  | 1084 | 								$spos += 1;
 | 
        
           |  |  | 1085 | 								if ($asciiEncoding && ($option == 0)) {
 | 
        
           |  |  | 1086 | 									$len = min($charsLeft, $limitpos - $spos); // min($charsLeft, $conlength);
 | 
        
           |  |  | 1087 | 									$retstr .= substr($data, $spos, $len);
 | 
        
           |  |  | 1088 | 									$charsLeft -= $len;
 | 
        
           |  |  | 1089 | 									$asciiEncoding = true;
 | 
        
           |  |  | 1090 | 								}
 | 
        
           |  |  | 1091 | 								elseif (!$asciiEncoding && ($option != 0)) {
 | 
        
           |  |  | 1092 | 									$len = min($charsLeft * 2, $limitpos - $spos); // min($charsLeft, $conlength);
 | 
        
           |  |  | 1093 | 									$retstr .= substr($data, $spos, $len);
 | 
        
           |  |  | 1094 | 									$charsLeft -= $len/2;
 | 
        
           |  |  | 1095 | 									$asciiEncoding = false;
 | 
        
           |  |  | 1096 | 								}
 | 
        
           |  |  | 1097 | 								elseif (!$asciiEncoding && ($option == 0)) {
 | 
        
           |  |  | 1098 | 									// Bummer - the string starts off as Unicode, but after the
 | 
        
           |  |  | 1099 | 									// continuation it is in straightforward ASCII encoding
 | 
        
           |  |  | 1100 | 									$len = min($charsLeft, $limitpos - $spos); // min($charsLeft, $conlength);
 | 
        
           |  |  | 1101 | 									for ($j = 0; $j < $len; $j++) {
 | 
        
           |  |  | 1102 | 										$retstr .= $data[$spos + $j].chr(0);
 | 
        
           |  |  | 1103 | 									}
 | 
        
           |  |  | 1104 | 									$charsLeft -= $len;
 | 
        
           |  |  | 1105 | 									$asciiEncoding = false;
 | 
        
           |  |  | 1106 | 								}
 | 
        
           |  |  | 1107 | 								else{
 | 
        
           |  |  | 1108 | 									$newstr = '';
 | 
        
           |  |  | 1109 | 									for ($j = 0; $j < strlen($retstr); $j++) {
 | 
        
           |  |  | 1110 | 										$newstr = $retstr[$j].chr(0);
 | 
        
           |  |  | 1111 | 									}
 | 
        
           |  |  | 1112 | 									$retstr = $newstr;
 | 
        
           |  |  | 1113 | 									$len = min($charsLeft * 2, $limitpos - $spos); // min($charsLeft, $conlength);
 | 
        
           |  |  | 1114 | 									$retstr .= substr($data, $spos, $len);
 | 
        
           |  |  | 1115 | 									$charsLeft -= $len/2;
 | 
        
           |  |  | 1116 | 									$asciiEncoding = false;
 | 
        
           |  |  | 1117 | 								}
 | 
        
           |  |  | 1118 | 								$spos += $len;
 | 
        
           |  |  | 1119 | 							}
 | 
        
           |  |  | 1120 | 						}
 | 
        
           | 1621 | raphael | 1121 | 						$retstr = iconv('latin9', 'utf-8', $retstr);
 | 
        
           | 452 | david | 1122 |   | 
        
           |  |  | 1123 | 						if ($richString){
 | 
        
           |  |  | 1124 | 							$spos += 4 * $formattingRuns;
 | 
        
           |  |  | 1125 | 						}
 | 
        
           |  |  | 1126 |   | 
        
           |  |  | 1127 | 						// For extended strings, skip over the extended string data
 | 
        
           |  |  | 1128 | 						if ($extendedString) {
 | 
        
           |  |  | 1129 | 							$spos += $extendedRunLength;
 | 
        
           |  |  | 1130 | 						}
 | 
        
           |  |  | 1131 | 						$this->sst[]=$retstr;
 | 
        
           |  |  | 1132 | 					}
 | 
        
           |  |  | 1133 | 					break;
 | 
        
           |  |  | 1134 | 				case SPREADSHEET_EXCEL_READER_TYPE_FILEPASS:
 | 
        
           |  |  | 1135 | 					return false;
 | 
        
           |  |  | 1136 | 					break;
 | 
        
           |  |  | 1137 | 				case SPREADSHEET_EXCEL_READER_TYPE_NAME:
 | 
        
           |  |  | 1138 | 					break;
 | 
        
           |  |  | 1139 | 				case SPREADSHEET_EXCEL_READER_TYPE_FORMAT:
 | 
        
           |  |  | 1140 | 					$indexCode = v($data,$pos+4);
 | 
        
           |  |  | 1141 | 					if ($version == SPREADSHEET_EXCEL_READER_BIFF8) {
 | 
        
           |  |  | 1142 | 						$numchars = v($data,$pos+6);
 | 
        
           |  |  | 1143 | 						if (ord($data[$pos+8]) == 0){
 | 
        
           |  |  | 1144 | 							$formatString = substr($data, $pos+9, $numchars);
 | 
        
           |  |  | 1145 | 						} else {
 | 
        
           |  |  | 1146 | 							$formatString = substr($data, $pos+9, $numchars*2);
 | 
        
           |  |  | 1147 | 						}
 | 
        
           |  |  | 1148 | 					} else {
 | 
        
           |  |  | 1149 | 						$numchars = ord($data[$pos+6]);
 | 
        
           |  |  | 1150 | 						$formatString = substr($data, $pos+7, $numchars*2);
 | 
        
           |  |  | 1151 | 					}
 | 
        
           |  |  | 1152 | 					$this->formatRecords[$indexCode] = $formatString;
 | 
        
           |  |  | 1153 | 					break;
 | 
        
           |  |  | 1154 | 				case SPREADSHEET_EXCEL_READER_TYPE_FONT:
 | 
        
           |  |  | 1155 | 						$height = v($data,$pos+4);
 | 
        
           |  |  | 1156 | 						$option = v($data,$pos+6);
 | 
        
           |  |  | 1157 | 						$color = v($data,$pos+8);
 | 
        
           |  |  | 1158 | 						$weight = v($data,$pos+10);
 | 
        
           |  |  | 1159 | 						$under  = ord($data[$pos+14]);
 | 
        
           |  |  | 1160 | 						$font = "";
 | 
        
           |  |  | 1161 | 						// Font name
 | 
        
           |  |  | 1162 | 						$numchars = ord($data[$pos+18]);
 | 
        
           |  |  | 1163 | 						if ((ord($data[$pos+19]) & 1) == 0){
 | 
        
           |  |  | 1164 | 						    $font = substr($data, $pos+20, $numchars);
 | 
        
           |  |  | 1165 | 						} else {
 | 
        
           |  |  | 1166 | 						    $font = substr($data, $pos+20, $numchars*2);
 | 
        
           |  |  | 1167 | 						    $font =  $this->_encodeUTF16($font);
 | 
        
           |  |  | 1168 | 						}
 | 
        
           |  |  | 1169 | 						$this->fontRecords[] = array(
 | 
        
           |  |  | 1170 | 								'height' => $height / 20,
 | 
        
           |  |  | 1171 | 								'italic' => !!($option & 2),
 | 
        
           |  |  | 1172 | 								'color' => $color,
 | 
        
           |  |  | 1173 | 								'under' => !($under==0),
 | 
        
           |  |  | 1174 | 								'bold' => ($weight==700),
 | 
        
           |  |  | 1175 | 								'font' => $font,
 | 
        
           |  |  | 1176 | 								'raw' => $this->dumpHexData($data, $pos+3, $length)
 | 
        
           |  |  | 1177 | 								);
 | 
        
           |  |  | 1178 | 					    break;
 | 
        
           |  |  | 1179 |   | 
        
           |  |  | 1180 | 				case SPREADSHEET_EXCEL_READER_TYPE_PALETTE:
 | 
        
           |  |  | 1181 | 						$colors = ord($data[$pos+4]) | ord($data[$pos+5]) << 8;
 | 
        
           |  |  | 1182 | 						for ($coli = 0; $coli < $colors; $coli++) {
 | 
        
           |  |  | 1183 | 						    $colOff = $pos + 2 + ($coli * 4);
 | 
        
           |  |  | 1184 |   						    $colr = ord($data[$colOff]);
 | 
        
           |  |  | 1185 |   						    $colg = ord($data[$colOff+1]);
 | 
        
           |  |  | 1186 |   						    $colb = ord($data[$colOff+2]);
 | 
        
           |  |  | 1187 | 							$this->colors[0x07 + $coli] = '#' . $this->myhex($colr) . $this->myhex($colg) . $this->myhex($colb);
 | 
        
           |  |  | 1188 | 						}
 | 
        
           |  |  | 1189 | 					    break;
 | 
        
           |  |  | 1190 |   | 
        
           |  |  | 1191 | 				case SPREADSHEET_EXCEL_READER_TYPE_XF:
 | 
        
           |  |  | 1192 | 						$fontIndexCode = (ord($data[$pos+4]) | ord($data[$pos+5]) << 8) - 1;
 | 
        
           |  |  | 1193 | 						$fontIndexCode = max(0,$fontIndexCode);
 | 
        
           |  |  | 1194 | 						$indexCode = ord($data[$pos+6]) | ord($data[$pos+7]) << 8;
 | 
        
           |  |  | 1195 | 						$alignbit = ord($data[$pos+10]) & 3;
 | 
        
           |  |  | 1196 | 						$bgi = (ord($data[$pos+22]) | ord($data[$pos+23]) << 8) & 0x3FFF;
 | 
        
           |  |  | 1197 | 						$bgcolor = ($bgi & 0x7F);
 | 
        
           |  |  | 1198 | //						$bgcolor = ($bgi & 0x3f80) >> 7;
 | 
        
           |  |  | 1199 | 						$align = "";
 | 
        
           |  |  | 1200 | 						if ($alignbit==3) { $align="right"; }
 | 
        
           |  |  | 1201 | 						if ($alignbit==2) { $align="center"; }
 | 
        
           |  |  | 1202 |   | 
        
           |  |  | 1203 | 						$fillPattern = (ord($data[$pos+21]) & 0xFC) >> 2;
 | 
        
           |  |  | 1204 | 						if ($fillPattern == 0) {
 | 
        
           |  |  | 1205 | 							$bgcolor = "";
 | 
        
           |  |  | 1206 | 						}
 | 
        
           |  |  | 1207 |   | 
        
           |  |  | 1208 | 						$xf = array();
 | 
        
           |  |  | 1209 | 						$xf['formatIndex'] = $indexCode;
 | 
        
           |  |  | 1210 | 						$xf['align'] = $align;
 | 
        
           |  |  | 1211 | 						$xf['fontIndex'] = $fontIndexCode;
 | 
        
           |  |  | 1212 | 						$xf['bgColor'] = $bgcolor;
 | 
        
           |  |  | 1213 | 						$xf['fillPattern'] = $fillPattern;
 | 
        
           |  |  | 1214 |   | 
        
           |  |  | 1215 | 						$border = ord($data[$pos+14]) | (ord($data[$pos+15]) << 8) | (ord($data[$pos+16]) << 16) | (ord($data[$pos+17]) << 24);
 | 
        
           |  |  | 1216 | 						$xf['borderLeft'] = $this->lineStyles[($border & 0xF)];
 | 
        
           |  |  | 1217 | 						$xf['borderRight'] = $this->lineStyles[($border & 0xF0) >> 4];
 | 
        
           |  |  | 1218 | 						$xf['borderTop'] = $this->lineStyles[($border & 0xF00) >> 8];
 | 
        
           |  |  | 1219 | 						$xf['borderBottom'] = $this->lineStyles[($border & 0xF000) >> 12];
 | 
        
           |  |  | 1220 |   | 
        
           |  |  | 1221 | 						$xf['borderLeftColor'] = ($border & 0x7F0000) >> 16;
 | 
        
           |  |  | 1222 | 						$xf['borderRightColor'] = ($border & 0x3F800000) >> 23;
 | 
        
           |  |  | 1223 | 						$border = (ord($data[$pos+18]) | ord($data[$pos+19]) << 8);
 | 
        
           |  |  | 1224 |   | 
        
           |  |  | 1225 | 						$xf['borderTopColor'] = ($border & 0x7F);
 | 
        
           |  |  | 1226 | 						$xf['borderBottomColor'] = ($border & 0x3F80) >> 7;
 | 
        
           |  |  | 1227 |   | 
        
           |  |  | 1228 | 						if (array_key_exists($indexCode, $this->dateFormats)) {
 | 
        
           |  |  | 1229 | 							$xf['type'] = 'date';
 | 
        
           |  |  | 1230 | 							$xf['format'] = $this->dateFormats[$indexCode];
 | 
        
           |  |  | 1231 | 							if ($align=='') { $xf['align'] = 'right'; }
 | 
        
           |  |  | 1232 | 						}elseif (array_key_exists($indexCode, $this->numberFormats)) {
 | 
        
           |  |  | 1233 | 							$xf['type'] = 'number';
 | 
        
           |  |  | 1234 | 							$xf['format'] = $this->numberFormats[$indexCode];
 | 
        
           |  |  | 1235 | 							if ($align=='') { $xf['align'] = 'right'; }
 | 
        
           |  |  | 1236 | 						}else{
 | 
        
           |  |  | 1237 | 							$isdate = FALSE;
 | 
        
           |  |  | 1238 | 							$formatstr = '';
 | 
        
           |  |  | 1239 | 							if ($indexCode > 0){
 | 
        
           |  |  | 1240 | 								if (isset($this->formatRecords[$indexCode]))
 | 
        
           |  |  | 1241 | 									$formatstr = $this->formatRecords[$indexCode];
 | 
        
           |  |  | 1242 | 								if ($formatstr!="") {
 | 
        
           |  |  | 1243 | 									$tmp = preg_replace("/\;.*/","",$formatstr);
 | 
        
           |  |  | 1244 | 									$tmp = preg_replace("/^\[[^\]]*\]/","",$tmp);
 | 
        
           |  |  | 1245 | 									if (preg_match("/[^hmsday\/\-:\s\\\,AMP]/i", $tmp) == 0) { // found day and time format
 | 
        
           |  |  | 1246 | 										$isdate = TRUE;
 | 
        
           |  |  | 1247 | 										$formatstr = $tmp;
 | 
        
           |  |  | 1248 | 										$formatstr = str_replace(array('AM/PM','mmmm','mmm'), array('a','F','M'), $formatstr);
 | 
        
           |  |  | 1249 | 										// m/mm are used for both minutes and months - oh SNAP!
 | 
        
           |  |  | 1250 | 										// This mess tries to fix for that.
 | 
        
           |  |  | 1251 | 										// 'm' == minutes only if following h/hh or preceding s/ss
 | 
        
           |  |  | 1252 | 										$formatstr = preg_replace("/(h:?)mm?/","$1i", $formatstr);
 | 
        
           |  |  | 1253 | 										$formatstr = preg_replace("/mm?(:?s)/","i$1", $formatstr);
 | 
        
           |  |  | 1254 | 										// A single 'm' = n in PHP
 | 
        
           |  |  | 1255 | 										$formatstr = preg_replace("/(^|[^m])m([^m]|$)/", '$1n$2', $formatstr);
 | 
        
           |  |  | 1256 | 										$formatstr = preg_replace("/(^|[^m])m([^m]|$)/", '$1n$2', $formatstr);
 | 
        
           |  |  | 1257 | 										// else it's months
 | 
        
           |  |  | 1258 | 										$formatstr = str_replace('mm', 'm', $formatstr);
 | 
        
           |  |  | 1259 | 										// Convert single 'd' to 'j'
 | 
        
           |  |  | 1260 | 										$formatstr = preg_replace("/(^|[^d])d([^d]|$)/", '$1j$2', $formatstr);
 | 
        
           |  |  | 1261 | 										$formatstr = str_replace(array('dddd','ddd','dd','yyyy','yy','hh','h'), array('l','D','d','Y','y','H','g'), $formatstr);
 | 
        
           |  |  | 1262 | 										$formatstr = preg_replace("/ss?/", 's', $formatstr);
 | 
        
           |  |  | 1263 | 									}
 | 
        
           |  |  | 1264 | 								}
 | 
        
           |  |  | 1265 | 							}
 | 
        
           |  |  | 1266 | 							if ($isdate){
 | 
        
           |  |  | 1267 | 								$xf['type'] = 'date';
 | 
        
           |  |  | 1268 | 								$xf['format'] = $formatstr;
 | 
        
           |  |  | 1269 | 								if ($align=='') { $xf['align'] = 'right'; }
 | 
        
           |  |  | 1270 | 							}else{
 | 
        
           |  |  | 1271 | 								// If the format string has a 0 or # in it, we'll assume it's a number
 | 
        
           |  |  | 1272 | 								if (preg_match("/[0#]/", $formatstr)) {
 | 
        
           |  |  | 1273 | 									$xf['type'] = 'number';
 | 
        
           |  |  | 1274 | 									if ($align=='') { $xf['align']='right'; }
 | 
        
           |  |  | 1275 | 								}
 | 
        
           |  |  | 1276 | 								else {
 | 
        
           |  |  | 1277 | 								$xf['type'] = 'other';
 | 
        
           |  |  | 1278 | 								}
 | 
        
           |  |  | 1279 | 								$xf['format'] = $formatstr;
 | 
        
           |  |  | 1280 | 								$xf['code'] = $indexCode;
 | 
        
           |  |  | 1281 | 							}
 | 
        
           |  |  | 1282 | 						}
 | 
        
           |  |  | 1283 | 						$this->xfRecords[] = $xf;
 | 
        
           |  |  | 1284 | 					break;
 | 
        
           |  |  | 1285 | 				case SPREADSHEET_EXCEL_READER_TYPE_NINETEENFOUR:
 | 
        
           |  |  | 1286 | 					$this->nineteenFour = (ord($data[$pos+4]) == 1);
 | 
        
           |  |  | 1287 | 					break;
 | 
        
           |  |  | 1288 | 				case SPREADSHEET_EXCEL_READER_TYPE_BOUNDSHEET:
 | 
        
           |  |  | 1289 | 						$rec_offset = $this->_GetInt4d($data, $pos+4);
 | 
        
           |  |  | 1290 | 						$rec_typeFlag = ord($data[$pos+8]);
 | 
        
           |  |  | 1291 | 						$rec_visibilityFlag = ord($data[$pos+9]);
 | 
        
           |  |  | 1292 | 						$rec_length = ord($data[$pos+10]);
 | 
        
           |  |  | 1293 |   | 
        
           |  |  | 1294 | 						if ($version == SPREADSHEET_EXCEL_READER_BIFF8){
 | 
        
           |  |  | 1295 | 							$chartype =  ord($data[$pos+11]);
 | 
        
           |  |  | 1296 | 							if ($chartype == 0){
 | 
        
           |  |  | 1297 | 								$rec_name	= substr($data, $pos+12, $rec_length);
 | 
        
           |  |  | 1298 | 							} else {
 | 
        
           |  |  | 1299 | 								$rec_name	= $this->_encodeUTF16(substr($data, $pos+12, $rec_length*2));
 | 
        
           |  |  | 1300 | 							}
 | 
        
           |  |  | 1301 | 						}elseif ($version == SPREADSHEET_EXCEL_READER_BIFF7){
 | 
        
           |  |  | 1302 | 								$rec_name	= substr($data, $pos+11, $rec_length);
 | 
        
           |  |  | 1303 | 						}
 | 
        
           |  |  | 1304 | 					$this->boundsheets[] = array('name'=>$rec_name,'offset'=>$rec_offset);
 | 
        
           |  |  | 1305 | 					break;
 | 
        
           |  |  | 1306 |   | 
        
           |  |  | 1307 | 			}
 | 
        
           |  |  | 1308 |   | 
        
           |  |  | 1309 | 			$pos += $length + 4;
 | 
        
           |  |  | 1310 | 			$code = ord($data[$pos]) | ord($data[$pos+1])<<8;
 | 
        
           |  |  | 1311 | 			$length = ord($data[$pos+2]) | ord($data[$pos+3])<<8;
 | 
        
           |  |  | 1312 | 		}
 | 
        
           |  |  | 1313 |   | 
        
           |  |  | 1314 | 		foreach ($this->boundsheets as $key=>$val){
 | 
        
           |  |  | 1315 | 			$this->sn = $key;
 | 
        
           |  |  | 1316 | 			$this->_parsesheet($val['offset']);
 | 
        
           |  |  | 1317 | 		}
 | 
        
           |  |  | 1318 | 		return true;
 | 
        
           |  |  | 1319 | 	}
 | 
        
           |  |  | 1320 |   | 
        
           |  |  | 1321 | 	/**
 | 
        
           |  |  | 1322 | 	 * Parse a worksheet
 | 
        
           |  |  | 1323 | 	 */
 | 
        
           |  |  | 1324 | 	function _parsesheet($spos) {
 | 
        
           |  |  | 1325 | 		$cont = true;
 | 
        
           |  |  | 1326 | 		$data = $this->data;
 | 
        
           |  |  | 1327 | 		// read BOF
 | 
        
           |  |  | 1328 | 		$code = ord($data[$spos]) | ord($data[$spos+1])<<8;
 | 
        
           |  |  | 1329 | 		$length = ord($data[$spos+2]) | ord($data[$spos+3])<<8;
 | 
        
           |  |  | 1330 |   | 
        
           |  |  | 1331 | 		$version = ord($data[$spos + 4]) | ord($data[$spos + 5])<<8;
 | 
        
           |  |  | 1332 | 		$substreamType = ord($data[$spos + 6]) | ord($data[$spos + 7])<<8;
 | 
        
           |  |  | 1333 |   | 
        
           |  |  | 1334 | 		if (($version != SPREADSHEET_EXCEL_READER_BIFF8) && ($version != SPREADSHEET_EXCEL_READER_BIFF7)) {
 | 
        
           |  |  | 1335 | 			return -1;
 | 
        
           |  |  | 1336 | 		}
 | 
        
           |  |  | 1337 |   | 
        
           |  |  | 1338 | 		if ($substreamType != SPREADSHEET_EXCEL_READER_WORKSHEET){
 | 
        
           |  |  | 1339 | 			return -2;
 | 
        
           |  |  | 1340 | 		}
 | 
        
           |  |  | 1341 | 		$spos += $length + 4;
 | 
        
           |  |  | 1342 | 		while($cont) {
 | 
        
           |  |  | 1343 | 			$lowcode = ord($data[$spos]);
 | 
        
           |  |  | 1344 | 			if ($lowcode == SPREADSHEET_EXCEL_READER_TYPE_EOF) break;
 | 
        
           |  |  | 1345 | 			$code = $lowcode | ord($data[$spos+1])<<8;
 | 
        
           |  |  | 1346 | 			$length = ord($data[$spos+2]) | ord($data[$spos+3])<<8;
 | 
        
           |  |  | 1347 | 			$spos += 4;
 | 
        
           |  |  | 1348 | 			$this->sheets[$this->sn]['maxrow'] = $this->_rowoffset - 1;
 | 
        
           |  |  | 1349 | 			$this->sheets[$this->sn]['maxcol'] = $this->_coloffset - 1;
 | 
        
           |  |  | 1350 | 			unset($this->rectype);
 | 
        
           |  |  | 1351 | 			switch ($code) {
 | 
        
           |  |  | 1352 | 				case SPREADSHEET_EXCEL_READER_TYPE_DIMENSION:
 | 
        
           |  |  | 1353 | 					if (!isset($this->numRows)) {
 | 
        
           |  |  | 1354 | 						if (($length == 10) ||  ($version == SPREADSHEET_EXCEL_READER_BIFF7)){
 | 
        
           |  |  | 1355 | 							$this->sheets[$this->sn]['numRows'] = ord($data[$spos+2]) | ord($data[$spos+3]) << 8;
 | 
        
           |  |  | 1356 | 							$this->sheets[$this->sn]['numCols'] = ord($data[$spos+6]) | ord($data[$spos+7]) << 8;
 | 
        
           |  |  | 1357 | 						} else {
 | 
        
           |  |  | 1358 | 							$this->sheets[$this->sn]['numRows'] = ord($data[$spos+4]) | ord($data[$spos+5]) << 8;
 | 
        
           |  |  | 1359 | 							$this->sheets[$this->sn]['numCols'] = ord($data[$spos+10]) | ord($data[$spos+11]) << 8;
 | 
        
           |  |  | 1360 | 						}
 | 
        
           |  |  | 1361 | 					}
 | 
        
           |  |  | 1362 | 					break;
 | 
        
           |  |  | 1363 | 				case SPREADSHEET_EXCEL_READER_TYPE_MERGEDCELLS:
 | 
        
           |  |  | 1364 | 					$cellRanges = ord($data[$spos]) | ord($data[$spos+1])<<8;
 | 
        
           |  |  | 1365 | 					for ($i = 0; $i < $cellRanges; $i++) {
 | 
        
           |  |  | 1366 | 						$fr =  ord($data[$spos + 8*$i + 2]) | ord($data[$spos + 8*$i + 3])<<8;
 | 
        
           |  |  | 1367 | 						$lr =  ord($data[$spos + 8*$i + 4]) | ord($data[$spos + 8*$i + 5])<<8;
 | 
        
           |  |  | 1368 | 						$fc =  ord($data[$spos + 8*$i + 6]) | ord($data[$spos + 8*$i + 7])<<8;
 | 
        
           |  |  | 1369 | 						$lc =  ord($data[$spos + 8*$i + 8]) | ord($data[$spos + 8*$i + 9])<<8;
 | 
        
           |  |  | 1370 | 						if ($lr - $fr > 0) {
 | 
        
           |  |  | 1371 | 							$this->sheets[$this->sn]['cellsInfo'][$fr+1][$fc+1]['rowspan'] = $lr - $fr + 1;
 | 
        
           |  |  | 1372 | 						}
 | 
        
           |  |  | 1373 | 						if ($lc - $fc > 0) {
 | 
        
           |  |  | 1374 | 							$this->sheets[$this->sn]['cellsInfo'][$fr+1][$fc+1]['colspan'] = $lc - $fc + 1;
 | 
        
           |  |  | 1375 | 						}
 | 
        
           |  |  | 1376 | 					}
 | 
        
           |  |  | 1377 | 					break;
 | 
        
           |  |  | 1378 | 				case SPREADSHEET_EXCEL_READER_TYPE_RK:
 | 
        
           |  |  | 1379 | 				case SPREADSHEET_EXCEL_READER_TYPE_RK2:
 | 
        
           |  |  | 1380 | 					$row = ord($data[$spos]) | ord($data[$spos+1])<<8;
 | 
        
           |  |  | 1381 | 					$column = ord($data[$spos+2]) | ord($data[$spos+3])<<8;
 | 
        
           |  |  | 1382 | 					$rknum = $this->_GetInt4d($data, $spos + 6);
 | 
        
           |  |  | 1383 | 					$numValue = $this->_GetIEEE754($rknum);
 | 
        
           |  |  | 1384 | 					$info = $this->_getCellDetails($spos,$numValue,$column);
 | 
        
           |  |  | 1385 | 					$this->addcell($row, $column, $info['string'],$info);
 | 
        
           |  |  | 1386 | 					break;
 | 
        
           |  |  | 1387 | 				case SPREADSHEET_EXCEL_READER_TYPE_LABELSST:
 | 
        
           |  |  | 1388 | 					$row		= ord($data[$spos]) | ord($data[$spos+1])<<8;
 | 
        
           |  |  | 1389 | 					$column	 = ord($data[$spos+2]) | ord($data[$spos+3])<<8;
 | 
        
           |  |  | 1390 | 					$xfindex	= ord($data[$spos+4]) | ord($data[$spos+5])<<8;
 | 
        
           |  |  | 1391 | 					$index  = $this->_GetInt4d($data, $spos + 6);
 | 
        
           |  |  | 1392 | 					$this->addcell($row, $column, $this->sst[$index], array('xfIndex'=>$xfindex) );
 | 
        
           |  |  | 1393 | 					break;
 | 
        
           |  |  | 1394 | 				case SPREADSHEET_EXCEL_READER_TYPE_MULRK:
 | 
        
           |  |  | 1395 | 					$row		= ord($data[$spos]) | ord($data[$spos+1])<<8;
 | 
        
           |  |  | 1396 | 					$colFirst   = ord($data[$spos+2]) | ord($data[$spos+3])<<8;
 | 
        
           |  |  | 1397 | 					$colLast	= ord($data[$spos + $length - 2]) | ord($data[$spos + $length - 1])<<8;
 | 
        
           |  |  | 1398 | 					$columns	= $colLast - $colFirst + 1;
 | 
        
           |  |  | 1399 | 					$tmppos = $spos+4;
 | 
        
           |  |  | 1400 | 					for ($i = 0; $i < $columns; $i++) {
 | 
        
           |  |  | 1401 | 						$numValue = $this->_GetIEEE754($this->_GetInt4d($data, $tmppos + 2));
 | 
        
           |  |  | 1402 | 						$info = $this->_getCellDetails($tmppos-4,$numValue,$colFirst + $i + 1);
 | 
        
           |  |  | 1403 | 						$tmppos += 6;
 | 
        
           |  |  | 1404 | 						$this->addcell($row, $colFirst + $i, $info['string'], $info);
 | 
        
           |  |  | 1405 | 					}
 | 
        
           |  |  | 1406 | 					break;
 | 
        
           |  |  | 1407 | 				case SPREADSHEET_EXCEL_READER_TYPE_NUMBER:
 | 
        
           |  |  | 1408 | 					$row	= ord($data[$spos]) | ord($data[$spos+1])<<8;
 | 
        
           |  |  | 1409 | 					$column = ord($data[$spos+2]) | ord($data[$spos+3])<<8;
 | 
        
           |  |  | 1410 | 					$tmp = unpack("ddouble", substr($data, $spos + 6, 8)); // It machine machine dependent
 | 
        
           |  |  | 1411 | 					if ($this->isDate($spos)) {
 | 
        
           |  |  | 1412 | 						$numValue = $tmp['double'];
 | 
        
           |  |  | 1413 | 					}
 | 
        
           |  |  | 1414 | 					else {
 | 
        
           |  |  | 1415 | 						$numValue = $this->createNumber($spos);
 | 
        
           |  |  | 1416 | 					}
 | 
        
           |  |  | 1417 | 					$info = $this->_getCellDetails($spos,$numValue,$column);
 | 
        
           |  |  | 1418 | 					$this->addcell($row, $column, $info['string'], $info);
 | 
        
           |  |  | 1419 | 					break;
 | 
        
           |  |  | 1420 |   | 
        
           |  |  | 1421 | 				case SPREADSHEET_EXCEL_READER_TYPE_FORMULA:
 | 
        
           |  |  | 1422 | 				case SPREADSHEET_EXCEL_READER_TYPE_FORMULA2:
 | 
        
           |  |  | 1423 | 					$row	= ord($data[$spos]) | ord($data[$spos+1])<<8;
 | 
        
           |  |  | 1424 | 					$column = ord($data[$spos+2]) | ord($data[$spos+3])<<8;
 | 
        
           |  |  | 1425 | 					if ((ord($data[$spos+6])==0) && (ord($data[$spos+12])==255) && (ord($data[$spos+13])==255)) {
 | 
        
           |  |  | 1426 | 						//String formula. Result follows in a STRING record
 | 
        
           |  |  | 1427 | 						// This row/col are stored to be referenced in that record
 | 
        
           |  |  | 1428 | 						// http://code.google.com/p/php-excel-reader/issues/detail?id=4
 | 
        
           |  |  | 1429 | 						$previousRow = $row;
 | 
        
           |  |  | 1430 | 						$previousCol = $column;
 | 
        
           |  |  | 1431 | 					} elseif ((ord($data[$spos+6])==1) && (ord($data[$spos+12])==255) && (ord($data[$spos+13])==255)) {
 | 
        
           |  |  | 1432 | 						//Boolean formula. Result is in +2; 0=false,1=true
 | 
        
           |  |  | 1433 | 						// http://code.google.com/p/php-excel-reader/issues/detail?id=4
 | 
        
           |  |  | 1434 |                         if (ord($this->data[$spos+8])==1) {
 | 
        
           |  |  | 1435 |                             $this->addcell($row, $column, "TRUE");
 | 
        
           |  |  | 1436 |                         } else {
 | 
        
           |  |  | 1437 |                             $this->addcell($row, $column, "FALSE");
 | 
        
           |  |  | 1438 |                         }
 | 
        
           |  |  | 1439 | 					} elseif ((ord($data[$spos+6])==2) && (ord($data[$spos+12])==255) && (ord($data[$spos+13])==255)) {
 | 
        
           |  |  | 1440 | 						//Error formula. Error code is in +2;
 | 
        
           |  |  | 1441 | 					} elseif ((ord($data[$spos+6])==3) && (ord($data[$spos+12])==255) && (ord($data[$spos+13])==255)) {
 | 
        
           |  |  | 1442 | 						//Formula result is a null string.
 | 
        
           |  |  | 1443 | 						$this->addcell($row, $column, '');
 | 
        
           |  |  | 1444 | 					} else {
 | 
        
           |  |  | 1445 | 						// result is a number, so first 14 bytes are just like a _NUMBER record
 | 
        
           |  |  | 1446 | 						$tmp = unpack("ddouble", substr($data, $spos + 6, 8)); // It machine machine dependent
 | 
        
           |  |  | 1447 | 							  if ($this->isDate($spos)) {
 | 
        
           |  |  | 1448 | 								$numValue = $tmp['double'];
 | 
        
           |  |  | 1449 | 							  }
 | 
        
           |  |  | 1450 | 							  else {
 | 
        
           |  |  | 1451 | 								$numValue = $this->createNumber($spos);
 | 
        
           |  |  | 1452 | 							  }
 | 
        
           |  |  | 1453 | 						$info = $this->_getCellDetails($spos,$numValue,$column);
 | 
        
           |  |  | 1454 | 						$this->addcell($row, $column, $info['string'], $info);
 | 
        
           |  |  | 1455 | 					}
 | 
        
           |  |  | 1456 | 					break;
 | 
        
           |  |  | 1457 | 				case SPREADSHEET_EXCEL_READER_TYPE_BOOLERR:
 | 
        
           |  |  | 1458 | 					$row	= ord($data[$spos]) | ord($data[$spos+1])<<8;
 | 
        
           |  |  | 1459 | 					$column = ord($data[$spos+2]) | ord($data[$spos+3])<<8;
 | 
        
           |  |  | 1460 | 					$string = ord($data[$spos+6]);
 | 
        
           |  |  | 1461 | 					$this->addcell($row, $column, $string);
 | 
        
           |  |  | 1462 | 					break;
 | 
        
           |  |  | 1463 |                 case SPREADSHEET_EXCEL_READER_TYPE_STRING:
 | 
        
           |  |  | 1464 | 					// http://code.google.com/p/php-excel-reader/issues/detail?id=4
 | 
        
           |  |  | 1465 | 					if ($version == SPREADSHEET_EXCEL_READER_BIFF8){
 | 
        
           |  |  | 1466 | 						// Unicode 16 string, like an SST record
 | 
        
           |  |  | 1467 | 						$xpos = $spos;
 | 
        
           |  |  | 1468 | 						$numChars =ord($data[$xpos]) | (ord($data[$xpos+1]) << 8);
 | 
        
           |  |  | 1469 | 						$xpos += 2;
 | 
        
           |  |  | 1470 | 						$optionFlags =ord($data[$xpos]);
 | 
        
           |  |  | 1471 | 						$xpos++;
 | 
        
           |  |  | 1472 | 						$asciiEncoding = (($optionFlags &0x01) == 0) ;
 | 
        
           |  |  | 1473 | 						$extendedString = (($optionFlags & 0x04) != 0);
 | 
        
           |  |  | 1474 |                         // See if string contains formatting information
 | 
        
           |  |  | 1475 | 						$richString = (($optionFlags & 0x08) != 0);
 | 
        
           |  |  | 1476 | 						if ($richString) {
 | 
        
           |  |  | 1477 | 							// Read in the crun
 | 
        
           |  |  | 1478 | 							$formattingRuns =ord($data[$xpos]) | (ord($data[$xpos+1]) << 8);
 | 
        
           |  |  | 1479 | 							$xpos += 2;
 | 
        
           |  |  | 1480 | 						}
 | 
        
           |  |  | 1481 | 						if ($extendedString) {
 | 
        
           |  |  | 1482 | 							// Read in cchExtRst
 | 
        
           |  |  | 1483 | 							$extendedRunLength =$this->_GetInt4d($this->data, $xpos);
 | 
        
           |  |  | 1484 | 							$xpos += 4;
 | 
        
           |  |  | 1485 | 						}
 | 
        
           |  |  | 1486 | 						$len = ($asciiEncoding)?$numChars : $numChars*2;
 | 
        
           |  |  | 1487 | 						$retstr =substr($data, $xpos, $len);
 | 
        
           |  |  | 1488 | 						$xpos += $len;
 | 
        
           |  |  | 1489 | 						$retstr = ($asciiEncoding)? $retstr : $this->_encodeUTF16($retstr);
 | 
        
           |  |  | 1490 | 					}
 | 
        
           |  |  | 1491 | 					elseif ($version == SPREADSHEET_EXCEL_READER_BIFF7){
 | 
        
           |  |  | 1492 | 						// Simple byte string
 | 
        
           |  |  | 1493 | 						$xpos = $spos;
 | 
        
           |  |  | 1494 | 						$numChars =ord($data[$xpos]) | (ord($data[$xpos+1]) << 8);
 | 
        
           |  |  | 1495 | 						$xpos += 2;
 | 
        
           |  |  | 1496 | 						$retstr =substr($data, $xpos, $numChars);
 | 
        
           |  |  | 1497 | 					}
 | 
        
           |  |  | 1498 | 					$this->addcell($previousRow, $previousCol, $retstr);
 | 
        
           |  |  | 1499 | 					break;
 | 
        
           |  |  | 1500 | 				case SPREADSHEET_EXCEL_READER_TYPE_ROW:
 | 
        
           |  |  | 1501 | 					$row	= ord($data[$spos]) | ord($data[$spos+1])<<8;
 | 
        
           |  |  | 1502 | 					$rowInfo = ord($data[$spos + 6]) | ((ord($data[$spos+7]) << 8) & 0x7FFF);
 | 
        
           |  |  | 1503 | 					if (($rowInfo & 0x8000) > 0) {
 | 
        
           |  |  | 1504 | 						$rowHeight = -1;
 | 
        
           |  |  | 1505 | 					} else {
 | 
        
           |  |  | 1506 | 						$rowHeight = $rowInfo & 0x7FFF;
 | 
        
           |  |  | 1507 | 					}
 | 
        
           |  |  | 1508 | 					$rowHidden = (ord($data[$spos + 12]) & 0x20) >> 5;
 | 
        
           |  |  | 1509 | 					$this->rowInfo[$this->sn][$row+1] = Array('height' => $rowHeight / 20, 'hidden'=>$rowHidden );
 | 
        
           |  |  | 1510 | 					break;
 | 
        
           |  |  | 1511 | 				case SPREADSHEET_EXCEL_READER_TYPE_DBCELL:
 | 
        
           |  |  | 1512 | 					break;
 | 
        
           |  |  | 1513 | 				case SPREADSHEET_EXCEL_READER_TYPE_MULBLANK:
 | 
        
           |  |  | 1514 | 					$row = ord($data[$spos]) | ord($data[$spos+1])<<8;
 | 
        
           |  |  | 1515 | 					$column = ord($data[$spos+2]) | ord($data[$spos+3])<<8;
 | 
        
           |  |  | 1516 | 					$cols = ($length / 2) - 3;
 | 
        
           |  |  | 1517 | 					for ($c = 0; $c < $cols; $c++) {
 | 
        
           |  |  | 1518 | 						$xfindex = ord($data[$spos + 4 + ($c * 2)]) | ord($data[$spos + 5 + ($c * 2)])<<8;
 | 
        
           |  |  | 1519 | 						$this->addcell($row, $column + $c, "", array('xfIndex'=>$xfindex));
 | 
        
           |  |  | 1520 | 					}
 | 
        
           |  |  | 1521 | 					break;
 | 
        
           |  |  | 1522 | 				case SPREADSHEET_EXCEL_READER_TYPE_LABEL:
 | 
        
           |  |  | 1523 | 					$row	= ord($data[$spos]) | ord($data[$spos+1])<<8;
 | 
        
           |  |  | 1524 | 					$column = ord($data[$spos+2]) | ord($data[$spos+3])<<8;
 | 
        
           |  |  | 1525 | 					$this->addcell($row, $column, substr($data, $spos + 8, ord($data[$spos + 6]) | ord($data[$spos + 7])<<8));
 | 
        
           |  |  | 1526 | 					break;
 | 
        
           |  |  | 1527 | 				case SPREADSHEET_EXCEL_READER_TYPE_EOF:
 | 
        
           |  |  | 1528 | 					$cont = false;
 | 
        
           |  |  | 1529 | 					break;
 | 
        
           |  |  | 1530 | 				case SPREADSHEET_EXCEL_READER_TYPE_HYPER:
 | 
        
           |  |  | 1531 | 					//  Only handle hyperlinks to a URL
 | 
        
           |  |  | 1532 | 					$row	= ord($this->data[$spos]) | ord($this->data[$spos+1])<<8;
 | 
        
           |  |  | 1533 | 					$row2   = ord($this->data[$spos+2]) | ord($this->data[$spos+3])<<8;
 | 
        
           |  |  | 1534 | 					$column = ord($this->data[$spos+4]) | ord($this->data[$spos+5])<<8;
 | 
        
           |  |  | 1535 | 					$column2 = ord($this->data[$spos+6]) | ord($this->data[$spos+7])<<8;
 | 
        
           |  |  | 1536 | 					$linkdata = Array();
 | 
        
           |  |  | 1537 | 					$flags = ord($this->data[$spos + 28]);
 | 
        
           |  |  | 1538 | 					$udesc = "";
 | 
        
           |  |  | 1539 | 					$ulink = "";
 | 
        
           |  |  | 1540 | 					$uloc = 32;
 | 
        
           |  |  | 1541 | 					$linkdata['flags'] = $flags;
 | 
        
           |  |  | 1542 | 					if (($flags & 1) > 0 ) {   // is a type we understand
 | 
        
           |  |  | 1543 | 						//  is there a description ?
 | 
        
           |  |  | 1544 | 						if (($flags & 0x14) == 0x14 ) {   // has a description
 | 
        
           |  |  | 1545 | 							$uloc += 4;
 | 
        
           |  |  | 1546 | 							$descLen = ord($this->data[$spos + 32]) | ord($this->data[$spos + 33]) << 8;
 | 
        
           |  |  | 1547 | 							$udesc = substr($this->data, $spos + $uloc, $descLen * 2);
 | 
        
           |  |  | 1548 | 							$uloc += 2 * $descLen;
 | 
        
           |  |  | 1549 | 						}
 | 
        
           |  |  | 1550 | 						$ulink = $this->read16bitstring($this->data, $spos + $uloc + 20);
 | 
        
           |  |  | 1551 | 						if ($udesc == "") {
 | 
        
           |  |  | 1552 | 							$udesc = $ulink;
 | 
        
           |  |  | 1553 | 						}
 | 
        
           |  |  | 1554 | 					}
 | 
        
           |  |  | 1555 | 					$linkdata['desc'] = $udesc;
 | 
        
           |  |  | 1556 | 					$linkdata['link'] = $this->_encodeUTF16($ulink);
 | 
        
           |  |  | 1557 | 					for ($r=$row; $r<=$row2; $r++) {
 | 
        
           |  |  | 1558 | 						for ($c=$column; $c<=$column2; $c++) {
 | 
        
           |  |  | 1559 | 							$this->sheets[$this->sn]['cellsInfo'][$r+1][$c+1]['hyperlink'] = $linkdata;
 | 
        
           |  |  | 1560 | 						}
 | 
        
           |  |  | 1561 | 					}
 | 
        
           |  |  | 1562 | 					break;
 | 
        
           |  |  | 1563 | 				case SPREADSHEET_EXCEL_READER_TYPE_DEFCOLWIDTH:
 | 
        
           |  |  | 1564 | 					$this->defaultColWidth  = ord($data[$spos+4]) | ord($data[$spos+5]) << 8;
 | 
        
           |  |  | 1565 | 					break;
 | 
        
           |  |  | 1566 | 				case SPREADSHEET_EXCEL_READER_TYPE_STANDARDWIDTH:
 | 
        
           |  |  | 1567 | 					$this->standardColWidth  = ord($data[$spos+4]) | ord($data[$spos+5]) << 8;
 | 
        
           |  |  | 1568 | 					break;
 | 
        
           |  |  | 1569 | 				case SPREADSHEET_EXCEL_READER_TYPE_COLINFO:
 | 
        
           |  |  | 1570 | 					$colfrom = ord($data[$spos+0]) | ord($data[$spos+1]) << 8;
 | 
        
           |  |  | 1571 | 					$colto = ord($data[$spos+2]) | ord($data[$spos+3]) << 8;
 | 
        
           |  |  | 1572 | 					$cw = ord($data[$spos+4]) | ord($data[$spos+5]) << 8;
 | 
        
           |  |  | 1573 | 					$cxf = ord($data[$spos+6]) | ord($data[$spos+7]) << 8;
 | 
        
           |  |  | 1574 | 					$co = ord($data[$spos+8]);
 | 
        
           |  |  | 1575 | 					for ($coli = $colfrom; $coli <= $colto; $coli++) {
 | 
        
           |  |  | 1576 | 						$this->colInfo[$this->sn][$coli+1] = Array('width' => $cw, 'xf' => $cxf, 'hidden' => ($co & 0x01), 'collapsed' => ($co & 0x1000) >> 12);
 | 
        
           |  |  | 1577 | 					}
 | 
        
           |  |  | 1578 | 					break;
 | 
        
           |  |  | 1579 |   | 
        
           |  |  | 1580 | 				default:
 | 
        
           |  |  | 1581 | 					break;
 | 
        
           |  |  | 1582 | 			}
 | 
        
           |  |  | 1583 | 			$spos += $length;
 | 
        
           |  |  | 1584 | 		}
 | 
        
           |  |  | 1585 |   | 
        
           |  |  | 1586 | 		if (!isset($this->sheets[$this->sn]['numRows']))
 | 
        
           |  |  | 1587 | 			 $this->sheets[$this->sn]['numRows'] = $this->sheets[$this->sn]['maxrow'];
 | 
        
           |  |  | 1588 | 		if (!isset($this->sheets[$this->sn]['numCols']))
 | 
        
           |  |  | 1589 | 			 $this->sheets[$this->sn]['numCols'] = $this->sheets[$this->sn]['maxcol'];
 | 
        
           |  |  | 1590 | 		}
 | 
        
           |  |  | 1591 |   | 
        
           |  |  | 1592 | 		function isDate($spos) {
 | 
        
           |  |  | 1593 | 			$xfindex = ord($this->data[$spos+4]) | ord($this->data[$spos+5]) << 8;
 | 
        
           |  |  | 1594 | 			return ($this->xfRecords[$xfindex]['type'] == 'date');
 | 
        
           |  |  | 1595 | 		}
 | 
        
           |  |  | 1596 |   | 
        
           |  |  | 1597 | 		// Get the details for a particular cell
 | 
        
           |  |  | 1598 | 		function _getCellDetails($spos,$numValue,$column) {
 | 
        
           |  |  | 1599 | 			$xfindex = ord($this->data[$spos+4]) | ord($this->data[$spos+5]) << 8;
 | 
        
           |  |  | 1600 | 			$xfrecord = $this->xfRecords[$xfindex];
 | 
        
           |  |  | 1601 | 			$type = $xfrecord['type'];
 | 
        
           |  |  | 1602 |   | 
        
           |  |  | 1603 | 			$format = $xfrecord['format'];
 | 
        
           |  |  | 1604 | 			$formatIndex = $xfrecord['formatIndex'];
 | 
        
           |  |  | 1605 | 			$fontIndex = $xfrecord['fontIndex'];
 | 
        
           |  |  | 1606 | 			$formatColor = "";
 | 
        
           |  |  | 1607 | 			$rectype = '';
 | 
        
           |  |  | 1608 | 			$string = '';
 | 
        
           |  |  | 1609 | 			$raw = '';
 | 
        
           |  |  | 1610 |   | 
        
           |  |  | 1611 | 			if (isset($this->_columnsFormat[$column + 1])){
 | 
        
           |  |  | 1612 | 				$format = $this->_columnsFormat[$column + 1];
 | 
        
           |  |  | 1613 | 			}
 | 
        
           |  |  | 1614 |   | 
        
           |  |  | 1615 | 			if ($type == 'date') {
 | 
        
           |  |  | 1616 | 				// See http://groups.google.com/group/php-excel-reader-discuss/browse_frm/thread/9c3f9790d12d8e10/f2045c2369ac79de
 | 
        
           |  |  | 1617 | 				$rectype = 'date';
 | 
        
           |  |  | 1618 | 				// Convert numeric value into a date
 | 
        
           |  |  | 1619 | 				$utcDays = floor($numValue - ($this->nineteenFour ? SPREADSHEET_EXCEL_READER_UTCOFFSETDAYS1904 : SPREADSHEET_EXCEL_READER_UTCOFFSETDAYS));
 | 
        
           |  |  | 1620 | 				$utcValue = ($utcDays) * SPREADSHEET_EXCEL_READER_MSINADAY;
 | 
        
           |  |  | 1621 | 				$dateinfo = gmgetdate($utcValue);
 | 
        
           |  |  | 1622 |   | 
        
           |  |  | 1623 | 				$raw = $numValue;
 | 
        
           |  |  | 1624 | 				$fractionalDay = $numValue - floor($numValue) + .0000001; // The .0000001 is to fix for php/excel fractional diffs
 | 
        
           |  |  | 1625 |   | 
        
           |  |  | 1626 | 				$totalseconds = floor(SPREADSHEET_EXCEL_READER_MSINADAY * $fractionalDay);
 | 
        
           |  |  | 1627 | 				$secs = $totalseconds % 60;
 | 
        
           |  |  | 1628 | 				$totalseconds -= $secs;
 | 
        
           |  |  | 1629 | 				$hours = floor($totalseconds / (60 * 60));
 | 
        
           |  |  | 1630 | 				$mins = floor($totalseconds / 60) % 60;
 | 
        
           | 634 | david | 1631 |                 // David Delon : on force du JJ/MM/AAAA
 | 
        
           |  |  | 1632 |                 $format= "d/m/Y";
 | 
        
           | 452 | david | 1633 | 				$string = date ($format, mktime($hours, $mins, $secs, $dateinfo["mon"], $dateinfo["mday"], $dateinfo["year"]));
 | 
        
           |  |  | 1634 | 			} else if ($type == 'number') {
 | 
        
           |  |  | 1635 | 				$rectype = 'number';
 | 
        
           |  |  | 1636 | 				$formatted = $this->_format_value($format, $numValue, $formatIndex);
 | 
        
           |  |  | 1637 | 				$string = $formatted['string'];
 | 
        
           |  |  | 1638 | 				$formatColor = $formatted['formatColor'];
 | 
        
           |  |  | 1639 | 				$raw = $numValue;
 | 
        
           |  |  | 1640 | 			} else{
 | 
        
           |  |  | 1641 | 				if ($format=="") {
 | 
        
           |  |  | 1642 | 					$format = $this->_defaultFormat;
 | 
        
           |  |  | 1643 | 				}
 | 
        
           |  |  | 1644 | 				$rectype = 'unknown';
 | 
        
           |  |  | 1645 | 				$formatted = $this->_format_value($format, $numValue, $formatIndex);
 | 
        
           |  |  | 1646 | 				$string = $formatted['string'];
 | 
        
           |  |  | 1647 | 				$formatColor = $formatted['formatColor'];
 | 
        
           |  |  | 1648 | 				$raw = $numValue;
 | 
        
           |  |  | 1649 | 			}
 | 
        
           |  |  | 1650 |   | 
        
           |  |  | 1651 | 			return array(
 | 
        
           |  |  | 1652 | 				'string'=>$string,
 | 
        
           |  |  | 1653 | 				'raw'=>$raw,
 | 
        
           |  |  | 1654 | 				'rectype'=>$rectype,
 | 
        
           |  |  | 1655 | 				'format'=>$format,
 | 
        
           |  |  | 1656 | 				'formatIndex'=>$formatIndex,
 | 
        
           |  |  | 1657 | 				'fontIndex'=>$fontIndex,
 | 
        
           |  |  | 1658 | 				'formatColor'=>$formatColor,
 | 
        
           |  |  | 1659 | 				'xfIndex'=>$xfindex
 | 
        
           |  |  | 1660 | 			);
 | 
        
           |  |  | 1661 |   | 
        
           |  |  | 1662 | 		}
 | 
        
           |  |  | 1663 |   | 
        
           |  |  | 1664 |   | 
        
           |  |  | 1665 | 	function createNumber($spos) {
 | 
        
           |  |  | 1666 | 		$rknumhigh = $this->_GetInt4d($this->data, $spos + 10);
 | 
        
           |  |  | 1667 | 		$rknumlow = $this->_GetInt4d($this->data, $spos + 6);
 | 
        
           |  |  | 1668 | 		$sign = ($rknumhigh & 0x80000000) >> 31;
 | 
        
           |  |  | 1669 | 		$exp =  ($rknumhigh & 0x7ff00000) >> 20;
 | 
        
           |  |  | 1670 | 		$mantissa = (0x100000 | ($rknumhigh & 0x000fffff));
 | 
        
           |  |  | 1671 | 		$mantissalow1 = ($rknumlow & 0x80000000) >> 31;
 | 
        
           |  |  | 1672 | 		$mantissalow2 = ($rknumlow & 0x7fffffff);
 | 
        
           |  |  | 1673 | 		$value = $mantissa / pow( 2 , (20- ($exp - 1023)));
 | 
        
           |  |  | 1674 | 		if ($mantissalow1 != 0) $value += 1 / pow (2 , (21 - ($exp - 1023)));
 | 
        
           |  |  | 1675 | 		$value += $mantissalow2 / pow (2 , (52 - ($exp - 1023)));
 | 
        
           |  |  | 1676 | 		if ($sign) {$value = -1 * $value;}
 | 
        
           |  |  | 1677 | 		return  $value;
 | 
        
           |  |  | 1678 | 	}
 | 
        
           |  |  | 1679 |   | 
        
           |  |  | 1680 | 	function addcell($row, $col, $string, $info=null) {
 | 
        
           |  |  | 1681 | 		$this->sheets[$this->sn]['maxrow'] = max($this->sheets[$this->sn]['maxrow'], $row + $this->_rowoffset);
 | 
        
           |  |  | 1682 | 		$this->sheets[$this->sn]['maxcol'] = max($this->sheets[$this->sn]['maxcol'], $col + $this->_coloffset);
 | 
        
           |  |  | 1683 | 		$this->sheets[$this->sn]['cells'][$row + $this->_rowoffset][$col + $this->_coloffset] = $string;
 | 
        
           |  |  | 1684 | 		if ($this->store_extended_info && $info) {
 | 
        
           |  |  | 1685 | 			foreach ($info as $key=>$val) {
 | 
        
           |  |  | 1686 | 				$this->sheets[$this->sn]['cellsInfo'][$row + $this->_rowoffset][$col + $this->_coloffset][$key] = $val;
 | 
        
           |  |  | 1687 | 			}
 | 
        
           |  |  | 1688 | 		}
 | 
        
           |  |  | 1689 | 	}
 | 
        
           |  |  | 1690 |   | 
        
           |  |  | 1691 |   | 
        
           |  |  | 1692 | 	function _GetIEEE754($rknum) {
 | 
        
           |  |  | 1693 | 		if (($rknum & 0x02) != 0) {
 | 
        
           |  |  | 1694 | 				$value = $rknum >> 2;
 | 
        
           |  |  | 1695 | 		} else {
 | 
        
           |  |  | 1696 | 			//mmp
 | 
        
           |  |  | 1697 | 			// I got my info on IEEE754 encoding from
 | 
        
           |  |  | 1698 | 			// http://research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html
 | 
        
           |  |  | 1699 | 			// The RK format calls for using only the most significant 30 bits of the
 | 
        
           |  |  | 1700 | 			// 64 bit floating point value. The other 34 bits are assumed to be 0
 | 
        
           |  |  | 1701 | 			// So, we use the upper 30 bits of $rknum as follows...
 | 
        
           |  |  | 1702 | 			$sign = ($rknum & 0x80000000) >> 31;
 | 
        
           |  |  | 1703 | 			$exp = ($rknum & 0x7ff00000) >> 20;
 | 
        
           |  |  | 1704 | 			$mantissa = (0x100000 | ($rknum & 0x000ffffc));
 | 
        
           |  |  | 1705 | 			$value = $mantissa / pow( 2 , (20- ($exp - 1023)));
 | 
        
           |  |  | 1706 | 			if ($sign) {
 | 
        
           |  |  | 1707 | 				$value = -1 * $value;
 | 
        
           |  |  | 1708 | 			}
 | 
        
           |  |  | 1709 | 			//end of changes by mmp
 | 
        
           |  |  | 1710 | 		}
 | 
        
           |  |  | 1711 | 		if (($rknum & 0x01) != 0) {
 | 
        
           |  |  | 1712 | 			$value /= 100;
 | 
        
           |  |  | 1713 | 		}
 | 
        
           |  |  | 1714 | 		return $value;
 | 
        
           |  |  | 1715 | 	}
 | 
        
           |  |  | 1716 |   | 
        
           |  |  | 1717 | 	function _encodeUTF16($string) {
 | 
        
           |  |  | 1718 | 		$result = $string;
 | 
        
           |  |  | 1719 | 		if ($this->_defaultEncoding){
 | 
        
           |  |  | 1720 | 			switch ($this->_encoderFunction){
 | 
        
           |  |  | 1721 | 				case 'iconv' :	 $result = iconv('UTF-16LE', $this->_defaultEncoding, $string);
 | 
        
           |  |  | 1722 | 								break;
 | 
        
           |  |  | 1723 | 				case 'mb_convert_encoding' :	 $result = mb_convert_encoding($string, $this->_defaultEncoding, 'UTF-16LE' );
 | 
        
           |  |  | 1724 | 								break;
 | 
        
           |  |  | 1725 | 			}
 | 
        
           |  |  | 1726 | 		}
 | 
        
           |  |  | 1727 | 		return $result;
 | 
        
           |  |  | 1728 | 	}
 | 
        
           |  |  | 1729 |   | 
        
           |  |  | 1730 | 	function _GetInt4d($data, $pos) {
 | 
        
           |  |  | 1731 | 		$value = ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16) | (ord($data[$pos+3]) << 24);
 | 
        
           |  |  | 1732 | 		if ($value>=4294967294) {
 | 
        
           |  |  | 1733 | 			$value=-2;
 | 
        
           |  |  | 1734 | 		}
 | 
        
           |  |  | 1735 | 		return $value;
 | 
        
           |  |  | 1736 | 	}
 | 
        
           |  |  | 1737 |   | 
        
           |  |  | 1738 | }
 | 
        
           |  |  | 1739 |   | 
        
           |  |  | 1740 | ?>
 |