心理咨询网
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

oleread.php 8.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. <?php
  2. namespace core\extend\excel;
  3. define('NUM_BIG_BLOCK_DEPOT_BLOCKS_POS', 0x2c);
  4. define('SMALL_BLOCK_DEPOT_BLOCK_POS', 0x3c);
  5. define('ROOT_START_BLOCK_POS', 0x30);
  6. define('BIG_BLOCK_SIZE', 0x200);
  7. define('SMALL_BLOCK_SIZE', 0x40);
  8. define('EXTENSION_BLOCK_POS', 0x44);
  9. define('NUM_EXTENSION_BLOCK_POS', 0x48);
  10. define('PROPERTY_STORAGE_BLOCK_SIZE', 0x80);
  11. define('BIG_BLOCK_DEPOT_BLOCKS_POS', 0x4c);
  12. define('SMALL_BLOCK_THRESHOLD', 0x1000);
  13. // property storage offsets
  14. define('SIZE_OF_NAME_POS', 0x40);
  15. define('TYPE_POS', 0x42);
  16. define('START_BLOCK_POS', 0x74);
  17. define('SIZE_POS', 0x78);
  18. define('IDENTIFIER_OLE', pack("CCCCCCCC", 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1));
  19. // echo 'ROOT_START_BLOCK_POS = '.ROOT_START_BLOCK_POS."\n";
  20. // echo bin2hex($data[ROOT_START_BLOCK_POS])."\n";
  21. // echo "a=";
  22. // echo $data[ROOT_START_BLOCK_POS];
  23. // function log
  24. function GetInt4d($data, $pos)
  25. {
  26. $value = ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16) | (ord($data[$pos + 3]) << 24);
  27. if ($value >= 4294967294) {
  28. $value = - 2;
  29. }
  30. return $value;
  31. }
  32. class OLERead
  33. {
  34. var $data = '';
  35. function OLERead()
  36. {}
  37. function read($sFileName)
  38. {
  39. // check if file exist and is readable (Darko Miljanovic)
  40. if (! is_readable($sFileName)) {
  41. $this->error = 1;
  42. return false;
  43. }
  44. $this->data = @file_get_contents($sFileName);
  45. if (! $this->data) {
  46. $this->error = 1;
  47. return false;
  48. }
  49. // echo IDENTIFIER_OLE;
  50. // echo 'start';
  51. if (substr($this->data, 0, 8) != IDENTIFIER_OLE) {
  52. $this->error = 1;
  53. return false;
  54. }
  55. $this->numBigBlockDepotBlocks = GetInt4d($this->data, NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);
  56. $this->sbdStartBlock = GetInt4d($this->data, SMALL_BLOCK_DEPOT_BLOCK_POS);
  57. $this->rootStartBlock = GetInt4d($this->data, ROOT_START_BLOCK_POS);
  58. $this->extensionBlock = GetInt4d($this->data, EXTENSION_BLOCK_POS);
  59. $this->numExtensionBlocks = GetInt4d($this->data, NUM_EXTENSION_BLOCK_POS);
  60. /*
  61. * echo $this->numBigBlockDepotBlocks." ";
  62. * echo $this->sbdStartBlock." ";
  63. * echo $this->rootStartBlock." ";
  64. * echo $this->extensionBlock." ";
  65. * echo $this->numExtensionBlocks." ";
  66. */
  67. // echo "sbdStartBlock = $this->sbdStartBlock\n";
  68. $bigBlockDepotBlocks = array();
  69. $pos = BIG_BLOCK_DEPOT_BLOCKS_POS;
  70. // echo "pos = $pos";
  71. $bbdBlocks = $this->numBigBlockDepotBlocks;
  72. if ($this->numExtensionBlocks != 0) {
  73. $bbdBlocks = (BIG_BLOCK_SIZE - BIG_BLOCK_DEPOT_BLOCKS_POS) / 4;
  74. }
  75. for ($i = 0; $i < $bbdBlocks; $i ++) {
  76. $bigBlockDepotBlocks[$i] = GetInt4d($this->data, $pos);
  77. $pos += 4;
  78. }
  79. for ($j = 0; $j < $this->numExtensionBlocks; $j ++) {
  80. $pos = ($this->extensionBlock + 1) * BIG_BLOCK_SIZE;
  81. $blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, BIG_BLOCK_SIZE / 4 - 1);
  82. for ($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; $i ++) {
  83. $bigBlockDepotBlocks[$i] = GetInt4d($this->data, $pos);
  84. $pos += 4;
  85. }
  86. $bbdBlocks += $blocksToRead;
  87. if ($bbdBlocks < $this->numBigBlockDepotBlocks) {
  88. $this->extensionBlock = GetInt4d($this->data, $pos);
  89. }
  90. }
  91. // var_dump($bigBlockDepotBlocks);
  92. // readBigBlockDepot
  93. $pos = 0;
  94. $index = 0;
  95. $this->bigBlockChain = array();
  96. for ($i = 0; $i < $this->numBigBlockDepotBlocks; $i ++) {
  97. $pos = ($bigBlockDepotBlocks[$i] + 1) * BIG_BLOCK_SIZE;
  98. // echo "pos = $pos";
  99. for ($j = 0; $j < BIG_BLOCK_SIZE / 4; $j ++) {
  100. $this->bigBlockChain[$index] = GetInt4d($this->data, $pos);
  101. $pos += 4;
  102. $index ++;
  103. }
  104. }
  105. // var_dump($this->bigBlockChain);
  106. // echo '=====2';
  107. // readSmallBlockDepot();
  108. $pos = 0;
  109. $index = 0;
  110. $sbdBlock = $this->sbdStartBlock;
  111. $this->smallBlockChain = array();
  112. while ($sbdBlock != - 2) {
  113. $pos = ($sbdBlock + 1) * BIG_BLOCK_SIZE;
  114. for ($j = 0; $j < BIG_BLOCK_SIZE / 4; $j ++) {
  115. $this->smallBlockChain[$index] = GetInt4d($this->data, $pos);
  116. $pos += 4;
  117. $index ++;
  118. }
  119. $sbdBlock = $this->bigBlockChain[$sbdBlock];
  120. }
  121. // readData(rootStartBlock)
  122. $block = $this->rootStartBlock;
  123. $pos = 0;
  124. $this->entry = $this->__readData($block);
  125. /*
  126. * while ($block != -2) {
  127. * $pos = ($block + 1) * BIG_BLOCK_SIZE;
  128. * $this->entry = $this->entry.substr($this->data, $pos, BIG_BLOCK_SIZE);
  129. * $block = $this->bigBlockChain[$block];
  130. * }
  131. */
  132. // echo '==='.$this->entry."===";
  133. $this->__readPropertySets();
  134. }
  135. function __readData($bl)
  136. {
  137. $block = $bl;
  138. $pos = 0;
  139. $data = '';
  140. while ($block != - 2) {
  141. $pos = ($block + 1) * BIG_BLOCK_SIZE;
  142. $data = $data . substr($this->data, $pos, BIG_BLOCK_SIZE);
  143. // echo "pos = $pos data=$data\n";
  144. $block = $this->bigBlockChain[$block];
  145. }
  146. return $data;
  147. }
  148. function __readPropertySets()
  149. {
  150. $offset = 0;
  151. // var_dump($this->entry);
  152. while ($offset < strlen($this->entry)) {
  153. $d = substr($this->entry, $offset, PROPERTY_STORAGE_BLOCK_SIZE);
  154. $nameSize = ord($d[SIZE_OF_NAME_POS]) | (ord($d[SIZE_OF_NAME_POS + 1]) << 8);
  155. $type = ord($d[TYPE_POS]);
  156. // $maxBlock = strlen($d) / BIG_BLOCK_SIZE - 1;
  157. $startBlock = GetInt4d($d, START_BLOCK_POS);
  158. $size = GetInt4d($d, SIZE_POS);
  159. $name = '';
  160. for ($i = 0; $i < $nameSize; $i ++) {
  161. $name .= $d[$i];
  162. }
  163. $name = str_replace("\x00", "", $name);
  164. $this->props[] = array(
  165. 'name' => $name,
  166. 'type' => $type,
  167. 'startBlock' => $startBlock,
  168. 'size' => $size
  169. );
  170. if (($name == "Workbook") || ($name == "Book")) {
  171. $this->wrkbook = count($this->props) - 1;
  172. }
  173. if ($name == "Root Entry") {
  174. $this->rootentry = count($this->props) - 1;
  175. }
  176. // echo "name ==$name=\n";
  177. $offset += PROPERTY_STORAGE_BLOCK_SIZE;
  178. }
  179. }
  180. function getWorkBook()
  181. {
  182. if ($this->props[$this->wrkbook]['size'] < SMALL_BLOCK_THRESHOLD) {
  183. // getSmallBlockStream(PropertyStorage ps)
  184. $rootdata = $this->__readData($this->props[$this->rootentry]['startBlock']);
  185. $streamData = '';
  186. $block = $this->props[$this->wrkbook]['startBlock'];
  187. // $count = 0;
  188. $pos = 0;
  189. while ($block != - 2) {
  190. $pos = $block * SMALL_BLOCK_SIZE;
  191. $streamData .= substr($rootdata, $pos, SMALL_BLOCK_SIZE);
  192. $block = $this->smallBlockChain[$block];
  193. }
  194. return $streamData;
  195. } else {
  196. $numBlocks = $this->props[$this->wrkbook]['size'] / BIG_BLOCK_SIZE;
  197. if ($this->props[$this->wrkbook]['size'] % BIG_BLOCK_SIZE != 0) {
  198. $numBlocks ++;
  199. }
  200. if ($numBlocks == 0)
  201. return '';
  202. // echo "numBlocks = $numBlocks\n";
  203. // byte[] streamData = new byte[numBlocks * BIG_BLOCK_SIZE];
  204. // print_r($this->wrkbook);
  205. $streamData = '';
  206. $block = $this->props[$this->wrkbook]['startBlock'];
  207. // $count = 0;
  208. $pos = 0;
  209. // echo "block = $block";
  210. while ($block != - 2) {
  211. $pos = ($block + 1) * BIG_BLOCK_SIZE;
  212. $streamData .= substr($this->data, $pos, BIG_BLOCK_SIZE);
  213. $block = $this->bigBlockChain[$block];
  214. }
  215. // echo 'stream'.$streamData;
  216. return $streamData;
  217. }
  218. }
  219. }