ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
OLERead.php
Go to the documentation of this file.
1 <?php
28 defined('IDENTIFIER_OLE') ||
29  define('IDENTIFIER_OLE', pack('CCCCCCCC', 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1));
30 
32  private $data = '';
33 
34  // OLE identifier
36 
37  // Size of a sector = 512 bytes
38  const BIG_BLOCK_SIZE = 0x200;
39 
40  // Size of a short sector = 64 bytes
41  const SMALL_BLOCK_SIZE = 0x40;
42 
43  // Size of a directory entry always = 128 bytes
45 
46  // Minimum size of a standard stream = 4096 bytes, streams smaller than this are stored as short streams
47  const SMALL_BLOCK_THRESHOLD = 0x1000;
48 
49  // header offsets
51  const ROOT_START_BLOCK_POS = 0x30;
53  const EXTENSION_BLOCK_POS = 0x44;
56 
57  // property storage offsets (directory offsets)
58  const SIZE_OF_NAME_POS = 0x40;
59  const TYPE_POS = 0x42;
60  const START_BLOCK_POS = 0x74;
61  const SIZE_POS = 0x78;
62 
63 
64 
65  public $wrkbook = null;
66  public $summaryInformation = null;
68 
69 
76  public function read($sFileName)
77  {
78  // Check if file exists and is readable
79  if(!is_readable($sFileName)) {
80  throw new PHPExcel_Reader_Exception("Could not open " . $sFileName . " for reading! File does not exist, or it is not readable.");
81  }
82 
83  // Get the file identifier
84  // Don't bother reading the whole file until we know it's a valid OLE file
85  $this->data = file_get_contents($sFileName, FALSE, NULL, 0, 8);
86 
87  // Check OLE identifier
88  if ($this->data != self::IDENTIFIER_OLE) {
89  throw new PHPExcel_Reader_Exception('The filename ' . $sFileName . ' is not recognised as an OLE file');
90  }
91 
92  // Get the file data
93  $this->data = file_get_contents($sFileName);
94 
95  // Total number of sectors used for the SAT
96  $this->numBigBlockDepotBlocks = self::_GetInt4d($this->data, self::NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);
97 
98  // SecID of the first sector of the directory stream
99  $this->rootStartBlock = self::_GetInt4d($this->data, self::ROOT_START_BLOCK_POS);
100 
101  // SecID of the first sector of the SSAT (or -2 if not extant)
102  $this->sbdStartBlock = self::_GetInt4d($this->data, self::SMALL_BLOCK_DEPOT_BLOCK_POS);
103 
104  // SecID of the first sector of the MSAT (or -2 if no additional sectors are used)
105  $this->extensionBlock = self::_GetInt4d($this->data, self::EXTENSION_BLOCK_POS);
106 
107  // Total number of sectors used by MSAT
108  $this->numExtensionBlocks = self::_GetInt4d($this->data, self::NUM_EXTENSION_BLOCK_POS);
109 
110  $bigBlockDepotBlocks = array();
111  $pos = self::BIG_BLOCK_DEPOT_BLOCKS_POS;
112 
113  $bbdBlocks = $this->numBigBlockDepotBlocks;
114 
115  if ($this->numExtensionBlocks != 0) {
116  $bbdBlocks = (self::BIG_BLOCK_SIZE - self::BIG_BLOCK_DEPOT_BLOCKS_POS)/4;
117  }
118 
119  for ($i = 0; $i < $bbdBlocks; ++$i) {
120  $bigBlockDepotBlocks[$i] = self::_GetInt4d($this->data, $pos);
121  $pos += 4;
122  }
123 
124  for ($j = 0; $j < $this->numExtensionBlocks; ++$j) {
125  $pos = ($this->extensionBlock + 1) * self::BIG_BLOCK_SIZE;
126  $blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, self::BIG_BLOCK_SIZE / 4 - 1);
127 
128  for ($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; ++$i) {
129  $bigBlockDepotBlocks[$i] = self::_GetInt4d($this->data, $pos);
130  $pos += 4;
131  }
132 
133  $bbdBlocks += $blocksToRead;
134  if ($bbdBlocks < $this->numBigBlockDepotBlocks) {
135  $this->extensionBlock = self::_GetInt4d($this->data, $pos);
136  }
137  }
138 
139  $pos = 0;
140  $this->bigBlockChain = '';
141  $bbs = self::BIG_BLOCK_SIZE / 4;
142  for ($i = 0; $i < $this->numBigBlockDepotBlocks; ++$i) {
143  $pos = ($bigBlockDepotBlocks[$i] + 1) * self::BIG_BLOCK_SIZE;
144 
145  $this->bigBlockChain .= substr($this->data, $pos, 4*$bbs);
146  $pos += 4*$bbs;
147  }
148 
149  $pos = 0;
150  $sbdBlock = $this->sbdStartBlock;
151  $this->smallBlockChain = '';
152  while ($sbdBlock != -2) {
153  $pos = ($sbdBlock + 1) * self::BIG_BLOCK_SIZE;
154 
155  $this->smallBlockChain .= substr($this->data, $pos, 4*$bbs);
156  $pos += 4*$bbs;
157 
158  $sbdBlock = self::_GetInt4d($this->bigBlockChain, $sbdBlock*4);
159  }
160 
161  // read the directory stream
162  $block = $this->rootStartBlock;
163  $this->entry = $this->_readData($block);
164 
165  $this->_readPropertySets();
166  }
167 
173  public function getStream($stream)
174  {
175  if ($stream === NULL) {
176  return null;
177  }
178 
179  $streamData = '';
180 
181  if ($this->props[$stream]['size'] < self::SMALL_BLOCK_THRESHOLD) {
182  $rootdata = $this->_readData($this->props[$this->rootentry]['startBlock']);
183 
184  $block = $this->props[$stream]['startBlock'];
185 
186  while ($block != -2) {
187  $pos = $block * self::SMALL_BLOCK_SIZE;
188  $streamData .= substr($rootdata, $pos, self::SMALL_BLOCK_SIZE);
189 
190  $block = self::_GetInt4d($this->smallBlockChain, $block*4);
191  }
192 
193  return $streamData;
194  } else {
195  $numBlocks = $this->props[$stream]['size'] / self::BIG_BLOCK_SIZE;
196  if ($this->props[$stream]['size'] % self::BIG_BLOCK_SIZE != 0) {
197  ++$numBlocks;
198  }
199 
200  if ($numBlocks == 0) return '';
201 
202  $block = $this->props[$stream]['startBlock'];
203 
204  while ($block != -2) {
205  $pos = ($block + 1) * self::BIG_BLOCK_SIZE;
206  $streamData .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
207  $block = self::_GetInt4d($this->bigBlockChain, $block*4);
208  }
209 
210  return $streamData;
211  }
212  }
213 
220  private function _readData($bl)
221  {
222  $block = $bl;
223  $data = '';
224 
225  while ($block != -2) {
226  $pos = ($block + 1) * self::BIG_BLOCK_SIZE;
227  $data .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
228  $block = self::_GetInt4d($this->bigBlockChain, $block*4);
229  }
230  return $data;
231  }
232 
236  private function _readPropertySets() {
237  $offset = 0;
238 
239  // loop through entires, each entry is 128 bytes
240  $entryLen = strlen($this->entry);
241  while ($offset < $entryLen) {
242  // entry data (128 bytes)
243  $d = substr($this->entry, $offset, self::PROPERTY_STORAGE_BLOCK_SIZE);
244 
245  // size in bytes of name
246  $nameSize = ord($d[self::SIZE_OF_NAME_POS]) | (ord($d[self::SIZE_OF_NAME_POS+1]) << 8);
247 
248  // type of entry
249  $type = ord($d[self::TYPE_POS]);
250 
251  // sectorID of first sector or short sector, if this entry refers to a stream (the case with workbook)
252  // sectorID of first sector of the short-stream container stream, if this entry is root entry
253  $startBlock = self::_GetInt4d($d, self::START_BLOCK_POS);
254 
255  $size = self::_GetInt4d($d, self::SIZE_POS);
256 
257  $name = str_replace("\x00", "", substr($d,0,$nameSize));
258 
259 
260  $this->props[] = array (
261  'name' => $name,
262  'type' => $type,
263  'startBlock' => $startBlock,
264  'size' => $size);
265 
266  // tmp helper to simplify checks
267  $upName = strtoupper($name);
268 
269  // Workbook directory entry (BIFF5 uses Book, BIFF8 uses Workbook)
270  if (($upName === 'WORKBOOK') || ($upName === 'BOOK')) {
271  $this->wrkbook = count($this->props) - 1;
272  }
273  else if ( $upName === 'ROOT ENTRY' || $upName === 'R') {
274  // Root entry
275  $this->rootentry = count($this->props) - 1;
276  }
277 
278  // Summary information
279  if ($name == chr(5) . 'SummaryInformation') {
280 // echo 'Summary Information<br />';
281  $this->summaryInformation = count($this->props) - 1;
282  }
283 
284  // Additional Document Summary information
285  if ($name == chr(5) . 'DocumentSummaryInformation') {
286 // echo 'Document Summary Information<br />';
287  $this->documentSummaryInformation = count($this->props) - 1;
288  }
289 
290  $offset += self::PROPERTY_STORAGE_BLOCK_SIZE;
291  }
292 
293  }
294 
302  private static function _GetInt4d($data, $pos)
303  {
304  // FIX: represent numbers correctly on 64-bit system
305  // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
306  // Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
307  $_or_24 = ord($data[$pos + 3]);
308  if ($_or_24 >= 128) {
309  // negative number
310  $_ord_24 = -abs((256 - $_or_24) << 24);
311  } else {
312  $_ord_24 = ($_or_24 & 127) << 24;
313  }
314  return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16) | $_ord_24;
315  }
316 
317 }
Add some data
const NUM_EXTENSION_BLOCK_POS
Definition: OLERead.php:54
static _GetInt4d($data, $pos)
Read 4 bytes of data at specified position.
Definition: OLERead.php:302
$size
Definition: RandomTest.php:84
getStream($stream)
Extract binary stream data.
Definition: OLERead.php:173
const SMALL_BLOCK_DEPOT_BLOCK_POS
Definition: OLERead.php:52
$type
_readData($bl)
Read a standard stream (by joining sectors using information from SAT)
Definition: OLERead.php:220
$stream
PHP stream implementation.
if($format !==null) $name
Definition: metadata.php:146
const BIG_BLOCK_DEPOT_BLOCKS_POS
Definition: OLERead.php:55
read($sFileName)
Read the file.
Definition: OLERead.php:76
Create styles array
The data for the language used.
_readPropertySets()
Read entries in the directory stream.
Definition: OLERead.php:236
$i
Definition: disco.tpl.php:19
defined( 'APPLICATION_ENV')||define( 'APPLICATION_ENV'
Definition: bootstrap.php:27
const NUM_BIG_BLOCK_DEPOT_BLOCKS_POS
Definition: OLERead.php:50
const PROPERTY_STORAGE_BLOCK_SIZE
Definition: OLERead.php:44
for($i=6; $i< 13; $i++) for($i=1; $i< 13; $i++) $d
Definition: date.php:296